diff --git a/package-lock.json b/package-lock.json index d0cc76324..574dd331a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,16 +8,17 @@ "name": "code-sandbox", "version": "0.0.0", "dependencies": { - "@abgov/react-components": "6.5.0", - "@abgov/ui-components-common": "1.5.0", - "@abgov/web-components": "1.35.1", + "@abgov/react-components": "6.6.0-alpha.4", + "@abgov/ui-components-common": "1.6.0-alpha.4", + "@abgov/web-components": "1.36.0-alpha.6", "@faker-js/faker": "^8.3.1", "highlight.js": "^11.8.0", "js-cookie": "^3.0.5", "octokit": "^4.0.2", "react": "^18.2.0", "react-dom": "^18.2.0", - "react-router-dom": "^6.13.0" + "react-router-dom": "^6.13.0", + "use-debounce": "^10.0.4" }, "devDependencies": { "@types/js-cookie": "^3.0.6", @@ -67,9 +68,9 @@ } }, "node_modules/@abgov/react-components": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/@abgov/react-components/-/react-components-6.5.0.tgz", - "integrity": "sha512-Bnhz35v/kDrT1sAhM0/+3kfbk3za4OR9QWAxNV88nkx/Lj3th22T9D+IZc0ACLLIwRZJdvb5umTTZZn+Tl5Wew==", + "version": "6.6.0-alpha.4", + "resolved": "https://registry.npmjs.org/@abgov/react-components/-/react-components-6.6.0-alpha.4.tgz", + "integrity": "sha512-fKCLEiA492r3Qw94yARh4xhYEds/ze8h/PvoxUJ+wcHD3f5Ud8qyb4/yfmt5odO8E2dZnaAm1MzwNCYtja0MCA==", "peerDependencies": { "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", "react": "^17.0.0 || ^18.0.0 || ^19.0.0", @@ -77,14 +78,14 @@ } }, "node_modules/@abgov/ui-components-common": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@abgov/ui-components-common/-/ui-components-common-1.5.0.tgz", - "integrity": "sha512-QhJX1IIAlR1x5bBj3mmM6MJAcq8TYTSK53vOG5MeNKTu3U0ifgGJHNf8ftA7mL70eGLcCVlYsNpA9l+krEfaTg==" + "version": "1.6.0-alpha.4", + "resolved": "https://registry.npmjs.org/@abgov/ui-components-common/-/ui-components-common-1.6.0-alpha.4.tgz", + "integrity": "sha512-mJanU5U8oy2+o6oVP/bHSg9gMbuv33Ak3EPJpEmC4gvqTWjvoZUsRaxBYGDx8SGr+Bt3paQhcV593uctg5EeWQ==" }, "node_modules/@abgov/web-components": { - "version": "1.35.1", - "resolved": "https://registry.npmjs.org/@abgov/web-components/-/web-components-1.35.1.tgz", - "integrity": "sha512-A8ee+QjiyUJ1UC9USFH8qI0Dnx0LP8guiKpu/mWYtkmM76cu4iwpEQieD9pbGVcM/0xPjqbs59JEih+AEwMt2w==", + "version": "1.36.0-alpha.6", + "resolved": "https://registry.npmjs.org/@abgov/web-components/-/web-components-1.36.0-alpha.6.tgz", + "integrity": "sha512-c7BaBMHkSlcEBOo2yqEK3ipBea9ERQ9qgdPmOKCoOybQjbc2YZAOZHogxqODFg1IikyaOMzfsWRrTTL/Sr3pPA==", "peerDependencies": { "@sveltejs/vite-plugin-svelte": "3.x", "glob": "10.x", @@ -598,17 +599,13 @@ } }, "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.8", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz", - "integrity": "sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==", + "version": "0.3.12", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.12.tgz", + "integrity": "sha512-OuLGC46TjB5BbN1dH8JULVVZY4WTdkF7tV9Ys6wLL1rubZnCMstOhNHueU5bLCrnRuDhKPDM4g6sw4Bel5Gzqg==", "peer": true, "dependencies": { - "@jridgewell/set-array": "^1.2.1", - "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/sourcemap-codec": "^1.5.0", "@jridgewell/trace-mapping": "^0.3.24" - }, - "engines": { - "node": ">=6.0.0" } }, "node_modules/@jridgewell/resolve-uri": { @@ -620,25 +617,16 @@ "node": ">=6.0.0" } }, - "node_modules/@jridgewell/set-array": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", - "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", - "peer": true, - "engines": { - "node": ">=6.0.0" - } - }, "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", - "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.4.tgz", + "integrity": "sha512-VT2+G1VQs/9oz078bLrYbecdZKs912zQlkelYpuf+SXF+QvZDYJlbx/LSx+meSAwdDFnF8FVXW92AVjjkVmgFw==", "peer": true }, "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.25", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", - "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "version": "0.3.29", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.29.tgz", + "integrity": "sha512-uw6guiW/gcAGPDhLmd77/6lW8QLeiV5RUTsAX46Db6oLhGaVj4lhnPwb184s1bkc8kdVg/+h988dro8GRDpmYQ==", "peer": true, "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", @@ -2530,9 +2518,9 @@ } }, "node_modules/glob/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", "peer": true, "dependencies": { "balanced-match": "^1.0.0" @@ -3698,6 +3686,17 @@ "punycode": "^2.1.0" } }, + "node_modules/use-debounce": { + "version": "10.0.5", + "resolved": "https://registry.npmjs.org/use-debounce/-/use-debounce-10.0.5.tgz", + "integrity": "sha512-Q76E3lnIV+4YT9AHcrHEHYmAd9LKwUAbPXDm7FlqVGDHiSOhX3RDjT8dm0AxbJup6WgOb1YEcKyCr11kBJR5KQ==", + "engines": { + "node": ">= 16.0.0" + }, + "peerDependencies": { + "react": "*" + } + }, "node_modules/vite": { "version": "5.4.19", "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.19.tgz", diff --git a/package.json b/package.json index b196eccc7..9622fe12e 100644 --- a/package.json +++ b/package.json @@ -12,16 +12,17 @@ "prettier": "npx prettier . --write" }, "dependencies": { - "@abgov/react-components": "6.5.0", - "@abgov/ui-components-common": "1.5.0", - "@abgov/web-components": "1.35.1", + "@abgov/react-components": "6.6.0-alpha.4", + "@abgov/ui-components-common": "1.6.0-alpha.4", + "@abgov/web-components": "1.36.0-alpha.6", "@faker-js/faker": "^8.3.1", "highlight.js": "^11.8.0", "js-cookie": "^3.0.5", "octokit": "^4.0.2", "react": "^18.2.0", "react-dom": "^18.2.0", - "react-router-dom": "^6.13.0" + "react-router-dom": "^6.13.0", + "use-debounce": "^10.0.4" }, "devDependencies": { "@types/js-cookie": "^3.0.6", diff --git a/public/images/accordion.png b/public/images/component-thumbnails/accordion.png similarity index 100% rename from public/images/accordion.png rename to public/images/component-thumbnails/accordion.png diff --git a/public/images/badge.png b/public/images/component-thumbnails/badge.png similarity index 100% rename from public/images/badge.png rename to public/images/component-thumbnails/badge.png diff --git a/public/images/block.png b/public/images/component-thumbnails/block.png similarity index 100% rename from public/images/block.png rename to public/images/component-thumbnails/block.png diff --git a/public/images/button-group.png b/public/images/component-thumbnails/button-group.png similarity index 100% rename from public/images/button-group.png rename to public/images/component-thumbnails/button-group.png diff --git a/public/images/button.png b/public/images/component-thumbnails/button.png similarity index 100% rename from public/images/button.png rename to public/images/component-thumbnails/button.png diff --git a/public/images/callout.png b/public/images/component-thumbnails/callout.png similarity index 100% rename from public/images/callout.png rename to public/images/component-thumbnails/callout.png diff --git a/public/images/card.png b/public/images/component-thumbnails/card.png similarity index 100% rename from public/images/card.png rename to public/images/component-thumbnails/card.png diff --git a/public/images/checkbox.png b/public/images/component-thumbnails/checkbox.png similarity index 100% rename from public/images/checkbox.png rename to public/images/component-thumbnails/checkbox.png diff --git a/public/images/combobox.png b/public/images/component-thumbnails/combobox.png similarity index 100% rename from public/images/combobox.png rename to public/images/component-thumbnails/combobox.png diff --git a/public/images/container.png b/public/images/component-thumbnails/container.png similarity index 100% rename from public/images/container.png rename to public/images/component-thumbnails/container.png diff --git a/public/images/date-dst.png b/public/images/component-thumbnails/date-dst.png similarity index 100% rename from public/images/date-dst.png rename to public/images/component-thumbnails/date-dst.png diff --git a/public/images/date-picker.png b/public/images/component-thumbnails/date-picker.png similarity index 100% rename from public/images/date-picker.png rename to public/images/component-thumbnails/date-picker.png diff --git a/public/images/date-st.png b/public/images/component-thumbnails/date-st.png similarity index 100% rename from public/images/date-st.png rename to public/images/component-thumbnails/date-st.png diff --git a/public/images/design-system-technologies.png b/public/images/component-thumbnails/design-system-technologies.png similarity index 100% rename from public/images/design-system-technologies.png rename to public/images/component-thumbnails/design-system-technologies.png diff --git a/public/images/details-demo.jpg b/public/images/component-thumbnails/details-demo.jpg similarity index 100% rename from public/images/details-demo.jpg rename to public/images/component-thumbnails/details-demo.jpg diff --git a/public/images/details.png b/public/images/component-thumbnails/details.png similarity index 100% rename from public/images/details.png rename to public/images/component-thumbnails/details.png diff --git a/public/images/disclaimer.png b/public/images/component-thumbnails/disclaimer.png similarity index 100% rename from public/images/disclaimer.png rename to public/images/component-thumbnails/disclaimer.png diff --git a/public/images/divider.png b/public/images/component-thumbnails/divider.png similarity index 100% rename from public/images/divider.png rename to public/images/component-thumbnails/divider.png diff --git a/public/images/drawer.png b/public/images/component-thumbnails/drawer.png similarity index 100% rename from public/images/drawer.png rename to public/images/component-thumbnails/drawer.png diff --git a/public/images/dropdown.png b/public/images/component-thumbnails/dropdown.png similarity index 100% rename from public/images/dropdown.png rename to public/images/component-thumbnails/dropdown.png diff --git a/public/images/file-uploader.png b/public/images/component-thumbnails/file-uploader.png similarity index 100% rename from public/images/file-uploader.png rename to public/images/component-thumbnails/file-uploader.png diff --git a/public/images/filter-chip.png b/public/images/component-thumbnails/filter-chip.png similarity index 100% rename from public/images/filter-chip.png rename to public/images/component-thumbnails/filter-chip.png diff --git a/public/images/footer.png b/public/images/component-thumbnails/footer.png similarity index 100% rename from public/images/footer.png rename to public/images/component-thumbnails/footer.png diff --git a/public/images/form-item.png b/public/images/component-thumbnails/form-item.png similarity index 100% rename from public/images/form-item.png rename to public/images/component-thumbnails/form-item.png diff --git a/public/images/form-stepper.png b/public/images/component-thumbnails/form-stepper.png similarity index 100% rename from public/images/form-stepper.png rename to public/images/component-thumbnails/form-stepper.png diff --git a/public/images/governance-process.png b/public/images/component-thumbnails/governance-process.png similarity index 100% rename from public/images/governance-process.png rename to public/images/component-thumbnails/governance-process.png diff --git a/public/images/grid.png b/public/images/component-thumbnails/grid.png similarity index 100% rename from public/images/grid.png rename to public/images/component-thumbnails/grid.png diff --git a/public/images/header.png b/public/images/component-thumbnails/header.png similarity index 100% rename from public/images/header.png rename to public/images/component-thumbnails/header.png diff --git a/public/images/heading-band.png b/public/images/component-thumbnails/heading-band.png similarity index 100% rename from public/images/heading-band.png rename to public/images/component-thumbnails/heading-band.png diff --git a/public/images/hero-banner.png b/public/images/component-thumbnails/hero-banner.png similarity index 100% rename from public/images/hero-banner.png rename to public/images/component-thumbnails/hero-banner.png diff --git a/public/images/icon-button.png b/public/images/component-thumbnails/icon-button.png similarity index 100% rename from public/images/icon-button.png rename to public/images/component-thumbnails/icon-button.png diff --git a/public/images/icon.png b/public/images/component-thumbnails/icon.png similarity index 100% rename from public/images/icon.png rename to public/images/component-thumbnails/icon.png diff --git a/public/images/icons.png b/public/images/component-thumbnails/icons.png similarity index 100% rename from public/images/icons.png rename to public/images/component-thumbnails/icons.png diff --git a/public/images/input.png b/public/images/component-thumbnails/input.png similarity index 100% rename from public/images/input.png rename to public/images/component-thumbnails/input.png diff --git a/public/images/link.png b/public/images/component-thumbnails/link.png similarity index 100% rename from public/images/link.png rename to public/images/component-thumbnails/link.png diff --git a/public/images/list.png b/public/images/component-thumbnails/list.png similarity index 100% rename from public/images/list.png rename to public/images/component-thumbnails/list.png diff --git a/public/images/microsite-header.png b/public/images/component-thumbnails/microsite-header.png similarity index 100% rename from public/images/microsite-header.png rename to public/images/component-thumbnails/microsite-header.png diff --git a/public/images/modal.png b/public/images/component-thumbnails/modal.png similarity index 100% rename from public/images/modal.png rename to public/images/component-thumbnails/modal.png diff --git a/public/images/not-yet-available.png b/public/images/component-thumbnails/not-yet-available.png similarity index 100% rename from public/images/not-yet-available.png rename to public/images/component-thumbnails/not-yet-available.png diff --git a/public/images/notification-banner.png b/public/images/component-thumbnails/notification-banner.png similarity index 100% rename from public/images/notification-banner.png rename to public/images/component-thumbnails/notification-banner.png diff --git a/public/images/pagination.png b/public/images/component-thumbnails/pagination.png similarity index 100% rename from public/images/pagination.png rename to public/images/component-thumbnails/pagination.png diff --git a/public/images/popover.png b/public/images/component-thumbnails/popover.png similarity index 100% rename from public/images/popover.png rename to public/images/component-thumbnails/popover.png diff --git a/public/images/progress-indicator.png b/public/images/component-thumbnails/progress-indicator.png similarity index 100% rename from public/images/progress-indicator.png rename to public/images/component-thumbnails/progress-indicator.png diff --git a/public/images/radio.png b/public/images/component-thumbnails/radio.png similarity index 100% rename from public/images/radio.png rename to public/images/component-thumbnails/radio.png diff --git a/public/images/side-menu.png b/public/images/component-thumbnails/side-menu.png similarity index 100% rename from public/images/side-menu.png rename to public/images/component-thumbnails/side-menu.png diff --git a/public/images/skeleton-loader.png b/public/images/component-thumbnails/skeleton-loader.png similarity index 100% rename from public/images/skeleton-loader.png rename to public/images/component-thumbnails/skeleton-loader.png diff --git a/public/images/snackbar.png b/public/images/component-thumbnails/snackbar.png similarity index 100% rename from public/images/snackbar.png rename to public/images/component-thumbnails/snackbar.png diff --git a/public/images/spacer.png b/public/images/component-thumbnails/spacer.png similarity index 100% rename from public/images/spacer.png rename to public/images/component-thumbnails/spacer.png diff --git a/public/images/table.png b/public/images/component-thumbnails/table.png similarity index 100% rename from public/images/table.png rename to public/images/component-thumbnails/table.png diff --git a/public/images/tabs.png b/public/images/component-thumbnails/tabs.png similarity index 100% rename from public/images/tabs.png rename to public/images/component-thumbnails/tabs.png diff --git a/public/images/component-thumbnails/temporary-notification.png b/public/images/component-thumbnails/temporary-notification.png new file mode 100644 index 000000000..bfdc1a78f Binary files /dev/null and b/public/images/component-thumbnails/temporary-notification.png differ diff --git a/public/images/text-area.png b/public/images/component-thumbnails/text-area.png similarity index 100% rename from public/images/text-area.png rename to public/images/component-thumbnails/text-area.png diff --git a/public/images/text-field.png b/public/images/component-thumbnails/text-field.png similarity index 100% rename from public/images/text-field.png rename to public/images/component-thumbnails/text-field.png diff --git a/public/images/text.png b/public/images/component-thumbnails/text.png similarity index 100% rename from public/images/text.png rename to public/images/component-thumbnails/text.png diff --git a/public/images/tooltip.png b/public/images/component-thumbnails/tooltip.png similarity index 100% rename from public/images/tooltip.png rename to public/images/component-thumbnails/tooltip.png diff --git a/public/images/example-thumbnails/add-a-filter-chip.png b/public/images/example-thumbnails/add-a-filter-chip.png new file mode 100644 index 000000000..0311798ae Binary files /dev/null and b/public/images/example-thumbnails/add-a-filter-chip.png differ diff --git a/public/images/example-thumbnails/add-a-record-using-a-drawer.png b/public/images/example-thumbnails/add-a-record-using-a-drawer.png new file mode 100644 index 000000000..2f310c12b Binary files /dev/null and b/public/images/example-thumbnails/add-a-record-using-a-drawer.png differ diff --git a/public/images/example-thumbnails/add-and-edit-lots-of-filters.png b/public/images/example-thumbnails/add-and-edit-lots-of-filters.png new file mode 100644 index 000000000..502ccdb25 Binary files /dev/null and b/public/images/example-thumbnails/add-and-edit-lots-of-filters.png differ diff --git a/public/images/example-thumbnails/add-another-item-in-a-modal.png b/public/images/example-thumbnails/add-another-item-in-a-modal.png new file mode 100644 index 000000000..5ffed184c Binary files /dev/null and b/public/images/example-thumbnails/add-another-item-in-a-modal.png differ diff --git a/public/images/example-thumbnails/ask-a-long-answer-question-with-a-maximum-word-count.png b/public/images/example-thumbnails/ask-a-long-answer-question-with-a-maximum-word-count.png new file mode 100644 index 000000000..8cd5ece8c Binary files /dev/null and b/public/images/example-thumbnails/ask-a-long-answer-question-with-a-maximum-word-count.png differ diff --git a/public/images/example-thumbnails/ask-a-user-for-a-birthday.png b/public/images/example-thumbnails/ask-a-user-for-a-birthday.png new file mode 100644 index 000000000..7f2b0539a Binary files /dev/null and b/public/images/example-thumbnails/ask-a-user-for-a-birthday.png differ diff --git a/public/images/example-thumbnails/ask-a-user-for-an-address.png b/public/images/example-thumbnails/ask-a-user-for-an-address.png new file mode 100644 index 000000000..bcfcfa5d8 Binary files /dev/null and b/public/images/example-thumbnails/ask-a-user-for-an-address.png differ diff --git a/public/images/example-thumbnails/ask-a-user-for-an-indian-registration-number.png b/public/images/example-thumbnails/ask-a-user-for-an-indian-registration-number.png new file mode 100644 index 000000000..013fe6279 Binary files /dev/null and b/public/images/example-thumbnails/ask-a-user-for-an-indian-registration-number.png differ diff --git a/public/images/example-thumbnails/ask-a-user-for-direct-deposit-information.png b/public/images/example-thumbnails/ask-a-user-for-direct-deposit-information.png new file mode 100644 index 000000000..7751258d8 Binary files /dev/null and b/public/images/example-thumbnails/ask-a-user-for-direct-deposit-information.png differ diff --git a/public/images/example-thumbnails/ask-a-user-for-dollar-amounts.png b/public/images/example-thumbnails/ask-a-user-for-dollar-amounts.png new file mode 100644 index 000000000..2aea7d074 Binary files /dev/null and b/public/images/example-thumbnails/ask-a-user-for-dollar-amounts.png differ diff --git a/public/images/example-thumbnails/ask-a-user-one-question-at-a-time.png b/public/images/example-thumbnails/ask-a-user-one-question-at-a-time.png new file mode 100644 index 000000000..98e9aaf72 Binary files /dev/null and b/public/images/example-thumbnails/ask-a-user-one-question-at-a-time.png differ diff --git a/public/images/example-thumbnails/ask-a-user-to-select-one-option-from-a-list.png b/public/images/example-thumbnails/ask-a-user-to-select-one-option-from-a-list.png new file mode 100644 index 000000000..164f17b58 Binary files /dev/null and b/public/images/example-thumbnails/ask-a-user-to-select-one-option-from-a-list.png differ diff --git a/public/images/example-thumbnails/basic-page-layout.png b/public/images/example-thumbnails/basic-page-layout.png new file mode 100644 index 000000000..0d88efe4d Binary files /dev/null and b/public/images/example-thumbnails/basic-page-layout.png differ diff --git a/public/images/example-thumbnails/card-grid.png b/public/images/example-thumbnails/card-grid.png new file mode 100644 index 000000000..1e5fddf6a Binary files /dev/null and b/public/images/example-thumbnails/card-grid.png differ diff --git a/public/images/example-thumbnails/card-view-of-case-files.png b/public/images/example-thumbnails/card-view-of-case-files.png new file mode 100644 index 000000000..52e2f65e1 Binary files /dev/null and b/public/images/example-thumbnails/card-view-of-case-files.png differ diff --git a/public/images/example-thumbnails/confirm-a-change.png b/public/images/example-thumbnails/confirm-a-change.png new file mode 100644 index 000000000..24b79f145 Binary files /dev/null and b/public/images/example-thumbnails/confirm-a-change.png differ diff --git a/public/images/example-thumbnails/confirm-a-destructive-action.png b/public/images/example-thumbnails/confirm-a-destructive-action.png new file mode 100644 index 000000000..1ecd3f36d Binary files /dev/null and b/public/images/example-thumbnails/confirm-a-destructive-action.png differ diff --git a/public/images/example-thumbnails/confirm-before-navigating-away.png b/public/images/example-thumbnails/confirm-before-navigating-away.png new file mode 100644 index 000000000..8cfbbd65e Binary files /dev/null and b/public/images/example-thumbnails/confirm-before-navigating-away.png differ diff --git a/public/images/example-thumbnails/confirm-that-an-application-was-submitted.png b/public/images/example-thumbnails/confirm-that-an-application-was-submitted.png new file mode 100644 index 000000000..1491e2f63 Binary files /dev/null and b/public/images/example-thumbnails/confirm-that-an-application-was-submitted.png differ diff --git a/public/images/example-thumbnails/copy-to-clipboard.png b/public/images/example-thumbnails/copy-to-clipboard.png new file mode 100644 index 000000000..eeb484b80 Binary files /dev/null and b/public/images/example-thumbnails/copy-to-clipboard.png differ diff --git a/public/images/example-thumbnails/disabled-button-with-a-required-field.png b/public/images/example-thumbnails/disabled-button-with-a-required-field.png new file mode 100644 index 000000000..c5ab1bf94 Binary files /dev/null and b/public/images/example-thumbnails/disabled-button-with-a-required-field.png differ diff --git a/public/images/example-thumbnails/display-numbers-in-a-table-so-they-can-be-scanned-easily.png b/public/images/example-thumbnails/display-numbers-in-a-table-so-they-can-be-scanned-easily.png new file mode 100644 index 000000000..1ac464167 Binary files /dev/null and b/public/images/example-thumbnails/display-numbers-in-a-table-so-they-can-be-scanned-easily.png differ diff --git a/public/images/example-thumbnails/display-user-information.png b/public/images/example-thumbnails/display-user-information.png new file mode 100644 index 000000000..9868869b1 Binary files /dev/null and b/public/images/example-thumbnails/display-user-information.png differ diff --git a/public/images/example-thumbnails/dynamically-add-an-item-to-a-dropdown-list.png b/public/images/example-thumbnails/dynamically-add-an-item-to-a-dropdown-list.png new file mode 100644 index 000000000..b34250e89 Binary files /dev/null and b/public/images/example-thumbnails/dynamically-add-an-item-to-a-dropdown-list.png differ diff --git a/public/images/example-thumbnails/dynamically-change-items-in-a-dropdown-list.png b/public/images/example-thumbnails/dynamically-change-items-in-a-dropdown-list.png new file mode 100644 index 000000000..2fe98b801 Binary files /dev/null and b/public/images/example-thumbnails/dynamically-change-items-in-a-dropdown-list.png differ diff --git a/public/images/example-thumbnails/expand-or-collapse-part-of-a-form.png b/public/images/example-thumbnails/expand-or-collapse-part-of-a-form.png new file mode 100644 index 000000000..2d3544c8e Binary files /dev/null and b/public/images/example-thumbnails/expand-or-collapse-part-of-a-form.png differ diff --git a/public/images/example-thumbnails/form-stepper-with-controlled-navigation.png b/public/images/example-thumbnails/form-stepper-with-controlled-navigation.png new file mode 100644 index 000000000..643d3a92b Binary files /dev/null and b/public/images/example-thumbnails/form-stepper-with-controlled-navigation.png differ diff --git a/public/images/example-thumbnails/give-background-information-before-asking-a-question.png b/public/images/example-thumbnails/give-background-information-before-asking-a-question.png new file mode 100644 index 000000000..19c829369 Binary files /dev/null and b/public/images/example-thumbnails/give-background-information-before-asking-a-question.png differ diff --git a/public/images/example-thumbnails/give-context-before-asking-a-long-answer-question.png b/public/images/example-thumbnails/give-context-before-asking-a-long-answer-question.png new file mode 100644 index 000000000..5b250c562 Binary files /dev/null and b/public/images/example-thumbnails/give-context-before-asking-a-long-answer-question.png differ diff --git a/public/images/example-thumbnails/group-related-questions-together-on-a-question-page.png b/public/images/example-thumbnails/group-related-questions-together-on-a-question-page.png new file mode 100644 index 000000000..64fefa77c Binary files /dev/null and b/public/images/example-thumbnails/group-related-questions-together-on-a-question-page.png differ diff --git a/public/images/example-thumbnails/header-with-menu-click-event.png b/public/images/example-thumbnails/header-with-menu-click-event.png new file mode 100644 index 000000000..a777ec38b Binary files /dev/null and b/public/images/example-thumbnails/header-with-menu-click-event.png differ diff --git a/public/images/example-thumbnails/header-with-navigation.png b/public/images/example-thumbnails/header-with-navigation.png new file mode 100644 index 000000000..02d92303a Binary files /dev/null and b/public/images/example-thumbnails/header-with-navigation.png differ diff --git a/public/images/example-thumbnails/hero-banner-with-actions.png b/public/images/example-thumbnails/hero-banner-with-actions.png new file mode 100644 index 000000000..7a4132c2d Binary files /dev/null and b/public/images/example-thumbnails/hero-banner-with-actions.png differ diff --git a/public/images/example-thumbnails/hide-and-show-many-sections-of-information.png b/public/images/example-thumbnails/hide-and-show-many-sections-of-information.png new file mode 100644 index 000000000..27f801d02 Binary files /dev/null and b/public/images/example-thumbnails/hide-and-show-many-sections-of-information.png differ diff --git a/public/images/example-thumbnails/include-a-link-in-the-helper-text-of-an-option.png b/public/images/example-thumbnails/include-a-link-in-the-helper-text-of-an-option.png new file mode 100644 index 000000000..917a66cc5 Binary files /dev/null and b/public/images/example-thumbnails/include-a-link-in-the-helper-text-of-an-option.png differ diff --git a/public/images/example-thumbnails/include-descriptions-for-individual-input-options.png b/public/images/example-thumbnails/include-descriptions-for-individual-input-options.png new file mode 100644 index 000000000..1b0ae2145 Binary files /dev/null and b/public/images/example-thumbnails/include-descriptions-for-individual-input-options.png differ diff --git a/public/images/example-thumbnails/indeterminate-progress-search.png b/public/images/example-thumbnails/indeterminate-progress-search.png new file mode 100644 index 000000000..0d5a8283a Binary files /dev/null and b/public/images/example-thumbnails/indeterminate-progress-search.png differ diff --git a/public/images/example-thumbnails/link-the-user-to-give-feedback-to-the-service.png b/public/images/example-thumbnails/link-the-user-to-give-feedback-to-the-service.png new file mode 100644 index 000000000..3a1499264 Binary files /dev/null and b/public/images/example-thumbnails/link-the-user-to-give-feedback-to-the-service.png differ diff --git a/public/images/example-thumbnails/link-to-an-external-page.png b/public/images/example-thumbnails/link-to-an-external-page.png new file mode 100644 index 000000000..baf8068ff Binary files /dev/null and b/public/images/example-thumbnails/link-to-an-external-page.png differ diff --git a/public/images/example-thumbnails/multi-step-process-notifications.png b/public/images/example-thumbnails/multi-step-process-notifications.png new file mode 100644 index 000000000..2093dd1b2 Binary files /dev/null and b/public/images/example-thumbnails/multi-step-process-notifications.png differ diff --git a/public/images/example-thumbnails/progress-notification-with-cancel.png b/public/images/example-thumbnails/progress-notification-with-cancel.png new file mode 100644 index 000000000..365173566 Binary files /dev/null and b/public/images/example-thumbnails/progress-notification-with-cancel.png differ diff --git a/public/images/example-thumbnails/public-form.png b/public/images/example-thumbnails/public-form.png new file mode 100644 index 000000000..81aaf2ed2 Binary files /dev/null and b/public/images/example-thumbnails/public-form.png differ diff --git a/public/images/example-thumbnails/question-page.png b/public/images/example-thumbnails/question-page.png new file mode 100644 index 000000000..570cc575b Binary files /dev/null and b/public/images/example-thumbnails/question-page.png differ diff --git a/public/images/example-thumbnails/remove-a-filter.png b/public/images/example-thumbnails/remove-a-filter.png new file mode 100644 index 000000000..791255a3a Binary files /dev/null and b/public/images/example-thumbnails/remove-a-filter.png differ diff --git a/public/images/example-thumbnails/require-user-action-before-continuing.png b/public/images/example-thumbnails/require-user-action-before-continuing.png new file mode 100644 index 000000000..e07d55991 Binary files /dev/null and b/public/images/example-thumbnails/require-user-action-before-continuing.png differ diff --git a/public/images/example-thumbnails/reset-date-picker-field.png b/public/images/example-thumbnails/reset-date-picker-field.png new file mode 100644 index 000000000..4a85ce690 Binary files /dev/null and b/public/images/example-thumbnails/reset-date-picker-field.png differ diff --git a/public/images/example-thumbnails/result-page.png b/public/images/example-thumbnails/result-page.png new file mode 100644 index 000000000..1a5b623da Binary files /dev/null and b/public/images/example-thumbnails/result-page.png differ diff --git a/public/images/example-thumbnails/reveal-more-information-to-help-answer-a-question.png b/public/images/example-thumbnails/reveal-more-information-to-help-answer-a-question.png new file mode 100644 index 000000000..abe34421c Binary files /dev/null and b/public/images/example-thumbnails/reveal-more-information-to-help-answer-a-question.png differ diff --git a/public/images/example-thumbnails/review-and-action.png b/public/images/example-thumbnails/review-and-action.png new file mode 100644 index 000000000..8a5d85499 Binary files /dev/null and b/public/images/example-thumbnails/review-and-action.png differ diff --git a/public/images/example-thumbnails/review-page.png b/public/images/example-thumbnails/review-page.png new file mode 100644 index 000000000..991538adc Binary files /dev/null and b/public/images/example-thumbnails/review-page.png differ diff --git a/public/images/example-thumbnails/search.png b/public/images/example-thumbnails/search.png new file mode 100644 index 000000000..38941dae8 Binary files /dev/null and b/public/images/example-thumbnails/search.png differ diff --git a/public/images/example-thumbnails/select-one-or-more-from-a-list-of-options.png b/public/images/example-thumbnails/select-one-or-more-from-a-list-of-options.png new file mode 100644 index 000000000..ca72beebe Binary files /dev/null and b/public/images/example-thumbnails/select-one-or-more-from-a-list-of-options.png differ diff --git a/public/images/example-thumbnails/set-a-max-width-on-a-long-radio-item.png b/public/images/example-thumbnails/set-a-max-width-on-a-long-radio-item.png new file mode 100644 index 000000000..64632ddee Binary files /dev/null and b/public/images/example-thumbnails/set-a-max-width-on-a-long-radio-item.png differ diff --git a/public/images/example-thumbnails/set-a-specific-tab-to-be-active.png b/public/images/example-thumbnails/set-a-specific-tab-to-be-active.png new file mode 100644 index 000000000..ad801581b Binary files /dev/null and b/public/images/example-thumbnails/set-a-specific-tab-to-be-active.png differ diff --git a/public/images/example-thumbnails/set-the-status-of-step-on-a-form-stepper.png b/public/images/example-thumbnails/set-the-status-of-step-on-a-form-stepper.png new file mode 100644 index 000000000..8a2254918 Binary files /dev/null and b/public/images/example-thumbnails/set-the-status-of-step-on-a-form-stepper.png differ diff --git a/public/images/example-thumbnails/show-a-label-on-an-icon-only-button.png b/public/images/example-thumbnails/show-a-label-on-an-icon-only-button.png new file mode 100644 index 000000000..71859f125 Binary files /dev/null and b/public/images/example-thumbnails/show-a-label-on-an-icon-only-button.png differ diff --git a/public/images/example-thumbnails/show-a-list-to-help-answer-a-question.png b/public/images/example-thumbnails/show-a-list-to-help-answer-a-question.png new file mode 100644 index 000000000..d2662a1c9 Binary files /dev/null and b/public/images/example-thumbnails/show-a-list-to-help-answer-a-question.png differ diff --git a/public/images/example-thumbnails/show-a-notification-with-an-action.png b/public/images/example-thumbnails/show-a-notification-with-an-action.png new file mode 100644 index 000000000..fd2824956 Binary files /dev/null and b/public/images/example-thumbnails/show-a-notification-with-an-action.png differ diff --git a/public/images/example-thumbnails/show-a-notification.png b/public/images/example-thumbnails/show-a-notification.png new file mode 100644 index 000000000..e1d26d8a1 Binary files /dev/null and b/public/images/example-thumbnails/show-a-notification.png differ diff --git a/public/images/example-thumbnails/show-a-section-title-on-a-question-page.png b/public/images/example-thumbnails/show-a-section-title-on-a-question-page.png new file mode 100644 index 000000000..cdc3a56f0 Binary files /dev/null and b/public/images/example-thumbnails/show-a-section-title-on-a-question-page.png differ diff --git a/public/images/example-thumbnails/show-a-simple-progress-indicator-on-a-question-page-with-multiple-questions.png b/public/images/example-thumbnails/show-a-simple-progress-indicator-on-a-question-page-with-multiple-questions.png new file mode 100644 index 000000000..4d00de341 Binary files /dev/null and b/public/images/example-thumbnails/show-a-simple-progress-indicator-on-a-question-page-with-multiple-questions.png differ diff --git a/public/images/example-thumbnails/show-a-simple-progress-indicator-on-a-question-page.png b/public/images/example-thumbnails/show-a-simple-progress-indicator-on-a-question-page.png new file mode 100644 index 000000000..8390ee631 Binary files /dev/null and b/public/images/example-thumbnails/show-a-simple-progress-indicator-on-a-question-page.png differ diff --git a/public/images/example-thumbnails/show-a-user-progress-when-the-time-is-unknown.png b/public/images/example-thumbnails/show-a-user-progress-when-the-time-is-unknown.png new file mode 100644 index 000000000..193500499 Binary files /dev/null and b/public/images/example-thumbnails/show-a-user-progress-when-the-time-is-unknown.png differ diff --git a/public/images/example-thumbnails/show-a-user-progress.png b/public/images/example-thumbnails/show-a-user-progress.png new file mode 100644 index 000000000..58aa23b17 Binary files /dev/null and b/public/images/example-thumbnails/show-a-user-progress.png differ diff --git a/public/images/example-thumbnails/show-different-views-of-data-in-a-table.png b/public/images/example-thumbnails/show-different-views-of-data-in-a-table.png new file mode 100644 index 000000000..4f31ece15 Binary files /dev/null and b/public/images/example-thumbnails/show-different-views-of-data-in-a-table.png differ diff --git a/public/images/example-thumbnails/show-full-date-in-a-tooltip.png b/public/images/example-thumbnails/show-full-date-in-a-tooltip.png new file mode 100644 index 000000000..9117f8024 Binary files /dev/null and b/public/images/example-thumbnails/show-full-date-in-a-tooltip.png differ diff --git a/public/images/example-thumbnails/show-links-to-navigation-items.png b/public/images/example-thumbnails/show-links-to-navigation-items.png new file mode 100644 index 000000000..d24d9b1ab Binary files /dev/null and b/public/images/example-thumbnails/show-links-to-navigation-items.png differ diff --git a/public/images/example-thumbnails/show-multiple-actions-in-a-table.png b/public/images/example-thumbnails/show-multiple-actions-in-a-table.png new file mode 100644 index 000000000..cb54b7a87 Binary files /dev/null and b/public/images/example-thumbnails/show-multiple-actions-in-a-table.png differ diff --git a/public/images/example-thumbnails/show-multiple-tags-together.png b/public/images/example-thumbnails/show-multiple-tags-together.png new file mode 100644 index 000000000..9032c5993 Binary files /dev/null and b/public/images/example-thumbnails/show-multiple-tags-together.png differ diff --git a/public/images/example-thumbnails/show-number-of-results-per-page.png b/public/images/example-thumbnails/show-number-of-results-per-page.png new file mode 100644 index 000000000..1888db425 Binary files /dev/null and b/public/images/example-thumbnails/show-number-of-results-per-page.png differ diff --git a/public/images/example-thumbnails/show-quick-links.png b/public/images/example-thumbnails/show-quick-links.png new file mode 100644 index 000000000..486b2e1d8 Binary files /dev/null and b/public/images/example-thumbnails/show-quick-links.png differ diff --git a/public/images/example-thumbnails/show-status-in-a-table.png b/public/images/example-thumbnails/show-status-in-a-table.png new file mode 100644 index 000000000..88c4eb40f Binary files /dev/null and b/public/images/example-thumbnails/show-status-in-a-table.png differ diff --git a/public/images/example-thumbnails/show-status-on-a-card.png b/public/images/example-thumbnails/show-status-on-a-card.png new file mode 100644 index 000000000..f0cc2c653 Binary files /dev/null and b/public/images/example-thumbnails/show-status-on-a-card.png differ diff --git a/public/images/example-thumbnails/show-version-number.png b/public/images/example-thumbnails/show-version-number.png new file mode 100644 index 000000000..a411bb0e3 Binary files /dev/null and b/public/images/example-thumbnails/show-version-number.png differ diff --git a/public/images/example-thumbnails/slotted-error-text-in-a-form-item.png b/public/images/example-thumbnails/slotted-error-text-in-a-form-item.png new file mode 100644 index 000000000..a6978dd60 Binary files /dev/null and b/public/images/example-thumbnails/slotted-error-text-in-a-form-item.png differ diff --git a/public/images/example-thumbnails/slotted-helper-text-in-a-form-item.png b/public/images/example-thumbnails/slotted-helper-text-in-a-form-item.png new file mode 100644 index 000000000..5c17d414f Binary files /dev/null and b/public/images/example-thumbnails/slotted-helper-text-in-a-form-item.png differ diff --git a/public/images/example-thumbnails/sort-data-in-a-table.png b/public/images/example-thumbnails/sort-data-in-a-table.png new file mode 100644 index 000000000..c93d720cd Binary files /dev/null and b/public/images/example-thumbnails/sort-data-in-a-table.png differ diff --git a/public/images/example-thumbnails/start-page.png b/public/images/example-thumbnails/start-page.png new file mode 100644 index 000000000..0a63536ed Binary files /dev/null and b/public/images/example-thumbnails/start-page.png differ diff --git a/public/images/example-thumbnails/task-list-page.png b/public/images/example-thumbnails/task-list-page.png new file mode 100644 index 000000000..ea730beb7 Binary files /dev/null and b/public/images/example-thumbnails/task-list-page.png differ diff --git a/public/images/example-thumbnails/type-to-create-a-new-filter.png b/public/images/example-thumbnails/type-to-create-a-new-filter.png new file mode 100644 index 000000000..5cef373b7 Binary files /dev/null and b/public/images/example-thumbnails/type-to-create-a-new-filter.png differ diff --git a/public/images/example-thumbnails/warn-a-user-of-a-deadline.png b/public/images/example-thumbnails/warn-a-user-of-a-deadline.png new file mode 100644 index 000000000..ee4a47fab Binary files /dev/null and b/public/images/example-thumbnails/warn-a-user-of-a-deadline.png differ diff --git a/src/App.tsx b/src/App.tsx index cfda0d9e9..9c6cb9b45 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -12,12 +12,14 @@ import Root from "@routes/root"; import { DeviceWidthProvider } from "@contexts/DeviceWidthContext"; import "./index.css"; -// Support +import { + VersionUpdateNotificationProvider +} from "@components/version-language-switcher/VersionUpdateNotificationContext"; +import { SiteWideNotificationProvider } from "@contexts/SiteWideNotificationContext"; import HomePage from "@routes/home"; // Design Tokens - import DesignTokensOverviewPage from "@routes/design-tokens/overview/Overview"; import BorderRadiusPage from "@routes/design-tokens/border-radius/BorderRadius"; import BorderWidthPage from "@routes/design-tokens/border-width/BorderWidth"; @@ -30,7 +32,6 @@ import SpacingPage from "@routes/design-tokens/spacing/Spacing"; import TypographyPage from "@routes/design-tokens/typography/Typography"; // Get Started - import DevelopersOverviewPage from "@routes/get-started/developers/DevelopersOverview"; import DevelopersSetupPage from "@routes/get-started/developers/DevelopersSetup"; import DevelopersTechnologiesPage from "@routes/get-started/developers/DevelopersTechnologies"; @@ -47,22 +48,18 @@ import ReportBugPage from "@routes/get-started/ReportBug"; import RoadmapPage from "@routes/get-started/Roadmap"; import SupportedBrowsersPage from "@routes/get-started/developers/SupportedBrowsers"; import UxDesignerPage from "@routes/get-started/designers/UxDesigner"; -import { LtsPolicyPage } from "@routes/get-started/LtsPolicyPage.tsx"; - -// Content Pages - -import ContentLayout from "@routes/content/ContentLayout"; -import CapitalizationPage from "@routes/content/Capitalization"; -import DateFormatPage from "@routes/content/DateFormat"; -import ErrorMessagesPage from "@routes/content/ErrorMessages"; -import HelperTextPage from "@routes/content/HelperText"; import UserExperienceGuidelinesPage from "@routes/get-started/UserExperienceGuidelines"; +import { LtsPolicyPage } from "@routes/get-started/LtsPolicyPage.tsx"; +// Examples Pages import { VersionFromUrlProvider } from "@contexts/VersionFromUrlContext.tsx"; -import { ComponentsRouter, PatternsRouter } from "./versioned-router"; +import { ComponentsRouter } from "./versioned-router"; +import ExamplePageTemplate from "@routes/examples/ExamplePageTemplate"; import ComponentNotFound from "@routes/not-found/NotFound.tsx"; -import { LanguageVersionProvider } from "@contexts/LanguageVersionContext.tsx"; +import { LanguageVersionContext, LanguageVersionProvider } from "@contexts/LanguageVersionContext.tsx"; import DevelopersUpgradePage from "@routes/get-started/developers/upgrade-guide/DevelopersUpgrade.tsx"; +import ExamplesLayout from "@routes/examples/ExamplesLayout.tsx"; +import ExamplesOverviewPage from "@routes/examples/ExamplesOverview.tsx"; // Foundations Pages import FoundationsLayout from "@routes/foundations/FoundationsLayout"; @@ -75,12 +72,20 @@ import ImagesPage from "@routes/foundations/Photography"; import LogoPage from "@routes/foundations/Logo"; import FoundationsTypographyPage from "@routes/foundations/Typography"; import FoundationsLayoutPage from "@routes/foundations/Layout"; +import CapitalizationPage from "@routes/foundations/Capitalization.tsx"; +import DateFormatPage from "@routes/foundations/DateFormat.tsx"; +import ErrorMessagesPage from "@routes/foundations/ErrorMessages.tsx"; +import HelperTextPage from "@routes/foundations/HelperText.tsx"; const router = createBrowserRouter( createRoutesFromElements( }> } /> - }> + + {/* Component Pages */} + } /> + + {/* Design tokens Pages */} } errorElement={}> } /> } /> @@ -93,11 +98,10 @@ const router = createBrowserRouter( } /> + {/* Get started Pages */} }> } /> - - } /> - + } /> } /> } /> @@ -107,6 +111,7 @@ const router = createBrowserRouter( } /> } /> + } /> @@ -122,11 +127,13 @@ const router = createBrowserRouter( } /> } /> + } /> } /> - }> + {/* Foundations Pages */} + }> } /> } /> } /> @@ -136,18 +143,17 @@ const router = createBrowserRouter( } /> } /> } /> - - - }> - - } /> - + } /> } /> } /> } /> - }> + {/* Examples Pages */} + }> + } /> + + } /> ) ); @@ -157,9 +163,17 @@ ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render( - + + {({ version }) => ( + + + + + + )} + -); +); \ No newline at end of file diff --git a/src/components/component-card/ComponentCard.css b/src/components/component-card/ComponentCard.css index 998329079..da7df0c62 100644 --- a/src/components/component-card/ComponentCard.css +++ b/src/components/component-card/ComponentCard.css @@ -19,7 +19,6 @@ } .card-content a { - font-size: var(--goa-font-size-7); display: flex; } diff --git a/src/components/component-card/ComponentCard.tsx b/src/components/component-card/ComponentCard.tsx index 9e1d9daa9..f3d0e1645 100644 --- a/src/components/component-card/ComponentCard.tsx +++ b/src/components/component-card/ComponentCard.tsx @@ -3,11 +3,11 @@ import "./ComponentCard.css"; import { toKebabCase } from "../../utils"; import { GoabBadge, GoabText } from "@abgov/react-components"; import { useState, useEffect } from "react"; - -export type ComponentStatus = "Published" | "Not Published" | "In Progress"; +import { NEW_COMPONENTS } from "../../global-constants"; +export type ComponentStatus = "Available" | "Legacy" | "Not Published" | "In Progress"; // Define allowed group options as a union type -type Group = +export type Group = | "Content layout" | "Feedback and alerts" | "Inputs and actions" @@ -17,50 +17,58 @@ import { useContext } from "react"; import { LanguageVersionContext } from "@contexts/LanguageVersionContext.tsx"; import { ANGULAR_VERSIONS, REACT_VERSIONS } from "@components/version-language-switcher/version-language-constants.ts"; -export interface Props { +export interface ComponentCardProps { name: string; description: string; - groups: Group[]; // Use the Group type here tags?: string[]; status: ComponentStatus; githubLink?: string; openIssues?: number; isNew?: boolean; // if true, show a badge on the component card to let users know the component is available in the latest version + designSystemUrl?: string; + designComponentFigmaUrl?: string; + designContributionFigmaUrl?: string; + imageFolder?: "component-thumbnails" | "example-thumbnails"; } function dasherize(value: string): string { - return value.split(" ").join("-"); + return value.toLowerCase().split(" ").join("-"); +} + +function isRelativeUrl(url?: string): boolean { + return url !== undefined && !/^https?:\/\//i.test(url); } -export function ComponentCard(props: Props) { - const [imageUrl, setImageUrl] = useState(`/images/${dasherize(props.name)}.png`); +export function ComponentCard(props: ComponentCardProps) { + const folder = props.imageFolder ?? "components"; + const [imageUrl, setImageUrl] = useState(`/images/${folder}/${dasherize(props.name)}.png`); useEffect(() => { const testImage = new Image(); testImage.src = imageUrl; - testImage.onerror = () => setImageUrl("/images/not-yet-available.png"); + testImage.onerror = () => setImageUrl("/images/component-thumbnails/not-yet-available.png"); }, [imageUrl]); const getBadgeType = (status: ComponentStatus) => { switch (status) { - case "Published": - return null; // No badge for "Published" + case "Available": //Published replaced with Available + return null; // No badge for "Available" case "Not Published": - return "information"; + return "light"; case "In Progress": return "important"; default: - return "information"; // Fallback for unknown status + return "information"; // Fallback for Legacy and unknown status } }; - - const badgeType = getBadgeType(props.status); - - const {language} = useContext(LanguageVersionContext); + getBadgeType(props.status); + const { language, version } = useContext(LanguageVersionContext); return ( +
- {props.status === "Published" ? ( - + {props.status === "Available" || props.status === "Legacy" ? ( +
+ >
)}
-
- {badgeType && } - - {props.status === "Published" ? ( - - - {`${props.name.substring(0, 1).toUpperCase()}${props.name.substring(1)}`} - - + {props.status !== "Available" && ( + + )} +

+ {props.status === "Available" || props.status === "Legacy" ? ( + {props.name} ) : ( - - - {`${props.name.substring(0, 1).toUpperCase()}${props.name.substring(1)}`} - - + props.name )} -

- + + {props.description} - {props.status !== "Published" && props.githubLink && ( - + + + {props.status !== "Available" && props.githubLink && ( + - View issues{typeof props.openIssues === 'number' && ` (${props.openIssues})`} + {props.imageFolder === "example-thumbnails" ? "View issue" : "View open issues"} + {props.imageFolder === "example-thumbnails" ? "" : props.openIssues !== undefined ? ` (${props.openIssues})` : ""} )} - {props.isNew && } + + {NEW_COMPONENTS.includes(props.name) && ( + + )}
); diff --git a/src/components/component-header/ComponentHeader.tsx b/src/components/component-header/ComponentHeader.tsx index c4c884f34..49e66124d 100644 --- a/src/components/component-header/ComponentHeader.tsx +++ b/src/components/component-header/ComponentHeader.tsx @@ -2,7 +2,7 @@ import { GoabBadge, GoabBlock, GoabText } from "@abgov/react-components"; import "./ComponentHeader.css"; import { Link } from "react-router-dom"; import { useEffect, useState } from "react"; -import { toSentenceCase, fetchIssueCount } from "../../utils"; +import { toSentenceCase, fetchAllIssueCounts, fetchComponentMetadataFromProject } from "../../utils"; export enum Category { CONTENT_AND_LAYOUT = "Content and layout", @@ -29,7 +29,9 @@ export const ComponentHeader: React.FC = (props) => { const getCount = async () => { const label = toSentenceCase(props.githubLink!); - const count = await fetchIssueCount(label); + const metadata = await fetchComponentMetadataFromProject(); + const Allcounts = await fetchAllIssueCounts("Components", metadata); + const count = Allcounts[label] || 0; setIssueCount(count); }; diff --git a/src/components/component-properties/ComponentProperties.tsx b/src/components/component-properties/ComponentProperties.tsx index df79a0799..3d78c54bb 100644 --- a/src/components/component-properties/ComponentProperties.tsx +++ b/src/components/component-properties/ComponentProperties.tsx @@ -1,4 +1,5 @@ import { GoabBadge, GoabContainer, GoabText } from "@abgov/react-components"; +import { GoabBadgeType } from "@abgov/ui-components-common"; import { useContext, useEffect, useState } from "react"; import css from "./ComponentProperties.module.css"; @@ -10,6 +11,7 @@ export type ComponentProperty = { required?: boolean; description?: string; defaultValue?: string; + badge?: { content: string; type: GoabBadgeType }; }; interface Props { @@ -19,7 +21,7 @@ interface Props { } export const ComponentProperties = (props: Props) => { - const {language, version} = useContext(LanguageVersionContext); + const { language, version } = useContext(LanguageVersionContext); const [filteredProperties, setFilteredProperties] = useState([]); @@ -45,20 +47,17 @@ export const ComponentProperties = (props: Props) => { return ( <> - {props.heading || "Properties"} - - + {" "} + + {props.heading || "Properties"} + +
{filteredProperties.map((props, index) => ( - ))}
@@ -71,13 +70,14 @@ interface ComponentPropertyProps { props: ComponentProperty; } -function ComponentProperty({ props }: ComponentPropertyProps) { +export function ComponentProperty({ props }: ComponentPropertyProps) { return (
{props.name} {props.required && } + {props.badge && } {props.type && ( @@ -90,11 +90,8 @@ function ComponentProperty({ props }: ComponentPropertyProps) { {props.description} {props.defaultValue && ( -
- {" "} - Defaults to {props.defaultValue}. +
Defaults to {props.defaultValue}.
- )}
diff --git a/src/components/example-card/ExampleCard.css b/src/components/example-card/ExampleCard.css new file mode 100644 index 000000000..920a61727 --- /dev/null +++ b/src/components/example-card/ExampleCard.css @@ -0,0 +1,40 @@ +.card { + border: 1px solid var(--goa-color-greyscale-200); + border-radius: 4px; + overflow: hidden; +} + +.card-image { + width: 100%; + height: 200px; + background-size: cover; + background-repeat: no-repeat; + background-position: center; + border-bottom: 1px solid var(--goa-color-greyscale-200); + background-color: #F8F8F8; +} + +.card-content { + padding: 1.5rem; +} + +.card-content a { + display: flex; +} + +.card-content a.github-link { + font: var(--goa-typography-body-s); + margin-top: 1rem; + margin-bottom: 0; +} + +.card-content a:focus { + outline: none; + box-shadow: none; + background: none; +} + +.card:focus-within { + outline: 3px solid var(--goa-color-interactive-focus); + border-radius: 4px; +} \ No newline at end of file diff --git a/src/components/example-card/ExampleCard.tsx b/src/components/example-card/ExampleCard.tsx new file mode 100644 index 000000000..da24dc60e --- /dev/null +++ b/src/components/example-card/ExampleCard.tsx @@ -0,0 +1,151 @@ +import { Link } from "react-router-dom"; +import "./ExampleCard.css"; +import { toKebabCase } from "../../utils"; +import { GoabBadge, GoabText } from "@abgov/react-components"; +import { useState, useEffect } from "react"; + +export type ComponentStatus = "Available" | "Not Published" | "In Progress" | "Legacy"; + +// Define allowed group options as a union type +export type Group = + | "Content layout" + | "Feedback and alerts" + | "Inputs and actions" + | "Structure and navigation" + | "Utilities"; +import { useContext } from "react"; +import { LanguageVersionContext } from "@contexts/LanguageVersionContext.tsx"; +import { ANGULAR_VERSIONS, REACT_VERSIONS } from "@components/version-language-switcher/version-language-constants.ts"; + +function dasherize(value: string): string { + return value.toLowerCase().split(" ").join("-"); +} + +function isRelativeUrl(url?: string): boolean { + return url !== undefined && !/^https?:\/\//i.test(url); +} + +export interface ExampleCardProps { + name: string; + description: string; + tags?: string[]; + status: ComponentStatus; + githubLink?: string; + openIssues?: number; + isNew?: boolean; // if true, show a badge on the component card to let users know the component is available in the latest version + exampleUrl?: string; + designComponentFigmaUrl?: string; + designContributionFigmaUrl?: string; + imageFolder?: "component-thumbnails" | "example-thumbnails"; +} + +export function ExampleCard(props: ExampleCardProps) { + const folder = props.imageFolder ?? "example-thumbnails"; + const [imageUrl, setImageUrl] = useState(`/images/${folder}/${dasherize(props.name)}.png`); + + useEffect(() => { + const testImage = new Image(); + testImage.src = imageUrl; + testImage.onerror = () => { + if (props.status !== "Available") { + setImageUrl("/images/component-thumbnails/not-yet-available.png"); + } else { + setImageUrl(""); + } + }; + }, [imageUrl, props.status]); + + const getBadgeType = (status: ComponentStatus) => { + switch (status) { + case "Available": + return null; // No badge for "Available" + case "Not Published": + return "light"; + case "In Progress": + return "important"; + default: + return "information"; // Fallback for unknown status + } + }; + getBadgeType(props.status); + const { language } = useContext(LanguageVersionContext); + return ( + +
+ {props.status === "Available" ? ( + +
+ + ) : ( +
+ )} +
+ {props.isNew && ( + + )} + {props.status !== "Available" && ( + + )} +

+ {props.status === "Available" ? ( + {props.name} + ) : ( + props.name + )} +

+ + {props.description} + + + {props.tags?.map((tag) => ( + + ))} + + {props.status !== "Available" && props.githubLink && ( + + + View issue + + + )} + +
+
+ ); +} diff --git a/src/components/example-header/ExampleHeader.tsx b/src/components/example-header/ExampleHeader.tsx new file mode 100644 index 000000000..7de2e3a6d --- /dev/null +++ b/src/components/example-header/ExampleHeader.tsx @@ -0,0 +1,95 @@ +import { GoabBlock, GoabText, GoabBadge } from "@abgov/react-components"; +import "../component-header/ComponentHeader.css"; // reusing existing styling from component pages + +interface Props { + name: string; + description?: string; + githubLink?: string; + figmaLink?: string; + tags?: string[]; +} + +export const ExampleHeader: React.FC = ({ name, description, githubLink, figmaLink, tags }) => { + return ( +
+ + + {tags && tags.length > 0 && ( + + {tags.map((tag, index) => { + let type: "information" | "important" | "success" | "emergency" = "information"; + + if (/ask/i.test(tag)) type = "important"; + else if (/interact/i.test(tag)) type = "information"; + else if (/page/i.test(tag)) type = "success"; + else if (/error|block/i.test(tag)) type = "emergency"; + + return ( + + ); + })} + + )} + + + + + {name} + + + + {description && ( + + {description} + + )} + {(githubLink || figmaLink) && ( + + + {githubLink && ( + + + + Github issue + + + )} + {figmaLink && ( + +
+ + + + + + + +
+ + Figma + +
+ )} +
+ )} +
+
+ ); +}; \ No newline at end of file diff --git a/src/components/function-properties/FunctionProperties.tsx b/src/components/function-properties/FunctionProperties.tsx new file mode 100644 index 000000000..587299765 --- /dev/null +++ b/src/components/function-properties/FunctionProperties.tsx @@ -0,0 +1,74 @@ +import { GoabText, GoabContainer } from "@abgov/react-components"; +import { ReactNode, useContext, useEffect, useState } from "react"; + +import { ComponentProperty as ComponentPropertyType, ComponentProperty } from "@components/component-properties/ComponentProperties.tsx"; +import { LanguageVersionContext } from "@contexts/LanguageVersionContext.tsx"; + +interface Props { + properties: ComponentPropertyType[]; + oldProperties?: ComponentPropertyType[]; + heading?: string; + subHeading?: ReactNode; + codeSnippets?: { + angular?: ReactNode; + react?: ReactNode; + }; +} + +export const FunctionProperties = (props: Props) => { + const { language, version } = useContext(LanguageVersionContext); + const [filteredProperties, setFilteredProperties] = useState([]); + + const filterBy = (properties: ComponentPropertyType[]) => { + const result = properties.filter((child: ComponentPropertyType) => { + return !child.lang || child.lang === language; + }); + return result; + }; + + useEffect(() => { + if (version === "old") { + setFilteredProperties([...filterBy(props.oldProperties || props.properties)]); + return; + } + setFilteredProperties([...filterBy(props.properties)]); + }, [language, version, props.properties, props.oldProperties]); + + function dasherize(str: string): string { + return str.replace(" ", "-").toLowerCase(); + } + + return ( + <> + + + {props.heading || "Function Properties"} + + {props.subHeading && ( + + {props.subHeading} + + )} + + {props.codeSnippets && ( +
+ {props.codeSnippets.angular} + {props.codeSnippets.react} +
+ )} + + +
+ {filteredProperties.map((property, index) => ( + + ))} +
+
+ + ); +}; diff --git a/src/components/legacy-callout-banner/LegacyCalloutBanner.tsx b/src/components/legacy-callout-banner/LegacyCalloutBanner.tsx new file mode 100644 index 000000000..0ce118d09 --- /dev/null +++ b/src/components/legacy-callout-banner/LegacyCalloutBanner.tsx @@ -0,0 +1,20 @@ +import { GoabCallout } from "@abgov/react-components"; +import { ReactNode } from "react"; +interface LegacyCalloutBannerProps { + heading?: string; + children?: ReactNode; +} + +export const LegacyCalloutBanner = ({ + heading, + children, +}: LegacyCalloutBannerProps) => { + + return ( + + {children} + + ); +}; + +export default LegacyCalloutBanner; diff --git a/src/components/old-component-banner/OldComponentBanner.tsx b/src/components/old-component-banner/OldComponentBanner.tsx index 651e1c7f9..bb4718e6d 100644 --- a/src/components/old-component-banner/OldComponentBanner.tsx +++ b/src/components/old-component-banner/OldComponentBanner.tsx @@ -10,7 +10,7 @@ interface OldComponentBannerProps { export const OldComponentBanner = ({ componentName, language, type = "component" }: OldComponentBannerProps) => { return ( - This {type} is only available in {language == "angular" ? ANGULAR_VERSIONS.NEW.label.substring(0,2).toUpperCase() diff --git a/src/components/version-language-switcher/HelpButton.tsx b/src/components/version-language-switcher/HelpButton.tsx new file mode 100644 index 000000000..60eb0424a --- /dev/null +++ b/src/components/version-language-switcher/HelpButton.tsx @@ -0,0 +1,38 @@ +import { useContext } from "react"; +import { useLocation } from "react-router-dom"; +import { GoabIconButton, GoabTooltip } from "@abgov/react-components"; + +import { useVersionUpdateNotification } from "@components/version-language-switcher/VersionUpdateNotificationContext"; +import { useSiteWideNotification } from "@contexts/SiteWideNotificationContext"; +import { LanguageVersionContext } from "@contexts/LanguageVersionContext"; + +export function HelpButton() { + const { reset: resetVersion } = useVersionUpdateNotification(); + const { reset: resetSiteWideNotification } = useSiteWideNotification(); + useContext(LanguageVersionContext); + const location = useLocation(); + + const handleHelpClick = () => { + const isComponentOrExamplePage = + location.pathname.startsWith("/components") || location.pathname.startsWith("/examples"); + + if (isComponentOrExamplePage) { + resetVersion(); + } else { + resetSiteWideNotification(); + } + }; + + return ( + + + + ); +} \ No newline at end of file diff --git a/src/components/version-language-switcher/SiteWideNotification.tsx b/src/components/version-language-switcher/SiteWideNotification.tsx new file mode 100644 index 000000000..e97172d45 --- /dev/null +++ b/src/components/version-language-switcher/SiteWideNotification.tsx @@ -0,0 +1,23 @@ +import { GoabNotification } from "@abgov/react-components"; +import { useLocation } from "react-router-dom"; +import { useSiteWideNotification } from "@contexts/SiteWideNotificationContext"; +import { MAX_CONTENT_WIDTH } from "../../global-constants.ts"; + +export function SiteWideNotification() { + const { isDismissed, dismiss } = useSiteWideNotification(); + const location = useLocation(); + + const isComponentOrExamplePage = + location.pathname.startsWith("/components") || location.pathname.startsWith("/examples"); + + if (isComponentOrExamplePage || isDismissed) return null; + + return ( + + Select your development framework to see all code in your development language. Change framework and version at + the top right of the screen. + + ); +} + +export default SiteWideNotification; \ No newline at end of file diff --git a/src/components/version-language-switcher/VersionLanguageSwitcher.tsx b/src/components/version-language-switcher/VersionLanguageSwitcher.tsx index 843b86f3d..eab1f6c55 100644 --- a/src/components/version-language-switcher/VersionLanguageSwitcher.tsx +++ b/src/components/version-language-switcher/VersionLanguageSwitcher.tsx @@ -1,6 +1,6 @@ import { GoabIcon, - GoabPopover, + GoabPopover, GoabTooltip } from "@abgov/react-components"; import { ANGULAR_VERSIONS, getVersionedUrlPath, Language, LanguageVersion, @@ -103,6 +103,7 @@ export const VersionLanguageSwitcher = () => { return ( <> + openLanguagePopOver(e)}> @@ -118,7 +119,9 @@ export const VersionLanguageSwitcher = () => { } + + openVersionPopOver(e)}> @@ -133,7 +136,7 @@ export const VersionLanguageSwitcher = () => { ))} - + ); } diff --git a/src/components/version-language-switcher/VersionUpdateNotification.tsx b/src/components/version-language-switcher/VersionUpdateNotification.tsx new file mode 100644 index 000000000..a6156a5a6 --- /dev/null +++ b/src/components/version-language-switcher/VersionUpdateNotification.tsx @@ -0,0 +1,48 @@ +import { useEffect } from "react"; +import { GoabNotification } from "@abgov/react-components"; +import { MAX_CONTENT_WIDTH } from "../../global-constants"; +import { useVersionUpdateNotification } from "./VersionUpdateNotificationContext"; +import type { LanguageVersion } from "@components/version-language-switcher/version-language-constants"; + +interface VersionUpdateNotificationProps { + version: LanguageVersion; +} + +export function VersionUpdateNotification({ version }: VersionUpdateNotificationProps) { + const { isDismissed, dismiss, oldLinkRef, newLinkRef } = useVersionUpdateNotification(); + + useEffect(() => { + const el = document.querySelector("goa-notification"); + if (!el) return; + + const handleDismiss = () => dismiss(); + el.addEventListener("_dismiss", handleDismiss as EventListener); + + return () => el.removeEventListener("_dismiss", handleDismiss as EventListener); + }, [dismiss]); + + if (isDismissed) return null; + + return ( + + {version === "old" ? ( + <> + Support for the Long Term Support (LTS) version of the Design system will be available until September + 2025.{" "} + + View the upgrade guide + + + ) : ( + <> + Upgrading to the latest version of the design system?{" "} + + View the upgrade guide + + + )} + + ); +} + +export default VersionUpdateNotification; \ No newline at end of file diff --git a/src/components/version-language-switcher/VersionUpdateNotificationContext.tsx b/src/components/version-language-switcher/VersionUpdateNotificationContext.tsx new file mode 100644 index 000000000..315a68811 --- /dev/null +++ b/src/components/version-language-switcher/VersionUpdateNotificationContext.tsx @@ -0,0 +1,55 @@ +import { createContext, useContext, useEffect, useRef, useState } from "react"; +import type { LanguageVersion } from "@components/version-language-switcher/version-language-constants"; + +interface VersionUpdateNotificationContextType { + isDismissed: boolean; + dismiss: () => void; + reset: () => void; + oldLinkRef: React.RefObject; + newLinkRef: React.RefObject; +} + +const VersionUpdateNotificationContext = createContext(undefined); + +export const VersionUpdateNotificationProvider = ({ + version, + children + }: { + version: LanguageVersion; + children: React.ReactNode; +}) => { + const storageKey = `versionUpdateNotificationDismissed-${version}`; + const [isDismissed, setIsDismissed] = useState(false); + + const oldLinkRef = useRef(null); + const newLinkRef = useRef(null); + + useEffect(() => { + const storedValue = localStorage.getItem(storageKey); + setIsDismissed(storedValue === "true"); + }, [version]); + + const dismiss = () => { + localStorage.setItem(storageKey, "true"); + setIsDismissed(true); + }; + + const reset = () => { + localStorage.removeItem(storageKey); + setIsDismissed(false); + }; + + return ( + + {children} + + ); +}; + +export const useVersionUpdateNotification = () => { + const context = useContext(VersionUpdateNotificationContext); + if (!context) { + throw new Error("useVersionUpdateNotification must be used within VersionUpdateNotificationProvider"); + } + return context; +}; \ No newline at end of file diff --git a/src/components/version-language-switcher/version-language-switcher.css b/src/components/version-language-switcher/version-language-switcher.css index 43b4209b7..90615431b 100644 --- a/src/components/version-language-switcher/version-language-switcher.css +++ b/src/components/version-language-switcher/version-language-switcher.css @@ -28,4 +28,15 @@ margin-top: 4px; display: flex; /* if needed to align items horizontally */ align-items: center; /* vertically align content */ +} + +@media (max-width: 623px) { + [slot="version"] { + display: flex; /* if needed to align items horizontally */ + flex-direction: column; + align-items: flex-start; + gap: 2px; + margin-top: 0; + + } } \ No newline at end of file diff --git a/src/contexts/LanguageVersionContext.tsx b/src/contexts/LanguageVersionContext.tsx index 212edbf4f..6efeaf7fc 100644 --- a/src/contexts/LanguageVersionContext.tsx +++ b/src/contexts/LanguageVersionContext.tsx @@ -7,7 +7,7 @@ import { } from "@components/version-language-switcher/version-language-constants.ts"; import { DEFAULT_LANGUAGE, DEFAULT_VERSION } from "../global-constants"; -interface LanguageVersionContextProps { +export interface LanguageVersionContextProps { language: Language; version: LanguageVersion; setLanguage: (lang: Language) => void; diff --git a/src/contexts/SiteWideNotificationContext.tsx b/src/contexts/SiteWideNotificationContext.tsx new file mode 100644 index 000000000..ff6ac6c7e --- /dev/null +++ b/src/contexts/SiteWideNotificationContext.tsx @@ -0,0 +1,39 @@ +import { createContext, useContext, useState } from "react"; + +interface SiteWideNotificationContextType { + isDismissed: boolean; + dismiss: () => void; + reset: () => void; +} + +const SiteWideNotificationContext = createContext(undefined); + +export const SiteWideNotificationProvider = ({ children }: { children: React.ReactNode }) => { + const [isDismissed, setIsDismissed] = useState(() => { + const stored = localStorage.getItem("siteWideDismissed"); + return stored === "true"; + }); + const dismiss = () => { + localStorage.setItem("siteWideDismissed", "true"); + setIsDismissed(true); + }; + + const reset = () => { + localStorage.removeItem("siteWideDismissed"); + setIsDismissed(false); + }; + + return ( + + {children} + + ); +}; + +export const useSiteWideNotification = () => { + const context = useContext(SiteWideNotificationContext); + if (!context) { + throw new Error("useSiteWideNotification must be used within SiteWideNotificationProvider"); + } + return context; +}; \ No newline at end of file diff --git a/src/examples/accordion/AccordionExamples.tsx b/src/examples/accordion/AccordionExamples.tsx index bf65cd1d6..a861ff3e6 100644 --- a/src/examples/accordion/AccordionExamples.tsx +++ b/src/examples/accordion/AccordionExamples.tsx @@ -1,7 +1,6 @@ -import "./accordion-example.css"; -import { AccordionExpandOrCollapseExample } from "@examples/accordion/AccordionExpandOrCollapseExample.tsx"; -import { AccordionHideOrShowSectionExample } from "@examples/accordion/AccordionHideOrShowSectionExample.tsx"; +import { HideAndShowManySectionsOfInformation } from "@examples/hide-and-show-many-sections-of-information.tsx"; import { SandboxHeader } from "@components/sandbox/sandbox-header/sandboxHeader.tsx"; +import ExpandOrCollapsePartOfAForm from "@examples/expand-or-collapse-part-of-a-form.tsx"; export default function AccordionExamples() { return ( @@ -10,13 +9,13 @@ export default function AccordionExamples() { exampleTitle="Expand or collapse part of a form" figmaExample="https://www.figma.com/design/aIRjvBzpIUH0GbkffjbL04/%E2%9D%96-Patterns-library-%7C-DDD?node-id=6302-491810&t=X0IQW5flDDaj8Vyg-4"> - + - + ); } diff --git a/src/examples/filter-chip/FilterChipInteractiveExample.tsx b/src/examples/add-a-filter-chip.tsx similarity index 98% rename from src/examples/filter-chip/FilterChipInteractiveExample.tsx rename to src/examples/add-a-filter-chip.tsx index 88adcf008..b28cf82ab 100644 --- a/src/examples/filter-chip/FilterChipInteractiveExample.tsx +++ b/src/examples/add-a-filter-chip.tsx @@ -4,7 +4,7 @@ import { CodeSnippet } from "@components/code-snippet/CodeSnippet.tsx"; import { useContext, useState } from "react"; import { LanguageVersionContext } from "@contexts/LanguageVersionContext.tsx"; -export const FilterChipInteractiveExample = () => { +export const AddAFilterChip = () => { const {version} = useContext(LanguageVersionContext); const [activeFilters, setActiveFilters] = useState([]); const addFilter = () => { @@ -169,3 +169,5 @@ export const FilterChipInteractiveExample = () => { ) } + +export default AddAFilterChip; diff --git a/src/examples/drawer/DrawerAddRecordExample.tsx b/src/examples/add-a-record-using-a-drawer.tsx similarity index 99% rename from src/examples/drawer/DrawerAddRecordExample.tsx rename to src/examples/add-a-record-using-a-drawer.tsx index 51d9df313..c26d812dc 100644 --- a/src/examples/drawer/DrawerAddRecordExample.tsx +++ b/src/examples/add-a-record-using-a-drawer.tsx @@ -9,7 +9,7 @@ import { import { useState } from "react"; import { CodeSnippet } from "@components/code-snippet/CodeSnippet.tsx"; -export const DrawerAddRecordExample = () => { +export const AddARecordUsingADrawer = () => { const [open, setOpen] = useState(false); const noop = () => {/* do something */} return ( @@ -265,3 +265,5 @@ export const DrawerAddRecordExample = () => { ); }; + +export default AddARecordUsingADrawer; diff --git a/src/examples/drawer/DrawerFiltersExample.tsx b/src/examples/add-and-edit-lots-of-filters.tsx similarity index 99% rename from src/examples/drawer/DrawerFiltersExample.tsx rename to src/examples/add-and-edit-lots-of-filters.tsx index b5e618a63..89c0a69e6 100644 --- a/src/examples/drawer/DrawerFiltersExample.tsx +++ b/src/examples/add-and-edit-lots-of-filters.tsx @@ -12,7 +12,7 @@ import { import { useState } from "react"; import { CodeSnippet } from "@components/code-snippet/CodeSnippet.tsx"; -export const DrawerFiltersExample = () => { +export const AddAndEditLotsOfFilters = () => { const [open, setOpen] = useState(false); // const noop = () => {/* do something */}; return ( @@ -229,3 +229,5 @@ export const DrawerFiltersExample = () => { ); }; + +export default AddAndEditLotsOfFilters; diff --git a/src/examples/modal/ModalAddAnotherItemExample.tsx b/src/examples/add-another-item-in-a-modal.tsx similarity index 99% rename from src/examples/modal/ModalAddAnotherItemExample.tsx rename to src/examples/add-another-item-in-a-modal.tsx index 38b85208c..e5f0b110e 100644 --- a/src/examples/modal/ModalAddAnotherItemExample.tsx +++ b/src/examples/add-another-item-in-a-modal.tsx @@ -11,7 +11,7 @@ import { useContext, useState } from "react"; import { LanguageVersionContext } from "@contexts/LanguageVersionContext.tsx"; import { GoabDropdownOnChangeDetail, GoabTextAreaOnChangeDetail } from "@abgov/ui-components-common"; -export const ModalAddAnotherItemExample = () => { +export const AddAnotherItemInAModal = () => { const {version} = useContext(LanguageVersionContext); const [addItemModalOpen, setAddItemModalOpen] = useState(); const [type, setType] = useState(); @@ -329,3 +329,5 @@ export const ModalAddAnotherItemExample = () => { ) } + +export default AddAnotherItemInAModal; diff --git a/src/examples/app-footer/AppFooterExamples.tsx b/src/examples/app-footer/AppFooterExamples.tsx index dabf9710c..4201429b1 100644 --- a/src/examples/app-footer/AppFooterExamples.tsx +++ b/src/examples/app-footer/AppFooterExamples.tsx @@ -1,5 +1,5 @@ -import { AppFooterShowQuickLinkExample } from "@examples/app-footer/AppFooterShowQuickLinkExample.tsx"; -import { AppFooterShowNavigationItemsExample } from "@examples/app-footer/AppFooterShowNavigationItemsExample.tsx"; +import { ShowQuickLinks } from "@examples/show-quick-links.tsx"; +import { ShowLinksToNavigationItems } from "@examples/show-links-to-navigation-items.tsx"; import { SandboxHeader } from "@components/sandbox/sandbox-header/sandboxHeader.tsx"; export const AppFooterExamples = () => { @@ -9,13 +9,13 @@ export const AppFooterExamples = () => { exampleTitle="Show quick links" figmaExample="https://www.figma.com/design/aIRjvBzpIUH0GbkffjbL04/%E2%9D%96-Patterns-library-%7C-DDD?node-id=6309-60928&t=X0IQW5flDDaj8Vyg-4"> - + - + ) } diff --git a/src/examples/app-header/AppHeaderExamples.tsx b/src/examples/app-header/AppHeaderExamples.tsx index c343e4630..160267ff8 100644 --- a/src/examples/app-header/AppHeaderExamples.tsx +++ b/src/examples/app-header/AppHeaderExamples.tsx @@ -1,5 +1,5 @@ -import { AppHeaderWithNavigationExample } from "@examples/app-header/AppHeaderWithNavigationExample.tsx"; -import { AppHeaderWithMenuClickEventExample } from "@examples/app-header/AppHeaderWithMenuClickEventExample.tsx"; +import { HeaderWithNavigation } from "@examples/header-with-navigation.tsx"; +import { HeaderWithMenuClickEvent } from "@examples/header-with-menu-click-event.tsx"; import { SandboxHeader } from "@components/sandbox/sandbox-header/sandboxHeader.tsx"; export const AppHeaderExamples = () => { @@ -9,13 +9,13 @@ export const AppHeaderExamples = () => { exampleTitle="Header with navigation" figmaExample="https://www.figma.com/design/aIRjvBzpIUH0GbkffjbL04/%E2%9D%96-Patterns-library-%7C-DDD?node-id=6309-90004&t=X0IQW5flDDaj8Vyg-4"> - + - + ); }; diff --git a/src/examples/ask-a-long-answer-question-with-a-maximum-word-count.tsx b/src/examples/ask-a-long-answer-question-with-a-maximum-word-count.tsx new file mode 100644 index 000000000..cbf4e2b52 --- /dev/null +++ b/src/examples/ask-a-long-answer-question-with-a-maximum-word-count.tsx @@ -0,0 +1,23 @@ +import { Sandbox } from "@components/sandbox"; +import { + GoabFormItem, + GoabTextarea +} from "@abgov/react-components"; + +export const AskALongAnswerQuestionWithAMaximumWordCount = () => { + const noop = () => { + }; + return ( + + + + + + + + ); +}; + +export default AskALongAnswerQuestionWithAMaximumWordCount; \ No newline at end of file diff --git a/src/examples/text-field/TextFieldAskBirthdayExample.tsx b/src/examples/ask-a-user-for-a-birthday.tsx similarity index 98% rename from src/examples/text-field/TextFieldAskBirthdayExample.tsx rename to src/examples/ask-a-user-for-a-birthday.tsx index a12651a81..cd47bcec0 100644 --- a/src/examples/text-field/TextFieldAskBirthdayExample.tsx +++ b/src/examples/ask-a-user-for-a-birthday.tsx @@ -5,7 +5,7 @@ import { useContext } from "react"; import { LanguageVersionContext } from "@contexts/LanguageVersionContext.tsx"; -export const TextFieldAskBirthdayExample = () => { +export const AskAUserForABirthday = () => { const {version} = useContext(LanguageVersionContext); const noop = () => {} @@ -125,3 +125,5 @@ export const TextFieldAskBirthdayExample = () => { ) } + +export default AskAUserForABirthday; diff --git a/src/examples/button/ButtonAskUserAddressExample.tsx b/src/examples/ask-a-user-for-an-address.tsx similarity index 98% rename from src/examples/button/ButtonAskUserAddressExample.tsx rename to src/examples/ask-a-user-for-an-address.tsx index b8c4f432c..0cc890cb4 100644 --- a/src/examples/button/ButtonAskUserAddressExample.tsx +++ b/src/examples/ask-a-user-for-an-address.tsx @@ -12,7 +12,7 @@ import { import { LanguageVersionContext } from "@contexts/LanguageVersionContext.tsx"; import { useContext } from "react"; -export const ButtonAskUserAddressExample = () => { +export const AskAUserForAnAddress = () => { const {version} = useContext(LanguageVersionContext); const noop = () => {} return ( @@ -136,3 +136,5 @@ export const ButtonAskUserAddressExample = () => { ); }; + +export default AskAUserForAnAddress; diff --git a/src/examples/text-field/TextFieldAskUserIndianRegistrationExample.tsx b/src/examples/ask-a-user-for-an-indian-registration-number.tsx similarity index 97% rename from src/examples/text-field/TextFieldAskUserIndianRegistrationExample.tsx rename to src/examples/ask-a-user-for-an-indian-registration-number.tsx index 74292c1b0..b44d08336 100644 --- a/src/examples/text-field/TextFieldAskUserIndianRegistrationExample.tsx +++ b/src/examples/ask-a-user-for-an-indian-registration-number.tsx @@ -4,7 +4,7 @@ import { useContext } from "react"; import { LanguageVersionContext } from "@contexts/LanguageVersionContext.tsx"; import { CodeSnippet } from "@components/code-snippet/CodeSnippet.tsx"; -export const TextFieldAskUserIndianRegistrationExample = () => { +export const AskAUserForAnIndianRegistrationNumber = () => { const {version} = useContext(LanguageVersionContext); const noop = () => {} @@ -140,3 +140,5 @@ export const TextFieldAskUserIndianRegistrationExample = () => { ) } + +export default AskAUserForAnIndianRegistrationNumber; diff --git a/src/examples/details/DetailsShowDirectDepositInformationExample.tsx b/src/examples/ask-a-user-for-direct-deposit-information.tsx similarity index 98% rename from src/examples/details/DetailsShowDirectDepositInformationExample.tsx rename to src/examples/ask-a-user-for-direct-deposit-information.tsx index 7bc5af659..0faf09f91 100644 --- a/src/examples/details/DetailsShowDirectDepositInformationExample.tsx +++ b/src/examples/ask-a-user-for-direct-deposit-information.tsx @@ -4,7 +4,7 @@ import { useContext } from "react"; import { LanguageVersionContext } from "@contexts/LanguageVersionContext.tsx"; import { CodeSnippet } from "@components/code-snippet/CodeSnippet.tsx"; -export const DetailsShowDirectDepositInformationExample = () => { +export const AskAUserForDirectDepositInformation = () => { const {version} = useContext(LanguageVersionContext); const noop = () => {}; @@ -149,3 +149,5 @@ export const DetailsShowDirectDepositInformationExample = () => { ); }; + +export default AskAUserForDirectDepositInformation; diff --git a/src/examples/text-field/TextFieldAskUserAmountExample.tsx b/src/examples/ask-a-user-for-dollar-amounts.tsx similarity index 99% rename from src/examples/text-field/TextFieldAskUserAmountExample.tsx rename to src/examples/ask-a-user-for-dollar-amounts.tsx index 75708251f..1e0097d52 100644 --- a/src/examples/text-field/TextFieldAskUserAmountExample.tsx +++ b/src/examples/ask-a-user-for-dollar-amounts.tsx @@ -4,7 +4,7 @@ import { GoabFormItem, GoabInput } from "@abgov/react-components"; import { useContext } from "react"; import { LanguageVersionContext } from "@contexts/LanguageVersionContext.tsx"; -export const TextFieldAskUserAmountExample = () => { +export const AskAUserForDollarAmounts = () => { const {version} = useContext(LanguageVersionContext); const noop = () => {} @@ -210,3 +210,5 @@ export const TextFieldAskUserAmountExample = () => { ) } + +export default AskAUserForDollarAmounts; diff --git a/src/examples/ask-a-user-one-question-at-a-time.tsx b/src/examples/ask-a-user-one-question-at-a-time.tsx new file mode 100644 index 000000000..c269c3a5a --- /dev/null +++ b/src/examples/ask-a-user-one-question-at-a-time.tsx @@ -0,0 +1,66 @@ +import { Sandbox } from "@components/sandbox"; +import "./question-page/question-page-examples.css"; +import { CodeSnippet } from "@components/code-snippet/CodeSnippet.tsx"; +import { + GoabButton, + GoabFormItem, + GoabRadioGroup, + GoabRadioItem +} from "@abgov/react-components"; +import { LanguageVersionContext } from "@contexts/LanguageVersionContext.tsx"; +import { useContext } from "react"; + +export default function AskAUserOneQuestionAtATime() { + useContext(LanguageVersionContext); + return ( +
+ + {/*CSS Code Snippet*/} + ') 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); + } + `} + /> + + + Back + + + { + }}> + + + No + + + + + Save and continue + + + +
+ ); +} diff --git a/src/examples/badge/BadgeExamples.tsx b/src/examples/badge/BadgeExamples.tsx index d8b515eab..1743ff880 100644 --- a/src/examples/badge/BadgeExamples.tsx +++ b/src/examples/badge/BadgeExamples.tsx @@ -3,8 +3,8 @@ import { GoabBlock, } from "@abgov/react-components"; import { Sandbox } from "@components/sandbox"; -import { BadgeShowStatusInTableExample } from "@examples/badge/BadgeShowStatusInTableExample.tsx"; -import { BadgeShowStatusOnCardExample } from "@examples/badge/BadgeShowStatusOnCardExample.tsx"; +import { ShowStatusInATable } from "@examples/show-status-in-a-table.tsx"; +import { ShowStatusOnACard } from "@examples/show-status-on-a-card.tsx"; import { SandboxHeader } from "@components/sandbox/sandbox-header/sandboxHeader.tsx"; export default function BadgeExamples() { @@ -15,7 +15,7 @@ export default function BadgeExamples() { exampleTitle="Show status in a table" figmaExample="https://www.figma.com/design/aIRjvBzpIUH0GbkffjbL04/%E2%9D%96-Patterns-library-%7C-DDD?node-id=6304-22364&t=X0IQW5flDDaj8Vyg-4"> - + - + ); } diff --git a/src/routes/patterns/LayoutPage.tsx b/src/examples/basic-page-layout.tsx similarity index 66% rename from src/routes/patterns/LayoutPage.tsx rename to src/examples/basic-page-layout.tsx index edfa4022b..e6010b88e 100644 --- a/src/routes/patterns/LayoutPage.tsx +++ b/src/examples/basic-page-layout.tsx @@ -1,26 +1,17 @@ import {Sandbox} from "@components/sandbox"; -import Browser from "@components/browser/Browser"; -import { ComponentContent } from "@components/component-content/ComponentContent"; +import Browser from "@components/browser/Browser.tsx"; +import { ComponentContent } from "@components/component-content/ComponentContent.tsx"; import { GoabAppFooter, - GoabAppHeader, GoabBadge, GoabGrid, + GoabAppHeader, GoabGrid, GoabMicrositeHeader, GoabOneColumnLayout, - GoabPageBlock, GoabSkeleton, - GoabTab, - GoabTabs + GoabPageBlock, GoabSkeleton } from "@abgov/react-components"; -export default function LayoutPage() { +export const BasicPageLayout = () => { return ( -

Layout

-

- A structural template that supports consistency across applications by defining visual grids, spacing, and sections. -

- - -

Basic page layout

@@ -50,16 +41,8 @@ export default function LayoutPage() { -
- - - Design guidelines - - - }> -
); } + +export default BasicPageLayout; diff --git a/src/examples/button/ButtonConfirmDestructiveActionExample.tsx b/src/examples/button/ButtonConfirmDestructiveActionExample.tsx deleted file mode 100644 index 8446c5204..000000000 --- a/src/examples/button/ButtonConfirmDestructiveActionExample.tsx +++ /dev/null @@ -1,7 +0,0 @@ -import { ModalConfirmDestructiveActionExample } from "@examples/modal/ModalConfirmDestructiveActionExample.tsx"; - -export const ButtonConfirmDestructiveActionExample = () => { - return ( - - ); -}; diff --git a/src/examples/button/ButtonExamples.tsx b/src/examples/button/ButtonExamples.tsx index 93b1c880c..484468bc7 100644 --- a/src/examples/button/ButtonExamples.tsx +++ b/src/examples/button/ButtonExamples.tsx @@ -1,6 +1,6 @@ -import { ButtonAskUserAddressExample } from "@examples/button/ButtonAskUserAddressExample.tsx"; -import { ButtonConfirmDestructiveActionExample } from "@examples/button/ButtonConfirmDestructiveActionExample.tsx"; -import { ButtonDisabledWithRequiredFieldExample } from "@examples/button/ButtonDisabledWithRequiredFieldExample.tsx"; +import { AskAUserForAnAddress } from "@examples/ask-a-user-for-an-address.tsx"; +import { ConfirmADestructiveAction } from "@examples/confirm-a-destructive-action.tsx"; +import { DisabledButtonWithARequiredField } from "@examples/disabled-button-with-a-required-field.tsx"; import { SandboxHeader } from "@components/sandbox/sandbox-header/sandboxHeader.tsx"; export const ButtonExamples = () => { @@ -11,20 +11,20 @@ export const ButtonExamples = () => { exampleTitle="Ask a user for an address" figmaExample="https://www.figma.com/design/aIRjvBzpIUH0GbkffjbL04/%E2%9D%96-Patterns-library-%7C-DDD?node-id=6304-43250&t=X0IQW5flDDaj8Vyg-4"> - + {/*Button example 2*/} - + {/*Button example */} - + ; }; diff --git a/src/examples/callout/CalloutExamples.tsx b/src/examples/callout/CalloutExamples.tsx index 70fc9b1cc..e68e49eb3 100644 --- a/src/examples/callout/CalloutExamples.tsx +++ b/src/examples/callout/CalloutExamples.tsx @@ -1,146 +1,16 @@ -import { Sandbox } from "@components/sandbox"; -import { CodeSnippet } from "@components/code-snippet/CodeSnippet.tsx"; -import { GoabButton, GoabButtonGroup, GoabCallout, GoabSpacer } from "@abgov/react-components"; -import { useContext } from "react"; -import { LanguageVersionContext } from "@contexts/LanguageVersionContext.tsx"; import { SandboxHeader } from "@components/sandbox/sandbox-header/sandboxHeader.tsx"; +import { ConfirmThatAnApplicationWasSubmitted } from "@examples/confirm-that-an-application-was-submitted.tsx"; export const CalloutExamples = () => { - const {version} = useContext(LanguageVersionContext); - return ( - <> - - - - {/*Angular code*/} - {version === "old" && You have completed the application - - Your application was successful -

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 - - `} - />} - - {version === "new" && 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 - - `} - />} - - {/*React code*/} - {version === "old" && 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 - - `} - />} - - {version === "new" && 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 - - `} - />} - -

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 - -
- - ) -} + return <> + {/*Callout Example 1*/} + + + + + {/*Callout example 2*/} + ; +}; diff --git a/src/examples/container/ContainerCardGridExample.tsx b/src/examples/card-grid.tsx similarity index 96% rename from src/examples/container/ContainerCardGridExample.tsx rename to src/examples/card-grid.tsx index ec7b8cd78..f767f44f5 100644 --- a/src/examples/container/ContainerCardGridExample.tsx +++ b/src/examples/card-grid.tsx @@ -1,9 +1,9 @@ -import "./container-card-grid-example.css"; +import "./container/container-card-grid-example.css"; import { CodeSnippet } from "@components/code-snippet/CodeSnippet.tsx"; import { GoabContainer, GoabGrid } from "@abgov/react-components"; import { Sandbox } from "@components/sandbox"; -export const ContainerCardGridExample = () => { +export const CardGrid = () => { return ( { ) } + +export default CardGrid; diff --git a/src/examples/container/ContainerCaseFilesExample.tsx b/src/examples/card-view-of-case-files.tsx similarity index 96% rename from src/examples/container/ContainerCaseFilesExample.tsx rename to src/examples/card-view-of-case-files.tsx index 977da0199..55bb7f6d3 100644 --- a/src/examples/container/ContainerCaseFilesExample.tsx +++ b/src/examples/card-view-of-case-files.tsx @@ -1,9 +1,9 @@ -import "./container-case-files-example.css"; +import "./container/container-case-files-example.css"; import { CodeSnippet } from "@components/code-snippet/CodeSnippet.tsx"; import { GoabBadge, GoabBlock, GoabButton, GoabContainer } from "@abgov/react-components"; import { Sandbox } from "@components/sandbox"; -export const ContainerCaseFilesExample = () => { +export const CardViewOfCaseFiles = () => { return ( { ) } + +export default CardViewOfCaseFiles; diff --git a/src/examples/checkbox/CheckboxExamples.tsx b/src/examples/checkbox/CheckboxExamples.tsx index 95d01c59e..925016662 100644 --- a/src/examples/checkbox/CheckboxExamples.tsx +++ b/src/examples/checkbox/CheckboxExamples.tsx @@ -1,5 +1,6 @@ -import CheckboxDescriptionExample from "@examples/checkbox/CheckboxDescriptionExample.tsx"; -import CheckboxNoneOrManyExample from "@examples/checkbox/CheckboxNoneOrManyExample.tsx"; +import IncludeDescriptionsForItemsInACheckboxList + from "@examples/include-descriptions-for-items-in-a-checkbox-list.tsx"; +import SelectOneOrMoreFromAListOfOptions from "@examples/select-one-or-more-from-a-list-of-options.tsx"; import { CheckboxRevealSlotExample } from "@examples/checkbox/CheckboxRevealSlotExample.tsx"; import { SandboxHeader } from "@components/sandbox/sandbox-header/sandboxHeader.tsx"; @@ -10,19 +11,20 @@ export const CheckboxExamples = () => { exampleTitle="Include descriptions for items in a checkbox list" figmaExample="https://www.figma.com/design/aIRjvBzpIUH0GbkffjbL04/%E2%9D%96-Patterns-library-%7C-DDD?node-id=6307-131778&t=X0IQW5flDDaj8Vyg-4"> - + {/*Checkbox example 2*/} - + + {/*Checkbox example 3 - NEW from alpha*/} - + ; -} +} \ No newline at end of file diff --git a/src/examples/notification/NotificationServiceOutageExample.tsx b/src/examples/communicate-a-future-service-outage.tsx similarity index 96% rename from src/examples/notification/NotificationServiceOutageExample.tsx rename to src/examples/communicate-a-future-service-outage.tsx index 495947814..4fab70607 100644 --- a/src/examples/notification/NotificationServiceOutageExample.tsx +++ b/src/examples/communicate-a-future-service-outage.tsx @@ -4,7 +4,7 @@ import { GoabNotification } from "@abgov/react-components"; import { useContext } from "react"; import { LanguageVersionContext } from "@contexts/LanguageVersionContext.tsx"; -export const NotificationServiceOutageExample = () => { +export const CommunicateAFutureServiceOutage = () => { const {version} = useContext(LanguageVersionContext); return ( <> @@ -64,3 +64,5 @@ export const NotificationServiceOutageExample = () => { ) } + +export default CommunicateAFutureServiceOutage; diff --git a/src/examples/modal/ModalConfirmRecordChangeExample.tsx b/src/examples/confirm-a-change.tsx similarity index 99% rename from src/examples/modal/ModalConfirmRecordChangeExample.tsx rename to src/examples/confirm-a-change.tsx index edac7aeb1..1310df5cc 100644 --- a/src/examples/modal/ModalConfirmRecordChangeExample.tsx +++ b/src/examples/confirm-a-change.tsx @@ -11,7 +11,7 @@ import { useContext, useState } from "react"; import { LanguageVersionContext } from "@contexts/LanguageVersionContext.tsx"; import { GoabDatePickerOnChangeDetail } from "@abgov/ui-components-common"; -export const ModalConfirmRecordChangeExample = () => { +export const ConfirmAChange = () => { const {version} = useContext(LanguageVersionContext); const [inputModalOpen, setInputModalOpen] = useState(); const [effectiveDate, setEffectiveDate] = useState(new Date()); @@ -298,3 +298,5 @@ export const ModalConfirmRecordChangeExample = () => { ) } + +export default ConfirmAChange; diff --git a/src/examples/modal/ModalConfirmDestructiveActionExample.tsx b/src/examples/confirm-a-destructive-action.tsx similarity index 98% rename from src/examples/modal/ModalConfirmDestructiveActionExample.tsx rename to src/examples/confirm-a-destructive-action.tsx index c275e25e6..1d49f02ef 100644 --- a/src/examples/modal/ModalConfirmDestructiveActionExample.tsx +++ b/src/examples/confirm-a-destructive-action.tsx @@ -4,7 +4,7 @@ import { Sandbox } from "@components/sandbox"; import { useContext, useState } from "react"; import { LanguageVersionContext } from "@contexts/LanguageVersionContext.tsx"; -export const ModalConfirmDestructiveActionExample = () => { +export const ConfirmADestructiveAction = () => { const {version} = useContext(LanguageVersionContext); const [destructiveModalOpen, setDestructiveModalOpen] = useState(); return ( @@ -159,3 +159,5 @@ export const ModalConfirmDestructiveActionExample = () => { ) } + +export default ConfirmADestructiveAction; diff --git a/src/examples/modal/ModalRouteChangeExample.tsx b/src/examples/confirm-before-navigating-away.tsx similarity index 98% rename from src/examples/modal/ModalRouteChangeExample.tsx rename to src/examples/confirm-before-navigating-away.tsx index 9296863be..726f1838c 100644 --- a/src/examples/modal/ModalRouteChangeExample.tsx +++ b/src/examples/confirm-before-navigating-away.tsx @@ -5,7 +5,7 @@ import { useContext, useState } from "react"; import { LanguageVersionContext } from "@contexts/LanguageVersionContext.tsx"; import { useNavigate } from "react-router-dom"; -export const ModalRouteChangeExample = () => { +export const ConfirmBeforeNavigatingAway = () => { const {version} = useContext(LanguageVersionContext); const [onRouteChangeModalOpen, setOnRouteChangeModalOpen] = useState(); const navigate = useNavigate(); @@ -170,3 +170,5 @@ export const ModalRouteChangeExample = () => { ) } + +export default ConfirmBeforeNavigatingAway; diff --git a/src/examples/confirm-that-an-application-was-submitted.tsx b/src/examples/confirm-that-an-application-was-submitted.tsx new file mode 100644 index 000000000..3d1c0eb74 --- /dev/null +++ b/src/examples/confirm-that-an-application-was-submitted.tsx @@ -0,0 +1,145 @@ +import { Sandbox } from "@components/sandbox"; +import { CodeSnippet } from "@components/code-snippet/CodeSnippet.tsx"; +import { GoabButton, GoabButtonGroup, GoabCallout, GoabSpacer } from "@abgov/react-components"; +import { useContext } from "react"; +import { LanguageVersionContext } from "@contexts/LanguageVersionContext.tsx"; + +export const ConfirmThatAnApplicationWasSubmitted = () => { + const { version } = useContext(LanguageVersionContext); + return ( + <> + + + {/*Angular code*/} + {version === "old" && You have completed the application + + + Your application was successful +

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 + + `} + />} + + {version === "new" && 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 + + `} + />} + + {/*React code*/} + {version === "old" && 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 + + `} + />} + + {version === "new" && 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 + + `} + />} + +

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 + +
+ + ); + +}; + +export default ConfirmThatAnApplicationWasSubmitted; diff --git a/src/examples/container/ContainerExamples.tsx b/src/examples/container/ContainerExamples.tsx index 5e3bb9618..627c1ed32 100644 --- a/src/examples/container/ContainerExamples.tsx +++ b/src/examples/container/ContainerExamples.tsx @@ -1,7 +1,7 @@ -import { ContainerUserInformationExample } from "@examples/container/ContainerUserInformationExample.tsx"; -import { ContainerCaseFilesExample } from "@examples/container/ContainerCaseFilesExample.tsx"; -import { ContainerCardGridExample } from "@examples/container/ContainerCardGridExample.tsx"; -import { ContainerReviewActionExample } from "@examples/container/ContainerReviewActionExample.tsx"; +import { DisplayUserInformation } from "@examples/display-user-information.tsx"; +import { CardViewOfCaseFiles } from "@examples/card-view-of-case-files.tsx"; +import { CardGrid } from "@examples/card-grid.tsx"; +import { ReviewAndAction } from "@examples/review-and-action.tsx"; import { SandboxHeader } from "@components/sandbox/sandbox-header/sandboxHeader.tsx"; export default function ContainerExamples() { @@ -13,26 +13,26 @@ export default function ContainerExamples() { exampleTitle="User information" figmaExample="https://www.figma.com/design/aIRjvBzpIUH0GbkffjbL04/%E2%9D%96-Patterns-library-%7C-DDD?node-id=6307-154067&t=X0IQW5flDDaj8Vyg-4"> - + - + - + - + ); } diff --git a/src/examples/tooltip/TooltipClickCopyToClipboardExample.tsx b/src/examples/copy-to-clipboard.tsx similarity index 97% rename from src/examples/tooltip/TooltipClickCopyToClipboardExample.tsx rename to src/examples/copy-to-clipboard.tsx index 6357f3cf9..56b49da82 100644 --- a/src/examples/tooltip/TooltipClickCopyToClipboardExample.tsx +++ b/src/examples/copy-to-clipboard.tsx @@ -1,11 +1,11 @@ import { Sandbox } from "@components/sandbox"; import { CodeSnippet } from "@components/code-snippet/CodeSnippet.tsx"; import { GoabBlock, GoabIconButton, GoabTooltip } from "@abgov/react-components"; -import { getCssVarValue } from "src/utils/styling.ts"; +import { getCssVarValue } from "../utils/styling.ts"; import { useContext, useState } from "react"; import { LanguageVersionContext } from "@contexts/LanguageVersionContext.tsx"; -export const TooltipClickCopyToClipboardExample = () => { +export const CopyToClipboard = () => { const {version} = useContext(LanguageVersionContext); const [isCopied, setIsCopied] = useState(false); @@ -150,3 +150,5 @@ export const TooltipClickCopyToClipboardExample = () => { ) } + +export default CopyToClipboard; diff --git a/src/examples/date-picker/DatePickerExamples.tsx b/src/examples/date-picker/DatePickerExamples.tsx index 90dee0aa4..12e61da93 100644 --- a/src/examples/date-picker/DatePickerExamples.tsx +++ b/src/examples/date-picker/DatePickerExamples.tsx @@ -1,4 +1,4 @@ -import { DatePickerResetExample } from "@examples/date-picker/DatePickerResetExample.tsx"; +import { ResetDatePickerField } from "@examples/reset-date-picker-field.tsx"; import { SandboxHeader } from "@components/sandbox/sandbox-header/sandboxHeader.tsx"; export const DatePickerExamples = () => { @@ -8,7 +8,7 @@ export const DatePickerExamples = () => { exampleTitle="Reset example" figmaExample=""> - + ) } diff --git a/src/examples/details/DetailsExamples.tsx b/src/examples/details/DetailsExamples.tsx index 2f10f98c6..ed1a125dd 100644 --- a/src/examples/details/DetailsExamples.tsx +++ b/src/examples/details/DetailsExamples.tsx @@ -1,13 +1,12 @@ import { - DetailsMoreInformationBasicQuestionExample -} from "@examples/details/DetailsMoreInformationBasicQuestionExample.tsx"; + ShowAListToHelpAnswerAQuestion +} from "@examples/show-a-list-to-help-answer-a-question.tsx"; import { - DetailsAdditionalInformationHelpUserExample -} from "@examples/details/DetailsAdditionalInformationHelpUserExample.tsx"; -import { - DetailsShowDirectDepositInformationExample -} from "@examples/details/DetailsShowDirectDepositInformationExample.tsx"; + AskAUserForDirectDepositInformation +} from "@examples/ask-a-user-for-direct-deposit-information.tsx"; import { SandboxHeader } from "@components/sandbox/sandbox-header/sandboxHeader.tsx"; +import RevealMoreInformationToHelpAnswerAQuestion + from "@examples/reveal-more-information-to-help-answer-a-question.tsx"; export const DetailsExamples = () => { return ( @@ -16,19 +15,19 @@ export const DetailsExamples = () => { exampleTitle="Show more information to help answer a question" figmaExample="https://www.figma.com/design/aIRjvBzpIUH0GbkffjbL04/%E2%9D%96-Patterns-library-%7C-DDD?node-id=6307-197360&t=X0IQW5flDDaj8Vyg-4"> - + - + - + ) } diff --git a/src/examples/details/DetailsMoreInformationBasicQuestionExample.tsx b/src/examples/details/DetailsMoreInformationBasicQuestionExample.tsx deleted file mode 100644 index e24e9ec90..000000000 --- a/src/examples/details/DetailsMoreInformationBasicQuestionExample.tsx +++ /dev/null @@ -1,53 +0,0 @@ -import { Sandbox } from "@components/sandbox"; -import { GoabDetails, GoabFormItem, GoabRadioGroup, GoabRadioItem } from "@abgov/react-components"; -import { useContext } from "react"; -import { LanguageVersionContext } from "@contexts/LanguageVersionContext.tsx"; -import { CodeSnippet } from "@components/code-snippet/CodeSnippet.tsx"; - -export const DetailsMoreInformationBasicQuestionExample = () => { - const {version} = useContext(LanguageVersionContext); - return ( - - - {/*Angular code*/} - {version === "new" && } - - {/*React code*/} - {version === "new" && { - console.log("value is ", event.value); - } - `} - />} - - - { }}> - - - - - - -

- This question helps us better understand your situation and ensure that you receive - the right information and support. -

-
-
- ) -} diff --git a/src/examples/button/ButtonDisabledWithRequiredFieldExample.tsx b/src/examples/disabled-button-with-a-required-field.tsx similarity index 96% rename from src/examples/button/ButtonDisabledWithRequiredFieldExample.tsx rename to src/examples/disabled-button-with-a-required-field.tsx index f0b2f0411..1500df3f4 100644 --- a/src/examples/button/ButtonDisabledWithRequiredFieldExample.tsx +++ b/src/examples/disabled-button-with-a-required-field.tsx @@ -5,7 +5,7 @@ import { LanguageVersionContext } from "@contexts/LanguageVersionContext.tsx"; import { GoabButtonGroup, GoabButton, GoabFormItem, GoabInput } from "@abgov/react-components"; -export const ButtonDisabledWithRequiredFieldExample = () => { +export const DisabledButtonWithARequiredField = () => { const { version } = useContext(LanguageVersionContext); const noop = () => {} return ( @@ -103,3 +103,5 @@ export const ButtonDisabledWithRequiredFieldExample = () => { ); }; + +export default DisabledButtonWithARequiredField; diff --git a/src/examples/container/ContainerUserInformationExample.tsx b/src/examples/display-user-information.tsx similarity index 98% rename from src/examples/container/ContainerUserInformationExample.tsx rename to src/examples/display-user-information.tsx index 85d395d44..908aa4967 100644 --- a/src/examples/container/ContainerUserInformationExample.tsx +++ b/src/examples/display-user-information.tsx @@ -1,11 +1,11 @@ -import "./container-user-information-example.css"; +import "./container/container-user-information-example.css"; import { Sandbox } from "@components/sandbox"; import { CodeSnippet } from "@components/code-snippet/CodeSnippet.tsx"; import { GoabBlock, GoabButton, GoabContainer, GoabTable } from "@abgov/react-components"; import { useContext } from "react"; import { LanguageVersionContext } from "@contexts/LanguageVersionContext.tsx"; -export const ContainerUserInformationExample = () => { +export const DisplayUserInformation = () => { const {version} = useContext(LanguageVersionContext); return ( @@ -365,3 +365,5 @@ export const ContainerUserInformationExample = () => { ) } + +export default DisplayUserInformation; diff --git a/src/examples/drawer/DrawerExamples.tsx b/src/examples/drawer/DrawerExamples.tsx index 8328f143f..14e7babb4 100644 --- a/src/examples/drawer/DrawerExamples.tsx +++ b/src/examples/drawer/DrawerExamples.tsx @@ -1,19 +1,19 @@ -import { DrawerFiltersExample } from "@examples/drawer/DrawerFiltersExample.tsx"; -import { DrawerAddRecordExample } from "@examples/drawer/DrawerAddRecordExample.tsx"; +import { AddAndEditLotsOfFilters } from "@examples/add-and-edit-lots-of-filters.tsx"; +import { AddARecordUsingADrawer } from "@examples/add-a-record-using-a-drawer.tsx"; import { SandboxHeader } from "@components/sandbox/sandbox-header/sandboxHeader.tsx"; export const DrawerExamples = () => { return ( <> + exampleTitle="Add and edit lots of filters"> - + - + ); }; diff --git a/src/examples/dropdown/DropdownExamples.tsx b/src/examples/dropdown/DropdownExamples.tsx index 3a1917343..b172aa191 100644 --- a/src/examples/dropdown/DropdownExamples.tsx +++ b/src/examples/dropdown/DropdownExamples.tsx @@ -1,5 +1,7 @@ -import { DropdownAddItemExample } from "@examples/dropdown/DropdownAddItemExample.tsx"; -import { DropdownChangeItemExample } from "@examples/dropdown/DropdownChangeItemExample.tsx"; +import { DynamicallyAddAnItemToADropdownList } from "@examples/dynamically-add-an-item-to-a-dropdown-list.tsx"; +import { + DynamicallyChangeItemsInADropdownList +} from "@examples/dynamically-change-items-in-a-dropdown-list.tsx"; import { SandboxHeader } from "@components/sandbox/sandbox-header/sandboxHeader.tsx"; export const DropdownExamples = () => { @@ -9,13 +11,13 @@ export const DropdownExamples = () => { exampleTitle="Dynamically add an item to a dropdown list" figmaExample=""> - + - + ); } diff --git a/src/examples/dropdown/DropdownAddItemExample.tsx b/src/examples/dynamically-add-an-item-to-a-dropdown-list.tsx similarity index 99% rename from src/examples/dropdown/DropdownAddItemExample.tsx rename to src/examples/dynamically-add-an-item-to-a-dropdown-list.tsx index 541ba23b3..a07ef32d7 100644 --- a/src/examples/dropdown/DropdownAddItemExample.tsx +++ b/src/examples/dynamically-add-an-item-to-a-dropdown-list.tsx @@ -26,7 +26,7 @@ type Task = { mount: GoabDropdownItemMountType; }; -export const DropdownAddItemExample = () => { +export const DynamicallyAddAnItemToADropdownList = () => { const { version } = useContext(LanguageVersionContext); const [taskError, setTaskError] = useState(false); const [newTask, setNewTask] = useState(""); @@ -620,3 +620,5 @@ export const DropdownAddItemExample = () => { ); }; + +export default DynamicallyAddAnItemToADropdownList; \ No newline at end of file diff --git a/src/examples/dropdown/DropdownChangeItemExample.tsx b/src/examples/dynamically-change-items-in-a-dropdown-list.tsx similarity index 98% rename from src/examples/dropdown/DropdownChangeItemExample.tsx rename to src/examples/dynamically-change-items-in-a-dropdown-list.tsx index 3f361dd5f..54e083901 100644 --- a/src/examples/dropdown/DropdownChangeItemExample.tsx +++ b/src/examples/dynamically-change-items-in-a-dropdown-list.tsx @@ -4,7 +4,7 @@ import { useContext, useState } from "react"; import { CodeSnippet } from "@components/code-snippet/CodeSnippet.tsx"; import { LanguageVersionContext } from "@contexts/LanguageVersionContext.tsx"; -export const DropdownChangeItemExample = () => { +export const DynamicallyChangeItemsInADropdownList = () => { const {version} = useContext(LanguageVersionContext); const [children, setChildren] = useState([]); const parents = ["All", "Big", "Small"]; @@ -250,3 +250,5 @@ export const DropdownChangeItemExample = () => { ); } + +export default DynamicallyChangeItemsInADropdownList; diff --git a/src/examples/accordion/AccordionExpandOrCollapseExample.tsx b/src/examples/expand-or-collapse-part-of-a-form.tsx similarity index 98% rename from src/examples/accordion/AccordionExpandOrCollapseExample.tsx rename to src/examples/expand-or-collapse-part-of-a-form.tsx index d0cfc96c7..d910a96e9 100644 --- a/src/examples/accordion/AccordionExpandOrCollapseExample.tsx +++ b/src/examples/expand-or-collapse-part-of-a-form.tsx @@ -4,7 +4,7 @@ import { GoabAccordion, GoabBadge } from "@abgov/react-components"; import { useContext } from "react"; import { LanguageVersionContext } from "@contexts/LanguageVersionContext.tsx"; -export const AccordionExpandOrCollapseExample = () => { +const ExpandOrCollapsePartOfAForm = () => { const {version} = useContext(LanguageVersionContext); return ( @@ -204,3 +204,6 @@ export const AccordionExpandOrCollapseExample = () => { ) } + + +export default ExpandOrCollapsePartOfAForm; diff --git a/src/examples/filter-chip/FilterChipExamples.tsx b/src/examples/filter-chip/FilterChipExamples.tsx index a144e2046..a13e1a3fc 100644 --- a/src/examples/filter-chip/FilterChipExamples.tsx +++ b/src/examples/filter-chip/FilterChipExamples.tsx @@ -1,7 +1,7 @@ -import { TableWithGlobalFiltersExample } from "@examples/filter-chip/TableWithGlobalFiltersExample.tsx"; -import { FilterChipDeleteEventExample } from "@examples/filter-chip/FilterChipDeleteEventExample.tsx"; -import { FilterChipInteractiveExample } from "@examples/filter-chip/FilterChipInteractiveExample.tsx"; -import { FilterChipTypedChipExample } from "@examples/filter-chip/FilterChipTypedChipExample.tsx"; +import { FilterDataInATable } from "@examples/filter-data-in-a-table.tsx"; +import { RemoveAFilter } from "@examples/remove-a-filter.tsx"; +import { AddAFilterChip } from "@examples/add-a-filter-chip.tsx"; +import { TypeToCreateANewFilter } from "@examples/type-to-create-a-new-filter.tsx"; import { SandboxHeader } from "@components/sandbox/sandbox-header/sandboxHeader.tsx"; export const FilterChipExamples = () => { @@ -11,13 +11,13 @@ export const FilterChipExamples = () => { exampleTitle="Remove a filter" figmaExample="https://www.figma.com/design/aIRjvBzpIUH0GbkffjbL04/%E2%9D%96-Patterns-library-%7C-DDD?node-id=6309-59262&t=X0IQW5flDDaj8Vyg-4"> - + - + { figmaExample="https://www.figma.com/design/aIRjvBzpIUH0GbkffjbL04/%E2%9D%96-Patterns-library-%7C-DDD?node-id=6308-51849&t=X0IQW5flDDaj8Vyg-4"> - + - + ) } diff --git a/src/examples/filter-chip/TableWithGlobalFiltersExample.tsx b/src/examples/filter-data-in-a-table.tsx similarity index 99% rename from src/examples/filter-chip/TableWithGlobalFiltersExample.tsx rename to src/examples/filter-data-in-a-table.tsx index 918f38c31..e683be1c9 100644 --- a/src/examples/filter-chip/TableWithGlobalFiltersExample.tsx +++ b/src/examples/filter-data-in-a-table.tsx @@ -18,7 +18,7 @@ import type { import { LanguageVersionContext } from "@contexts/LanguageVersionContext.tsx"; import { CodeSnippet } from "@components/code-snippet/CodeSnippet.tsx"; -export const TableWithGlobalFiltersExample = () => { +export const FilterDataInATable = () => { const { version } = useContext(LanguageVersionContext); const [typedChips, setTypedChips] = useState([]); @@ -912,3 +912,5 @@ export class TableComponent { // ); }; + +export default FilterDataInATable; \ No newline at end of file diff --git a/src/examples/form-item/FormItemExamples.tsx b/src/examples/form-item/FormItemExamples.tsx index a409a01d6..d4b9859a3 100644 --- a/src/examples/form-item/FormItemExamples.tsx +++ b/src/examples/form-item/FormItemExamples.tsx @@ -1,21 +1,21 @@ -import { FormItemSlottedHelperTextExample } from "@examples/form-item/FormItemSlottedHelperTextExample.tsx"; -import { FormItemSlottedErrorTextExample } from "@examples/form-item/FormItemSlottedErrorTextExample.tsx"; +import { SlottedHelperTextInAFormItem } from "@examples/slotted-helper-text-in-a-form-item.tsx"; +import { SlottedErrorTextInAFormItem } from "@examples/slotted-error-text-in-a-form-item.tsx"; import { SandboxHeader } from "@components/sandbox/sandbox-header/sandboxHeader.tsx"; export const FormItemExamples = () => { return ( <> - + - + ) } diff --git a/src/examples/form-stepper/FormStepperControlledNavigationExample.tsx b/src/examples/form-stepper-with-controlled-navigation.tsx similarity index 98% rename from src/examples/form-stepper/FormStepperControlledNavigationExample.tsx rename to src/examples/form-stepper-with-controlled-navigation.tsx index a700519e6..6c2fa8cde 100644 --- a/src/examples/form-stepper/FormStepperControlledNavigationExample.tsx +++ b/src/examples/form-stepper-with-controlled-navigation.tsx @@ -11,7 +11,7 @@ import { Sandbox } from "@components/sandbox"; import { useContext, useState } from "react"; import { LanguageVersionContext } from "@contexts/LanguageVersionContext.tsx"; -export const FormStepperControlledNavigationExample = () => { +export const FormStepperWithControlledNavigation = () => { const {version} = useContext(LanguageVersionContext); const [controlledStep, setControlledStep] = useState(1); @@ -219,3 +219,5 @@ To use the controlled type you must set a step value ≥ 1.`}> ) } + +export default FormStepperWithControlledNavigation; diff --git a/src/examples/form-stepper/FormStepperExamples.tsx b/src/examples/form-stepper/FormStepperExamples.tsx index 1cc2e0420..0444a56c0 100644 --- a/src/examples/form-stepper/FormStepperExamples.tsx +++ b/src/examples/form-stepper/FormStepperExamples.tsx @@ -1,7 +1,7 @@ import { - FormStepperControlledNavigationExample -} from "@examples/form-stepper/FormStepperControlledNavigationExample.tsx"; -import { FormStepperStepStatusExample } from "@examples/form-stepper/FormStepperStepStatusExample.tsx"; + FormStepperWithControlledNavigation +} from "@examples/form-stepper-with-controlled-navigation.tsx"; +import { SetTheStatusOfStepOnAFormStepper } from "@examples/set-the-status-of-step-on-a-form-stepper.tsx"; import { SandboxHeader } from "@components/sandbox/sandbox-header/sandboxHeader.tsx"; export const FormStepperExamples = () => { @@ -11,13 +11,13 @@ export const FormStepperExamples = () => { exampleTitle="Controlled Navigation" figmaExample=""> - + - + ) } diff --git a/src/examples/give-background-information-before-asking-a-question.tsx b/src/examples/give-background-information-before-asking-a-question.tsx new file mode 100644 index 000000000..2cb68b8e5 --- /dev/null +++ b/src/examples/give-background-information-before-asking-a-question.tsx @@ -0,0 +1,79 @@ +import { Sandbox } from "@components/sandbox"; +import "./question-page/question-page-examples.css"; +import { CodeSnippet } from "@components/code-snippet/CodeSnippet.tsx"; +import { + GoabButton, + GoabFormItem, + GoabRadioGroup, + GoabRadioItem +} from "@abgov/react-components"; + +export default function GiveBackgroundInformationBeforeAskingAQuestion() { + return ( +
+ + + {/*CSS Code Snippet*/} + ') 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); + } + + a.back-link + h2 { + margin-top: var(--goa-space-2xl); + } + `} + /> + + Back + +

Current school status

+

+ School can encompass foundational programs that help individuals gain basic skills for + further learning and living, such as literacy and numeracy courses. It also includes + skills and employment training programs, designed to equip you with specific skills for + the job market. +

+

+ Post-secondary education, such as Bachelor's, Master's, or Doctoral degrees, and + continuing education courses for professional or personal development, are also + categorized under 'school'. +

+

Contact your provider if you’re concerned about your school status.

+ + { + }}> + + + + + + Save and continue + +
+ + +
+ ); +} diff --git a/src/examples/textarea/TextAreaAskQuestionMoreInformationExample.tsx b/src/examples/give-context-before-asking-a-long-answer-question.tsx similarity index 94% rename from src/examples/textarea/TextAreaAskQuestionMoreInformationExample.tsx rename to src/examples/give-context-before-asking-a-long-answer-question.tsx index ccd4f6d11..e3de88d02 100644 --- a/src/examples/textarea/TextAreaAskQuestionMoreInformationExample.tsx +++ b/src/examples/give-context-before-asking-a-long-answer-question.tsx @@ -2,7 +2,6 @@ import { Sandbox } from "@components/sandbox"; import { GoabButton, GoabButtonGroup, - GoabContainer, GoabDetails, GoabFormItem, GoabTextarea @@ -11,7 +10,7 @@ import { CodeSnippet } from "@components/code-snippet/CodeSnippet.tsx"; import { useContext } from "react"; import { LanguageVersionContext } from "@contexts/LanguageVersionContext.tsx"; -export const TextAreaAskQuestionMoreInformationExample = () => { +export const GiveContextBeforeAskingALongAnswerQuestion = () => { const {version} = useContext(LanguageVersionContext); const noop = () => {} return ( @@ -32,7 +31,6 @@ export const TextAreaAskQuestionMoreInformationExample = () => { } `} />} - Back @@ -61,9 +59,8 @@ export const TextAreaAskQuestionMoreInformationExample = () => { Continue - - - ) } + +export default GiveContextBeforeAskingALongAnswerQuestion; diff --git a/src/examples/group-related-questions-together-on-a-question-page.tsx b/src/examples/group-related-questions-together-on-a-question-page.tsx new file mode 100644 index 000000000..a61ce7eba --- /dev/null +++ b/src/examples/group-related-questions-together-on-a-question-page.tsx @@ -0,0 +1,118 @@ +import { Sandbox } from "@components/sandbox"; +import "./question-page/question-page-examples.css"; +import { CodeSnippet } from "@components/code-snippet/CodeSnippet.tsx"; +import { + GoabButton, + GoabDropdown, GoabDropdownItem, + GoabFormItem, + GoabInput +} from "@abgov/react-components"; +import { LanguageVersionContext } from "@contexts/LanguageVersionContext.tsx"; +import { useContext } from "react"; + +export default function GroupRelatedQuestionsTogetherOnAQuestionPage() { + useContext(LanguageVersionContext); + return ( +
+ + + + {/*CSS Code Snippet*/} + ') 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); + } + + a.back-link + h2 { + margin-top: var(--goa-space-2xl); + } + + h2.section-title { + margin-bottom: 0; + } + + h2.section-title + h3 { + margin-top: var(--goa-space-xs); + } + `} + /> + + + Back + +

Your address

+

This is the home address of the person applying

+ + { + }} + name="address-line-1" + ariaLabel="Address line 1" + width="100%" + /> + + + { + }} + name="address-line-2" + ariaLabel="Address line 2" + width="100%" + /> + + + { + }} + name="town-city" + ariaLabel="Town or city name" + width={"460px"} + /> + + + { + }} name="province-territory" ariaLabelledBy="provinceLabel"> + + + + + + + + + + + + + + + + + { + }} name="postal-code" width={"105px"} /> + + + Save and continue + +
+ +
+ ); +} diff --git a/src/examples/app-header/AppHeaderWithMenuClickEventExample.tsx b/src/examples/header-with-menu-click-event.tsx similarity index 98% rename from src/examples/app-header/AppHeaderWithMenuClickEventExample.tsx rename to src/examples/header-with-menu-click-event.tsx index 3831f5de8..62738326d 100644 --- a/src/examples/app-header/AppHeaderWithMenuClickEventExample.tsx +++ b/src/examples/header-with-menu-click-event.tsx @@ -5,7 +5,7 @@ import { GoabRadioGroupOnChangeDetail } from "@abgov/ui-components-common"; import { useContext, useState } from "react"; import { LanguageVersionContext } from "@contexts/LanguageVersionContext.tsx"; -export const AppHeaderWithMenuClickEventExample = () => { +export const HeaderWithMenuClickEvent = () => { const {version} = useContext(LanguageVersionContext); const [deviceWidth, setDeviceWidth] = useState("5000"); function handleMenuClick() { @@ -203,3 +203,5 @@ export const AppHeaderWithMenuClickEventExample = () => { ) } + +export default HeaderWithMenuClickEvent; diff --git a/src/examples/app-header/AppHeaderWithNavigationExample.tsx b/src/examples/header-with-navigation.tsx similarity index 97% rename from src/examples/app-header/AppHeaderWithNavigationExample.tsx rename to src/examples/header-with-navigation.tsx index 00698cbc0..a25b7b041 100644 --- a/src/examples/app-header/AppHeaderWithNavigationExample.tsx +++ b/src/examples/header-with-navigation.tsx @@ -4,7 +4,7 @@ import { GoabAppHeader, GoabAppHeaderMenu } from "@abgov/react-components"; import { useContext } from "react"; import { LanguageVersionContext } from "@contexts/LanguageVersionContext.tsx"; -export const AppHeaderWithNavigationExample = () => { +export const HeaderWithNavigation = () => { const {version} = useContext(LanguageVersionContext); return ( @@ -99,3 +99,5 @@ export const AppHeaderWithNavigationExample = () => { ) } + +export default HeaderWithNavigation; diff --git a/src/examples/accordion/AccordionHideOrShowSectionExample.tsx b/src/examples/hide-and-show-many-sections-of-information.tsx similarity index 99% rename from src/examples/accordion/AccordionHideOrShowSectionExample.tsx rename to src/examples/hide-and-show-many-sections-of-information.tsx index c81a09c91..0a30f4a68 100644 --- a/src/examples/accordion/AccordionHideOrShowSectionExample.tsx +++ b/src/examples/hide-and-show-many-sections-of-information.tsx @@ -4,7 +4,7 @@ import { GoabAccordion, GoabButton } from "@abgov/react-components"; import { LanguageVersionContext } from "@contexts/LanguageVersionContext.tsx"; import { useContext, useEffect, useState } from "react"; -export const AccordionHideOrShowSectionExample = () => { +export const HideAndShowManySectionsOfInformation = () => { const {version} = useContext(LanguageVersionContext); const [expandedAll, setExpandedAll] = useState(false); const [expandedList, setExpandedList] = useState([]); @@ -262,3 +262,5 @@ export const AccordionHideOrShowSectionExample = () => { ) } + +export default HideAndShowManySectionsOfInformation; diff --git a/src/examples/checkbox/CheckboxDescriptionExample.tsx b/src/examples/include-a-link-in-the-helper-text-of-an-option.tsx similarity index 72% rename from src/examples/checkbox/CheckboxDescriptionExample.tsx rename to src/examples/include-a-link-in-the-helper-text-of-an-option.tsx index 7b4aa8593..18714d585 100644 --- a/src/examples/checkbox/CheckboxDescriptionExample.tsx +++ b/src/examples/include-a-link-in-the-helper-text-of-an-option.tsx @@ -1,17 +1,18 @@ +import { CodeSnippet } from "@components/code-snippet/CodeSnippet.tsx"; import { GoabCheckbox, GoabFormItem } from "@abgov/react-components"; import { Sandbox } from "@components/sandbox"; -import { CodeSnippet } from "@components/code-snippet/CodeSnippet.tsx"; import { useContext } from "react"; import { LanguageVersionContext } from "@contexts/LanguageVersionContext.tsx"; -export default function CheckboxDescriptionExample () { +export const IncludeALinkInTheHelperTextOfAnOption = () => { const {version} = useContext(LanguageVersionContext); + return ( <> - - {/*Angular*/} + + {/*Angular*/} - {version === "old" && `} - />} + />} - {version === "new" && @@ -41,10 +42,10 @@ export default function CheckboxDescriptionExample () { `} - />} + />} - {/*React*/} - {version === "old" && `} - />} + />} - {version === "new" && `} - />} + />} - - Help text with a link.} - /> - - - - + + Help text with a link.} + /> + + + + ); } + +export default IncludeALinkInTheHelperTextOfAnOption; diff --git a/src/examples/radio/RadioSlottedDescriptionExample.tsx b/src/examples/include-descriptions-for-items-in-a-checkbox-list.tsx similarity index 97% rename from src/examples/radio/RadioSlottedDescriptionExample.tsx rename to src/examples/include-descriptions-for-items-in-a-checkbox-list.tsx index feb23afcc..98aa9c562 100644 --- a/src/examples/radio/RadioSlottedDescriptionExample.tsx +++ b/src/examples/include-descriptions-for-items-in-a-checkbox-list.tsx @@ -1,12 +1,14 @@ -import { CodeSnippet } from "@components/code-snippet/CodeSnippet.tsx"; import { GoabFormItem, GoabRadioGroup, GoabRadioItem } from "@abgov/react-components"; import { Sandbox } from "@components/sandbox"; +import { CodeSnippet } from "@components/code-snippet/CodeSnippet.tsx"; import { useContext } from "react"; import { LanguageVersionContext } from "@contexts/LanguageVersionContext.tsx"; -export const RadioSlottedDescriptionExample = () => { +export default function IncludeDescriptionsForIndividualInputOptions() { const {version} = useContext(LanguageVersionContext); - const noop = () => {} + const noop = () => { + }; + return ( {/* =========== Angular =============== */} @@ -137,4 +139,5 @@ export const RadioSlottedDescriptionExample = () => { ) -} \ No newline at end of file +} + diff --git a/src/examples/link-the-user-to-give-feedback-to-the-service.tsx b/src/examples/link-the-user-to-give-feedback-to-the-service.tsx new file mode 100644 index 000000000..5684c2e74 --- /dev/null +++ b/src/examples/link-the-user-to-give-feedback-to-the-service.tsx @@ -0,0 +1,19 @@ +import { GoabMicrositeHeader } from "@abgov/react-components"; +import { Sandbox } from "@components/sandbox"; + +export default function GiveFeedbackLinkExample() { + const onClick = () => { + console.log("Feedback clicked"); + alert("Thank you for your feedback!"); + }; + return ( + <> + + + + {/* ...React + Angular code snippets here (same as original)... */} + + + ); +} + diff --git a/src/examples/link-to-an-external-page.tsx b/src/examples/link-to-an-external-page.tsx new file mode 100644 index 000000000..bd1ae4826 --- /dev/null +++ b/src/examples/link-to-an-external-page.tsx @@ -0,0 +1,16 @@ +import { Sandbox } from "@components/sandbox"; +import { GoabLink } from "@abgov/react-components"; + +export const LinkToAnExternalPage = () => { + return ( + <> + + + External link + + + + ); +}; + +export default LinkToAnExternalPage; \ No newline at end of file diff --git a/src/examples/link/LinkExamples.tsx b/src/examples/link/LinkExamples.tsx index 1b123de1d..f4078897c 100644 --- a/src/examples/link/LinkExamples.tsx +++ b/src/examples/link/LinkExamples.tsx @@ -1,18 +1,12 @@ -import { Sandbox } from "@components/sandbox"; import { SandboxHeader } from "@components/sandbox/sandbox-header/sandboxHeader.tsx"; -import { GoabLink } from "@abgov/react-components"; +import { LinkToAnExternalPage } from "../link-to-an-external-page.tsx"; -export const LinkExamples = () => { +export default function LinkExamples() { return ( <> - - - - - - External link - - + + ); -} \ No newline at end of file +} diff --git a/src/examples/microsite-header/MicrositeHeaderExamples.tsx b/src/examples/microsite-header/MicrositeHeaderExamples.tsx index 02a69a843..7055574e6 100644 --- a/src/examples/microsite-header/MicrositeHeaderExamples.tsx +++ b/src/examples/microsite-header/MicrositeHeaderExamples.tsx @@ -1,207 +1,20 @@ -import { GoabMicrositeHeader } from "@abgov/react-components"; -import { Sandbox } from "@components/sandbox"; -import { CodeSnippet } from "@components/code-snippet/CodeSnippet.tsx"; -import { useContext } from "react"; -import { LanguageVersionContext } from "@contexts/LanguageVersionContext.tsx"; +import GiveFeedbackLinkExample from "../link-the-user-to-give-feedback-to-the-service.tsx"; +import ShowVersionNumberExample from "../show-version-number.tsx"; import { SandboxHeader } from "@components/sandbox/sandbox-header/sandboxHeader.tsx"; export default function MicrositeHeaderExamples() { - const { version } = useContext(LanguageVersionContext); - const onClick = () => { - console.log("Feedback clicked"); - alert("Thank you for your feedback!"); - }; return ( <> - - - - {/*Angular code*/} - {version === "old" && ( - - )} - {version === "new" && ( - - )} - - {version === "old" && ( - - `} - /> - )} - {version === "new" && ( - - `} - /> - )} - - {version === "old" && ( - - onClick()} - /> - - ); - } - `} - /> - )} - {version === "new" && ( - - onClick()} - /> - - ); - } - `} - /> - )} - - + figmaExample="https://www.figma.com/design/aIRjvBzpIUH0GbkffjbL04/%E2%9D%96-Patterns-library-%7C-DDD?node-id=6311-92884" + /> + - - - {/*Angular*/} - {version === "old" && -
- Slotted version text. - v1.23 -
- - `} - />} - {version === "new" && - - Slotted version text. - v1.23 - - - `} - />} - {/*React*/} - {version === "old" && Slotted version text.v1.23} - > - `} - />} - {version === "new" && Slotted version text.v1.23} - > - `} - />} - - - Slotted version text. - - v1.23 - - } - /> -
+ figmaExample="https://www.figma.com/design/aIRjvBzpIUH0GbkffjbL04/%E2%9D%96-Patterns-library-%7C-DDD?node-id=6311-92885" + /> + ); -} +} \ No newline at end of file diff --git a/src/examples/modal/ModalExamples.tsx b/src/examples/modal/ModalExamples.tsx index 857f561d5..74b1a2f70 100644 --- a/src/examples/modal/ModalExamples.tsx +++ b/src/examples/modal/ModalExamples.tsx @@ -1,50 +1,51 @@ import "./modal-examples.css"; -import { ModalBasicExample } from "@examples/modal/ModalBasicExample.tsx"; -import { ModalConfirmDestructiveActionExample } from "@examples/modal/ModalConfirmDestructiveActionExample.tsx"; -import { ModalWarnUserDeadlineExample } from "@examples/modal/ModalWarnUserDeadlineExample.tsx"; -import { ModalConfirmRecordChangeExample } from "@examples/modal/ModalConfirmRecordChangeExample.tsx"; -import { ModalAddAnotherItemExample } from "@examples/modal/ModalAddAnotherItemExample.tsx"; -import { ModalRouteChangeExample } from "@examples/modal/ModalRouteChangeExample.tsx"; +import { RequireUserActionBeforeContinuing } from "@examples/require-user-action-before-continuing.tsx"; +import { ConfirmADestructiveAction } from "@examples/confirm-a-destructive-action.tsx"; +import { WarnAUserOfADeadline } from "@examples/warn-a-user-of-a-deadline.tsx"; +import { ConfirmAChange } from "@examples/confirm-a-change.tsx"; +import { ConfirmBeforeNavigatingAway } from "@examples/confirm-before-navigating-away.tsx"; import { SandboxHeader } from "@components/sandbox/sandbox-header/sandboxHeader.tsx"; +import { AddAnotherItemInAModal } from "@examples/add-another-item-in-a-modal.tsx"; export default function ModalExamples() { return ( <> + exampleTitle="Basic Modal" + figmaExample={"https://www.figma.com/design/3pb2IK8s2QUqWieH79KdN7/%E2%9D%96-Component-library-%7C-DDD?node-id=26318-184965&t=Mgdr0KBlqhEz1RXF-4"}> - + - + - + - + - + - + ); } diff --git a/src/examples/notification/NotificationExamples.tsx b/src/examples/notification/NotificationExamples.tsx index bc9ff59df..97187f6bb 100644 --- a/src/examples/notification/NotificationExamples.tsx +++ b/src/examples/notification/NotificationExamples.tsx @@ -1,5 +1,5 @@ import { SandboxHeader } from "@components/sandbox/sandbox-header/sandboxHeader.tsx"; -import { NotificationServiceOutageExample } from "@examples/notification/NotificationServiceOutageExample.tsx"; +import { CommunicateAFutureServiceOutage } from "@examples/communicate-a-future-service-outage.tsx"; export const NotificationExamples = () => { return ( @@ -8,7 +8,7 @@ export const NotificationExamples = () => { exampleTitle="Communicate a future service outage" figmaExample="https://www.figma.com/design/aIRjvBzpIUH0GbkffjbL04/%E2%9D%96-Patterns-library-%7C-DDD?node-id=6311-93778&t=sWyB4A2UXCb9rn2W-1">
- + ) } diff --git a/src/examples/pagination/PaginationExamples.tsx b/src/examples/pagination/PaginationExamples.tsx index 257fb3fbc..dbb77150e 100644 --- a/src/examples/pagination/PaginationExamples.tsx +++ b/src/examples/pagination/PaginationExamples.tsx @@ -1,581 +1,14 @@ -import { Sandbox } from "@components/sandbox"; -import { CodeSnippet } from "@components/code-snippet/CodeSnippet.tsx"; -import { - GoabBlock, - GoabDropdown, - GoabDropdownItem, - GoabPagination, - GoabSpacer, - GoabTable, -} from "@abgov/react-components"; -import { useContext, useEffect, useState } from "react"; -import { LanguageVersionContext } from "@contexts/LanguageVersionContext.tsx"; -import { GoabDropdownOnChangeDetail } from "@abgov/ui-components-common"; -import { faker } from "@faker-js/faker"; +import ShowNumberOfResultsPerPageExample from "../show-number-of-results-per-page.tsx"; import { SandboxHeader } from "@components/sandbox/sandbox-header/sandboxHeader.tsx"; -interface User { - id: string; - firstName: string; - lastName: string; - age: number; -} - export const PaginationExamples = () => { - const { version } = useContext(LanguageVersionContext); - const [users, setUsers] = useState([]); - const [pageUsers, setPageUsers] = useState([]); - const [page, setPage] = useState(1); - const [perPage, setPerPage] = useState(10); - - useEffect(() => { - const _users = []; - for (let i = 1; i <= 100; i++) { - _users.push({ - id: faker.datatype.uuid(), - firstName: faker.name.firstName(), - lastName: faker.name.lastName(), - age: faker.datatype.number({ min: 18, max: 60 }), - }); - } - setUsers(_users); - setPageUsers(_users.slice(0, perPage)); - }, [perPage]); - - function changePage(newPage: number) { - const offset = (newPage - 1) * 10; - const _users = users.slice(offset, offset + perPage); - setPage(newPage); - setPageUsers(_users); - } - - function handlePerPageCountChangeEvent(event: GoabDropdownOnChangeDetail) { - const perPageValue = parseInt(event.value || "1"); - setPage(1); - setPerPage(perPageValue); - const _users = users.slice(0, perPageValue); - setPageUsers(_users); - } - return ( <> - - - {/*============= React code ==============*/} - {version === "old" && ( - ([]); - const [pageUsers, setPageUsers] = useState([]); - const [page, setPage] = useState(1); - const [perPage, setPerPage] = useState(10); - - useEffect(() => { - const _users = []; - for (let i = 1; i <= 100; i++) { - _users.push({ - id: faker.datatype.uuid(), - firstName: faker.name.firstName(), - lastName: faker.name.lastName(), - age: faker.datatype.number({ min: 18, max: 60 }), - }); - } - setUsers(_users); - setPageUsers(_users.slice(0, perPage)); - }, [perPage]); - - function changePage(newPage: number) { - const offset = (newPage - 1) * 10; - const _users = users.slice(offset, offset + perPage); - setPage(newPage); - setPageUsers(_users); - } - - function handlePerPageCountChangeEvent(name: string, value: string | string[]) { - const perPageValue = Array.isArray(value) ? parseInt(value[0]) : parseInt(value); - setPage(1); - setPerPage(perPageValue); - const _users = users.slice(0, perPageValue); - setPageUsers(_users); - } - `} - /> - )} - - {version === "new" && ( - ([]); - const [pageUsers, setPageUsers] = useState([]); - const [page, setPage] = useState(1); - const [perPage, setPerPage] = useState(10); - - useEffect(() => { - const _users = []; - for (let i = 1; i <= 100; i++) { - _users.push({ - id: faker.string.uuid(), - firstName: faker.person.firstName(), - lastName: faker.person.lastName(), - age: faker.number.int({ min: 18, max: 60 }), - }); - } - setUsers(_users); - setPageUsers(_users.slice(0, perPage)); - }, [perPage]); - - function changePage(newPage: number) { - const offset = (newPage - 1) * 10; - const _users = users.slice(offset, offset + perPage); - setPage(newPage); - setPageUsers(_users); - } - - function handlePerPageCountChangeEvent(event: GoabDropdownOnChangeDetail) { - const perPageValue = parseInt(event.value || '1'); - setPage(1); - setPerPage(perPageValue); - const _users = users.slice(0, perPageValue); - setPageUsers(_users); - } - `} - /> - )} - - {version === "old" && ( - - - - First name - Last name - Age - - - - {pageUsers.map((u) => ( - - {u.firstName} - {u.lastName} - {u.age} - - ))} - - - - - - Show - - - - - - of {users.length} - - - - - - - `} - /> - )} - - {version === "new" && ( - - - - First name - Last name - Age - - - - {pageUsers.map((u) => ( - - {u.firstName} - {u.lastName} - {u.age} - - ))} - - - - - - Show - - - - - - of {users.length} - - - - - changePage(event.page)} - /> - - `} - /> - )} - - {/*================ Angular code ==================*/} - {version === "old" && ( - - )} - - {version === "new" && ( - - )} - - {version === "old" && ( - - - - First name - Last name - Age - - - - - {{ user.firstName }} - {{ user.lastName }} - {{ user.age }} - - - - - - - Show - - - - - - - - - - - - - - of {{ this.users.length }} - - - - - - - - - `} - /> - )} - - {version === "new" && ( - - - - First name - Last name - Age - - - - - {{ user.firstName }} - {{ user.lastName }} - {{ user.age }} - - - - - - - Show - - - - - - - - - - - - - of {{ this.users.length }} - - - - - - - - `} - /> - )} - - - - - First name - Last name - Age - - - - {pageUsers.map(u => ( - - {u.firstName} - {u.lastName} - {u.age} - - ))} - - - - - - Show - - {[10, 20, 30].map(value => ( - - ))} - - per page - - - - changePage(event.page)} - /> - - + ); }; diff --git a/src/examples/popover/ButtonClosePopover.tsx b/src/examples/popover/ButtonClosePopover.tsx new file mode 100644 index 000000000..8fa94ebbe --- /dev/null +++ b/src/examples/popover/ButtonClosePopover.tsx @@ -0,0 +1,94 @@ +import { Sandbox } from "@components/sandbox"; +import { CodeSnippet } from "@components/code-snippet/CodeSnippet.tsx"; +import { GoabBlock, GoabButton, GoabPopover } from "@abgov/react-components"; +import { LanguageVersionContext } from "@contexts/LanguageVersionContext.tsx"; +import { useContext } from "react"; + +export const ButtonClosePopover = () => { + const { version } = useContext(LanguageVersionContext); + + const popoverTargetWithClose = ( + + Click to open + + ); + + return ( + + {/* React Code Snippets */} + {version === "new" && ( + + Click to open + + ); + `} + /> + )} + + {version === "new" && ( + +

This popover has a close button inside

+

Click the button below to close this popover.

+ + Close Popover + + + `} + /> + )} + + {/* Angular Code Snippets */} + {version === "new" && ( + +

This popover has a close button inside

+

Click the button below to close this popover.

+ + Close Popover + + + + + Click to open + + + + `} + /> + )} + + {/* Sandbox Example */} + + +

This popover has a close button inside

+

Click the button below to close this popover.

+ + Close Popover + +
+
+
+ ); +}; diff --git a/src/examples/popover/IconButtonClosePopover.tsx b/src/examples/popover/IconButtonClosePopover.tsx new file mode 100644 index 000000000..4d75a6053 --- /dev/null +++ b/src/examples/popover/IconButtonClosePopover.tsx @@ -0,0 +1,97 @@ +import { Sandbox } from "@components/sandbox"; +import { CodeSnippet } from "@components/code-snippet/CodeSnippet.tsx"; +import { GoabBlock, GoabButton, GoabIconButton, GoabPopover } from "@abgov/react-components"; +import { LanguageVersionContext } from "@contexts/LanguageVersionContext.tsx"; +import { useContext } from "react"; + +export const IconButtonClosePopover = () => { + const { version } = useContext(LanguageVersionContext); + + const popoverTargetWithClose = ( + + Click to open + + ); + + return ( + + {/* React Code Snippets */} + {version === "new" && ( + + Click to open + + ); + `} + /> + )} + + {version === "new" && ( + + + + +

This popover has a close icon button inside

+

Click the icon button above to close this popover.

+ + `} + /> + )} + + {/* Angular Code Snippets */} + {version === "new" && ( + + + + + +

This popover has a close icon button inside

+

Click the icon button above to close this popover.

+ + + + Click to open (with close icon button) + + + + `} + /> + )} + + {/* Sandbox Example */} + + + + + +

This popover has a close icon button inside

+

Click the icon button above to close this popover.

+
+
+
+ ); +}; diff --git a/src/examples/popover/LinkClosePopover.tsx b/src/examples/popover/LinkClosePopover.tsx new file mode 100644 index 000000000..49d247aab --- /dev/null +++ b/src/examples/popover/LinkClosePopover.tsx @@ -0,0 +1,87 @@ +import { Sandbox } from "@components/sandbox"; +import { CodeSnippet } from "@components/code-snippet/CodeSnippet.tsx"; +import { GoabBlock, GoabButton, GoabLink, GoabPopover } from "@abgov/react-components"; +import { LanguageVersionContext } from "@contexts/LanguageVersionContext.tsx"; +import { useContext } from "react"; + +export const LinkClosePopover = () => { + const { version } = useContext(LanguageVersionContext); + + const popoverTargetWithClose = ( + + Click to open + + ); + + return ( + + {/* React Code Snippets */} + {version === "new" && ( + + Click to open + + ); + `} + /> + )} + + {version === "new" && ( + +

This popover has a close link inside

+

Click the link below to close this popover.

+ + Close Popover + + + `} + /> + )} + + {/* Angular Code Snippets */} + {version === "new" && ( + +

This popover has a close link inside

+

Click the link below to close this popover.

+ + Close Popover + + + + + Click to open + + + + `} + /> + )} + + {/* Sandbox Example */} + + +

This popover has a close link inside

+

Click the link below to close this popover.

+ + Close Popover + +
+
+
+ ); +}; diff --git a/src/examples/popover/PopoverExamples.tsx b/src/examples/popover/PopoverExamples.tsx new file mode 100644 index 000000000..719e77319 --- /dev/null +++ b/src/examples/popover/PopoverExamples.tsx @@ -0,0 +1,34 @@ +import { ButtonClosePopover } from "@examples/popover/ButtonClosePopover"; +import { LinkClosePopover } from "@examples/popover/LinkClosePopover"; +import { IconButtonClosePopover } from "@examples/popover/IconButtonClosePopover"; +import { SandboxHeader } from "@components/sandbox/sandbox-header/sandboxHeader.tsx"; +import { GoabSpacer } from "@abgov/react-components"; +import { OldComponentBanner } from "@components/old-component-banner/OldComponentBanner.tsx"; +import { useContext } from "react"; +import { LanguageVersionContext } from "@contexts/LanguageVersionContext.tsx"; + +export const PopoverExamples = () => { + const { version, language } = useContext(LanguageVersionContext); + return ( + <> + {/*Popover Example - close using a button*/} + + + + {/*Popover example - close using a link*/} + + + + {/*Popover example - close using an icon-button*/} + + + + + {version === "old" && ( + + )} + + ); +}; diff --git a/src/examples/public-form.tsx b/src/examples/public-form.tsx new file mode 100644 index 000000000..e921c58ad --- /dev/null +++ b/src/examples/public-form.tsx @@ -0,0 +1,236 @@ +import { ComponentContent } from "@components/component-content/ComponentContent.tsx"; +import { GoabDetails, GoabGrid, GoabText } from "@abgov/react-components"; +import css from "@routes/examples/patterns.module.css"; +import { Link } from "react-router-dom"; + +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

+ +
+ public form pages overview image +
+ +
+
+ + 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. + +
+
+ +
+ +

+ Form structure +

+ + Form structure + + + + Use the public form structure focused on content, and asking the right questions to your user + to keep 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're telling a user +
  • +
+
+ +
+ Starting with one thing per page helps users to: +
    +
  • + understand what you're asking them to do +
  • +
  • + focus on specific questions 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: +
    +
  • + 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 doesn’t necessarily mean you should use one form field. For example, + asking a user for their address is best captured all on the same page with multiple fields. + + +

Accessibility

+
+ + Structuring your form with one idea per page simplifies the experience, and makes your + form 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. +
  3. + + 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. + +
  4. +
  5. + + 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 for users, particularly those with cognitive impairments and those + using assistive technologies. + +
  6. +
  7. + + Progressive disclosure: One idea per page allows the user to focus on + the current task and move through more information slowly. This can be especially + beneficial to users who are easily distracted or overwhelmed by too much information. + +
  8. +
+
+ +

Adding complexity

+ + Start by making sure that 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 to communicate + progress +
  • +
  • + breaking the form into sections on a task list page +
  • +
+
+ +

Form stepper

+ + Avoid using traditional horizontal form steppers for every form. Research has shown that + horizontal form 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 +
  • +
  • + follow the one idea per page approach, and break the form into + sections as needed using a task list page +
  • +
+
+
+ ); +} + +export default PublicForm; diff --git a/src/routes/patterns/QuestionPage.tsx b/src/examples/question-page.tsx similarity index 60% rename from src/routes/patterns/QuestionPage.tsx rename to src/examples/question-page.tsx index 7c51ce64f..b1b35b37d 100644 --- a/src/routes/patterns/QuestionPage.tsx +++ b/src/examples/question-page.tsx @@ -1,24 +1,21 @@ import { GoabTab, - GoabTabs + GoabTabs, + GoabText } from "@abgov/react-components"; -import { ComponentContent } from "@components/component-content/ComponentContent"; -import QuestionPageExamples from "@examples/question-page/QuestionPageExamples"; -import css from "./patterns.module.css"; +import { ComponentContent } from "@components/component-content/ComponentContent.tsx"; +import css from "@routes/examples/patterns.module.css"; +import QuestionPageExamples from "@examples/question-page/QuestionPageExamples.tsx"; -export default function QuestionPage() { + +export function QuestionPage() { return ( <> -

Question pages

-

- This is the starting point for a citizen to begin your form from within your service or from - Alberta.ca. -

- + @@ -31,101 +28,127 @@ export default function QuestionPage() {

Form structure

-

+ Start by splitting the form across multiple pages with each page containing just one idea, for example: -

+
    -
  • one piece of information you’re telling a user
  • -
  • one decision they have to make
  • -
  • one question they have to answer
  • +
  • + one piece of information you’re telling a user +
  • +
  • + one decision they have to make +
  • +
  • + one question they have to answer +

Helps users to:

    -
  • understand what you’re asking them to do
  • -
  • focus on the specific question and its answer
  • -
  • find their way through an unfamiliar process
  • -
  • use the service on a mobile device
  • -
  • recover easily from errors
  • -
  • navigate with assistive technologies
  • +
  • + understand what you’re asking them to do +
  • +
  • + focus on the specific question and its answer +
  • +
  • + find their way through an unfamiliar process +
  • +
  • + use the service on a mobile device +
  • +
  • + recover easily from errors +
  • +
  • + navigate with assistive technologies +

Helps the service to:

    -
  • handle branching questions and loops
  • -
  • save a user’s answers automatically as they go
  • -
  • capture analytics about each question
  • -
  • manage potential complexity on a page
  • +
  • + handle branching questions and loops +
  • +
  • + save a user’s answers automatically as they go +
  • +
  • + capture analytics about each question +
  • +
  • + manage potential complexity on a page +

What are the main benefits of starting with one idea per page?

-

+ Focus: Asking one question at a time helps users focus on the task at hand. This is especially beneficial for complex forms or surveys, where multiple fields can easily overwhelm or confuse the user. The user's attention is undivided, leading to higher quality responses and fewer errors. -

-

+ + Efficiency: Due to the improved focus of the task at hand, completion time for forms can be lowered when measured against traditional long form patterns. -

-

+ + Progression: This approach gives users a sense of progression and accomplishment as they navigate through the form, which can motivate them to complete the form. It allows for a linear progression model, which can be less intimidating and less overwhelming than seeing a full page of empty fields at once. -

-

+ + Reduce Cognitive Load: By reducing the amount of information presented at once, this design pattern can help minimize cognitive load. The cognitive load theory suggests that our working memory capacity is limited, and if too much information is presented at once, it can lead to confusion and mistakes. -

-

+ + Adaptive: allows for adaptive questioning. The answer to one question can determine the next question asked. This isn't always possible when all questions are presented at once. This can help make the form shorter and more relevant for the user, increasing completion rates and user satisfaction. -

-

+ + Data Quality: With all the user's attention on one question, they are more likely to provide accurate and thoughtful answers. This can help to improve the quality of data gathered. -

-

+ + Mobile Friendly: As mobile usage continues to grow, one question at a time approach makes it easier for users to fill out the form on smaller screens. Long forms can be particularly daunting on mobile devices, so breaking it up into smaller, manageable pieces can improve user experience. -

-

+ + Error Handling: If a user makes an error on a form, it is easier and faster to provide feedback on that specific question, leading to an overall smoother and less frustrating user experience. -

+

Using progress indicators

-

+ Start by testing your form without a progress indicator to see if it’s simple enough that users do not need one. -

-

+ + Try improving the order, type or number of questions before adding a progress indicator. If people still have difficulty, try adding a simple step or question indicator. -

-

+ + Only include the total number of questions if you can do so reliably. As the user moves through the form, make sure the indicator updates to tell them which question they are on and the total number remaining. -

+

Why should I avoid progress indicators on forms?

-

+ Induce anxiety: If the form is lengthy, showing a slow-moving progress bar can induce anxiety and may deter the user from completing the form. Users could feel overwhelmed by the perceived time investment and the number of questions yet to come. -

-

+ + False perception: Progress bars often represent completion in a linear fashion, but not all form questions take an equal amount of time or effort to complete. A user might spend more time on an earlier question and then speed through subsequent ones. This can lead to an inaccurate perception of progress, causing user frustration. -

-

+ + Distraction: In an adaptive questioning scenario where the next question depends on the answer to the current question, it's challenging to provide an accurate progress indicator as the total number of questions can change dynamically. -

-

+ + Speed over accuracy: A progress indicator can lead users to rush through the form to see the progress bar move faster, thus sacrificing the quality of their responses. -

-

+ + Cannot use branching form logic: It's challenging to provide an accurate progress indicator in a non-linear form where the next question depends on the answer to the current question. The total number of questions will change dynamically. -

-

+ + Additional development and testing time: that progress indicators and form steppers introduce. -

+

When to use a form stepper

-

A form stepper is a type of visual step/progress indicator in a form.

-

+ A form stepper is a type of visual step/progress indicator in a + form. + Start with a one thing per page approach, and consider using a form stepper when all of the following is true: -

+
  • - your form can be broken into logical groups or steps that is helpful to constantly - communicate to the user + your form can be broken into logical groups or steps that is + helpful to constantly communicate to the user
  • -
  • your form is always linear, and a user cannot skip questions
  • - it is valuable to indicate to the user where they are in the process at all times - ongoing + your form is always linear, and a user cannot skip + questions
  • - it is valuable to indicate to the user how many steps are remaining, and you can - do so reliably + it is valuable to indicate to the user where they are in the + process at all times ongoing
  • - the form is not dynamic, where the number of questions remaining can change - depending on the response + it is valuable to indicate to the user how many steps are + remaining, and you can do so reliably +
  • +
  • + the form is not dynamic, where the number of questions + remaining can change depending on the response
-

+ Make it clear which tasks a user has completed and which they still need to complete. -

+ ); } + +export default QuestionPage; diff --git a/src/examples/question-page/QuestionPageExamples.tsx b/src/examples/question-page/QuestionPageExamples.tsx index 5d3a7e920..6a06bbbcb 100644 --- a/src/examples/question-page/QuestionPageExamples.tsx +++ b/src/examples/question-page/QuestionPageExamples.tsx @@ -1,639 +1,59 @@ -import { Sandbox } from "@components/sandbox"; -import "./question-page-example.css"; -import { CodeSnippet } from "@components/code-snippet/CodeSnippet.tsx"; -import { - GoabButton, - GoabDetails, GoabDropdown, GoabDropdownItem, - GoabFormItem, - GoabInput, - GoabRadioGroup, - GoabRadioItem -} from "@abgov/react-components"; -import { LanguageVersionContext } from "@contexts/LanguageVersionContext.tsx"; -import { useContext } from "react"; +import { SandboxHeader } from "@components/sandbox/sandbox-header/sandboxHeader.tsx"; +import AskAUserOneQuestionAtATime from "@examples/ask-a-user-one-question-at-a-time.tsx"; +import GiveBackgroundInformationBeforeAskingAQuestion + from "../give-background-information-before-asking-a-question.tsx"; +import RevealMoreInformationToHelpAnswerAQuestion from "../reveal-more-information-to-help-answer-a-question.tsx"; +import ShowASectionTitleOnAQuestionPage from "../show-a-section-title-on-a-question-page.tsx"; +import ShowASimpleProgressIndicatorOnAQuestionPage from "../show-a-simple-progress-indicator-on-a-question-page.tsx"; +import GroupRelatedQuestionsTogetherOnAQuestionPage from "../group-related-questions-together-on-a-question-page.tsx"; +import ShowASimpleProgressIndicatorOnAQuestionPageWithMultipleQuestions + from "../show-a-simple-progress-indicator-on-a-question-page-with-multiple-questions.tsx"; export default function QuestionPageExamples() { - const {version} = useContext(LanguageVersionContext); return (
-
-

One question

- - View in Figma - -
- - {/*CSS Code Snippet*/} - ') 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); - } - `} - /> - - - Back - - - {}}> - - - No - - - - - Save and continue - - - -
-

Additional background information

- - View in Figma - -
- - {/*CSS Code Snippet*/} - ') 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); - } - - a.back-link + h2 { - margin-top: var(--goa-space-2xl); - } - `} - /> - - Back - -

Current school status

-

- School can encompass foundational programs that help individuals gain basic skills for - further learning and living, such as literacy and numeracy courses. It also includes - skills and employment training programs, designed to equip you with specific skills for - the job market. -

-

- Post-secondary education, such as Bachelor's, Master's, or Doctoral degrees, and - continuing education courses for professional or personal development, are also - categorized under 'school'. -

-

Contact your provider if you’re concerned about your school status.

- - {}}> - - - - - - Save and continue - -
- -
-

Progressive disclosure

- - View in Figma - -
- - {/* - CSS Code Snippet*/} - ') 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); - } - `} - /> - - - Back - - - {}}> - - - - - - -

We ask this question to determine if you are eligible for child care benefits.

-
- - Save and continue - -
- -
-

Section title

- - View in Figma - -
- - {/*CSS Code Snippet*/} - ') 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); - } - - h3.section-title { - margin-bottom: 0; - color: var(--goa-color-text-secondary); - } - - a.back-link + h3 { - margin-top: var(--goa-space-2xl); - } - `} - /> - - - Back - -

Personal information

- - {}}> - - - - - - Save and continue - -
- -
-

Simple progress indicator

- - View in Figma - -
- - {/*CSS Code Snippet*/} - ') 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); - } - - a.back-link + h3 { - margin-top: var(--goa-space-2xl); - } - `} - /> - - Back - -

Question 3 of 9

- - {}}> - - - - - - Save and continue - -
- -
-

Multiple questions

- - View in Figma - -
- - {/*CSS Code Snippet*/} - ') 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); - } - - a.back-link + h2 { - margin-top: var(--goa-space-2xl); - } - - h2.section-title { - margin-bottom: 0; - } - - h2.section-title + h3 { - margin-top: var(--goa-space-xs); - } - `} - /> - - - Back - -

Your address

-

This is the home address of the person applying

- - {}} - name="address-line-1" - ariaLabel="Address line 1" - width="100%" - /> - - - {}} - name="address-line-2" - ariaLabel="Address line 2" - width="100%" - /> - - - {}} - name="town-city" - ariaLabel="Town or city name" - width={"460px"} - /> - - - {}} name="province-territory" ariaLabelledBy="provinceLabel"> - - - - - - - - - - - - - - - - - {}} name="postal-code" width={"105px"} /> - - - Save and continue - -
- -
-

Multiple questions and a simple progress indicator

- - View in Figma - -
- - {/*CSS Code Snippet*/} - ') 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); - } - - h3.section-title { - margin-bottom: 0; - color: var(--goa-color-text-secondary); - } - - a.back-link + h3 { - margin-top: var(--goa-space-2xl); - } - - h3.section-title + h2 { - margin-top: var(--goa-space-xs); - } - `} - /> - - {/*Angular Code Snippet - need for leadingContent slot*/} - - {version === "old" && - Back - -

- Step 1 of 5 -

-

- Personal information -

- - - - - -
+1
-
-
- - - - - Save and continue - - `} - />} - - {version === "new" && - Back - -

- Step 1 of 5 -

-

- Personal information -

- - - - - -
+1
-
-
- - - - - Save and continue - - `} - />} - - {/*React Code Snippet - need for leadingContent slot*/} - {version === "old" && - Back - -

Step 1 of 5

-

Personal information

- - {}} name="name" ariaLabel="what is your name?" width="50ch" /> - - - {}} - name="phone-number" - ariaLabel="what is your phone number?" - leadingContent="+1" - /> - - - {}} - name="postal-code" - width="14ch" - ariaLabel="what is your home postal code"> - - - Save and continue - - `} - />} - - {version === "new" && - Back - -

Step 1 of 5

-

Personal information

- - {}} name="name" ariaLabel="what is your name?" width="50ch" /> - - - {}} - name="phone-number" - ariaLabel="what is your phone number?" - leadingContent="+1" - /> - - - {}} - name="postal-code" - width="14ch" - ariaLabel="what is your home postal code"> - - - Save and continue - - `} - />} - - - Back - -

Step 1 of 5

-

Personal information

- - - {}} name="name" ariaLabel="what is your name?" width="50ch" /> - - - {}} - name="phone-number" - ariaLabel="what is your phone number?" - leadingContent="+1" - /> - - - {}} - name="postal-code" - width="14ch" - ariaLabel="what is your home postal code"> - - - Save and continue - -
); -} +} \ No newline at end of file diff --git a/src/examples/question-page/question-page-example.css b/src/examples/question-page/question-page-examples.css similarity index 100% rename from src/examples/question-page/question-page-example.css rename to src/examples/question-page/question-page-examples.css diff --git a/src/examples/radio/RadioExamples.tsx b/src/examples/radio/RadioExamples.tsx index 0b8b3fa36..c766f7b22 100644 --- a/src/examples/radio/RadioExamples.tsx +++ b/src/examples/radio/RadioExamples.tsx @@ -1,29 +1,31 @@ -import { RadioSlottedDescriptionExample } from "@examples/radio/RadioSlottedDescriptionExample.tsx"; -import { RadioYesNoExample } from "@examples/radio/RadioYesNoExample.tsx"; -import { SandboxHeader } from "@components/sandbox/sandbox-header/sandboxHeader.tsx"; +import { + IncludeALinkInTheHelperTextOfAnOption +} from "@examples/include-a-link-in-the-helper-text-of-an-option.tsx"; +import { SetAMaxWidthOnALongRadioItem } from "@examples/set-a-max-width-on-a-long-radio-item.tsx"; import { RadioRevealSlotExample } from "@examples/radio/RadioRevealSlotExample.tsx"; +import { SandboxHeader } from "@components/sandbox/sandbox-header/sandboxHeader.tsx"; export default function RadioExamples () { return ( <> + exampleTitle="Include a link in the helper text of an option" + figmaExample="https://www.figma.com/design/aIRjvBzpIUH0GbkffjbL04/%E2%9D%96-Patterns-library-%7C-DDD?node-id=6311-133375&t=X0IQW5flDDaj8Vyg-4"> - + + exampleTitle="Max width on long radio items" + figmaExample="https://www.figma.com/design/aIRjvBzpIUH0GbkffjbL04/%E2%9D%96-Patterns-library-%7C-DDD?node-id=6311-133539&t=X0IQW5flDDaj8Vyg-4"> - + - + ); -} +} \ No newline at end of file diff --git a/src/examples/filter-chip/FilterChipDeleteEventExample.tsx b/src/examples/remove-a-filter.tsx similarity index 97% rename from src/examples/filter-chip/FilterChipDeleteEventExample.tsx rename to src/examples/remove-a-filter.tsx index d1cf464d6..664bc5f5e 100644 --- a/src/examples/filter-chip/FilterChipDeleteEventExample.tsx +++ b/src/examples/remove-a-filter.tsx @@ -4,7 +4,7 @@ import { CodeSnippet } from "@components/code-snippet/CodeSnippet.tsx"; import { useContext, useState } from "react"; import { LanguageVersionContext } from "@contexts/LanguageVersionContext.tsx"; -export const FilterChipDeleteEventExample = () => { +export const RemoveAFilter = () => { const {version} = useContext(LanguageVersionContext); const [chips, setChips] = useState(["Chip 1", "Chip 2", "Chip 3"]); const deleteChip = (chip: string) => { @@ -111,3 +111,5 @@ export const FilterChipDeleteEventExample = () => { ) } + +export default RemoveAFilter; diff --git a/src/examples/modal/ModalBasicExample.tsx b/src/examples/require-user-action-before-continuing.tsx similarity index 82% rename from src/examples/modal/ModalBasicExample.tsx rename to src/examples/require-user-action-before-continuing.tsx index 0ae259c33..08cd949f8 100644 --- a/src/examples/modal/ModalBasicExample.tsx +++ b/src/examples/require-user-action-before-continuing.tsx @@ -4,28 +4,28 @@ import { CodeSnippet } from "@components/code-snippet/CodeSnippet.tsx"; import { useContext, useState } from "react"; import { LanguageVersionContext } from "@contexts/LanguageVersionContext.tsx"; -export const ModalBasicExample = () => { +export const RequireUserActionBeforeContinuing = () => { const {version} = useContext(LanguageVersionContext); const [basicModalOpen, setBasicModalOpen] = useState(); return ( setBasicModalOpen(true)}>Open Basic Modal setBasicModalOpen(false)} actions={ setBasicModalOpen(false)}> - Secondary + Back setBasicModalOpen(false)}> - Primary + Continue }> -

Content

+

You cannot return to this page.

{/*Angular*/} { allowCopy={true} code={` Open Basic Modal - -

Content

+ +

You cannot return to this page.

- Secondary - Primary + Back + Continue
@@ -69,12 +69,12 @@ export const ModalBasicExample = () => { allowCopy={true} code={` Open Basic Modal - -

Content

+ +

You cannot return to this page.

- Secondary - Primary + Back + Continue
@@ -100,22 +100,22 @@ export const ModalBasicExample = () => { code={` setOpen(true)}>Open Basic Modal setOpen(false)} actions={ setOpen(false)}> - Secondary + Back setOpen(false)}> - Primary + Continue } > -

Content

+

You cannot return to this page.

`} /> @@ -129,22 +129,22 @@ export const ModalBasicExample = () => { code={` setOpen(true)}>Open Basic Modal setOpen(false)} actions={ setOpen(false)}> - Secondary + Back setOpen(false)}> - Primary + Continue } > -

Content

+

You cannot return to this page.

`} /> @@ -152,3 +152,5 @@ export const ModalBasicExample = () => {
) } + +export default RequireUserActionBeforeContinuing; diff --git a/src/examples/date-picker/DatePickerResetExample.tsx b/src/examples/reset-date-picker-field.tsx similarity index 99% rename from src/examples/date-picker/DatePickerResetExample.tsx rename to src/examples/reset-date-picker-field.tsx index 97f57f657..009dca0f7 100644 --- a/src/examples/date-picker/DatePickerResetExample.tsx +++ b/src/examples/reset-date-picker-field.tsx @@ -5,7 +5,7 @@ import { GoabDatePickerOnChangeDetail } from "@abgov/ui-components-common"; import { useContext, useState } from "react"; import { LanguageVersionContext } from "@contexts/LanguageVersionContext.tsx"; -export const DatePickerResetExample = () => { +export const ResetDatePickerField = () => { const {version} = useContext(LanguageVersionContext); const [date, setDate] = useState(); @@ -251,3 +251,5 @@ export const DatePickerResetExample = () => { ) } + +export default ResetDatePickerField; diff --git a/src/examples/result-page.tsx b/src/examples/result-page.tsx new file mode 100644 index 000000000..5e7f6b061 --- /dev/null +++ b/src/examples/result-page.tsx @@ -0,0 +1,66 @@ +import { + GoabTab, + GoabTabs, + GoabText +} from "@abgov/react-components"; +import { ComponentContent } from "@components/component-content/ComponentContent.tsx"; +import css from "@routes/examples/patterns.module.css"; +import { ResultPageExamples } from "@examples/result-page/ResultPageExamples.tsx"; + +export function ResultPage() { + return ( + <> + + + + + + + +

Overview

+
+ result page overview image +
+ +

When to use a results page

+ + Use a results page when a user has submitted a form, application, or task, and there is a result to show + them. + + +

What content to include

+
    +
  • + details of what happens next, and when +
  • +
  • + a reference number (if applicable) +
  • +
  • + a link to save a record of the confirmation, for examples as a + PDF +
  • +
  • + link to give feedback +
  • +
  • + contact details for the service +
  • +
  • + links to information or services that users are likely to need + next +
  • +
+
+
+
+ + ); +} + +export default ResultPage; diff --git a/src/examples/result-page/ResultPageExamples.tsx b/src/examples/result-page/ResultPageExamples.tsx index 572249381..86296988a 100644 --- a/src/examples/result-page/ResultPageExamples.tsx +++ b/src/examples/result-page/ResultPageExamples.tsx @@ -1,6 +1,5 @@ import { Sandbox } from "@components/sandbox"; import { CodeSnippet } from "@components/code-snippet/CodeSnippet.tsx"; -import "./result-page-example.css"; import { GoabBlock, GoabCallout } from "@abgov/react-components"; import { useContext } from "react"; import { LanguageVersionContext } from "@contexts/LanguageVersionContext.tsx"; @@ -8,16 +7,7 @@ import { LanguageVersionContext } from "@contexts/LanguageVersionContext.tsx"; export function ResultPageExamples() { const {version} = useContext(LanguageVersionContext); return ( -
-
-

Result page

- - View in Figma - -
+ {/*CSS Code Snippet*/} -
+ ); -} +} \ No newline at end of file diff --git a/src/examples/result-page/result-page-example.css b/src/examples/result-page/result-page-example.css deleted file mode 100644 index 0c6cb13de..000000000 --- a/src/examples/result-page/result-page-example.css +++ /dev/null @@ -1,4 +0,0 @@ -.result-page-example .page-header h2 { - margin-top: 0; - margin-bottom: 0; -} diff --git a/src/examples/reveal-more-information-to-help-answer-a-question.tsx b/src/examples/reveal-more-information-to-help-answer-a-question.tsx new file mode 100644 index 000000000..cd6d2cec8 --- /dev/null +++ b/src/examples/reveal-more-information-to-help-answer-a-question.tsx @@ -0,0 +1,73 @@ +import { Sandbox } from "@components/sandbox"; +import "./question-page/question-page-examples.css"; +import { CodeSnippet } from "@components/code-snippet/CodeSnippet.tsx"; +import { + GoabButton, GoabDetails, + GoabFormItem, + GoabRadioGroup, + GoabRadioItem +} from "@abgov/react-components"; +import { LanguageVersionContext } from "@contexts/LanguageVersionContext.tsx"; +import { useContext } from "react"; + +export default function RevealMoreInformationToHelpAnswerAQuestion() { + useContext(LanguageVersionContext); + return ( +
+ + + {/* + CSS Code Snippet*/} + ') 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); + } + `} + /> + + + Back + + + { + }}> + + + + + + +

We ask this question to determine if you are eligible for child care benefits.

+
+ + Save and continue + +
+ +
+ ); +} diff --git a/src/examples/container/ContainerReviewActionExample.tsx b/src/examples/review-and-action.tsx similarity index 98% rename from src/examples/container/ContainerReviewActionExample.tsx rename to src/examples/review-and-action.tsx index 131e8100c..79d5b8f9d 100644 --- a/src/examples/container/ContainerReviewActionExample.tsx +++ b/src/examples/review-and-action.tsx @@ -1,4 +1,4 @@ -import "./container-review-action-example.css"; +import "./container/container-review-action-example.css"; import { Sandbox } from "@components/sandbox"; import { CodeSnippet } from "@components/code-snippet/CodeSnippet.tsx"; import { @@ -11,7 +11,7 @@ import { import { useContext } from "react"; import { LanguageVersionContext } from "@contexts/LanguageVersionContext.tsx"; -export const ContainerReviewActionExample = () => { +export const ReviewAndAction = () => { const {version} = useContext(LanguageVersionContext); return ( @@ -182,3 +182,5 @@ export const ContainerReviewActionExample = () => { ) } + +export default ReviewAndAction; diff --git a/src/routes/patterns/ReviewPage.tsx b/src/examples/review-page.tsx similarity index 77% rename from src/routes/patterns/ReviewPage.tsx rename to src/examples/review-page.tsx index f21d2e6c5..65321a226 100644 --- a/src/routes/patterns/ReviewPage.tsx +++ b/src/examples/review-page.tsx @@ -1,16 +1,16 @@ import { GoabTab, - GoabTabs + GoabTabs, + GoabText } from "@abgov/react-components"; -import { ComponentContent } from "@components/component-content/ComponentContent"; -import css from "./patterns.module.css"; -import { ReviewPageExamples } from "@examples/review-page/ReviewPageExamples"; +import { ComponentContent } from "@components/component-content/ComponentContent.tsx"; +import css from "@routes/examples/patterns.module.css"; +import { ReviewPageExamples } from "@examples/review-page/ReviewPageExamples.tsx"; -export default function ReviewPage() { + +export function ReviewPage() { return ( <> -

Review page

-

Let users check answers before submitting information to a service.

@@ -31,28 +31,29 @@ export default function ReviewPage() {

When to use a review page

-

Review and submit your answers at the end of a form or section.

-

+ Review and submit your answers at the end of a form or + section. + When designing a very large transaction with multiple sections, it may help to include a check answers pages at the end of each section. -

+

Let users go back and change their answers

-

+ Provide a "change" link next to each section so that users can add or change the information they are submitting. -

-

+ + If you have questions that are optional, let users know that they've skipped it without giving an answer by showing their response as "Not provided". -

-

+ + Include the full question name again in the change button as "visually hidden" 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. -

+
); } + +export default ReviewPage; diff --git a/src/examples/review-page/ReviewPageExamples.tsx b/src/examples/review-page/ReviewPageExamples.tsx index dd5b5c827..e9a7d1df0 100644 --- a/src/examples/review-page/ReviewPageExamples.tsx +++ b/src/examples/review-page/ReviewPageExamples.tsx @@ -1,27 +1,16 @@ import { Sandbox } from "@components/sandbox"; import { CodeSnippet } from "@components/code-snippet/CodeSnippet.tsx"; -import "./review-page-example.css"; import { GoabButton, GoabButtonGroup, GoabTable } from "@abgov/react-components"; export function ReviewPageExamples() { return ( -
-
-

Review page

- - View in Figma - -
- - {/*CSS Code Snippet*/} - + {/*CSS Code Snippet*/} + -

Review your answers

-

Your situation

- - - - - What was your (the applicant's) relationship to the deceased? - - Other - - Change - - - - - My relationship to the deceased was - - Manager - - Change - - - - - - Was the deceased part of a household that was receiving Assured Income for the - Severely Handicapped (AISH) or Income Support? - - - No - - Change - - - - - Was the deceased a minor? - - No - - Change - - - - - What was the deceased's marital status at time of death? - - Married - - Change - - - - - Did the deceased have any dependents? - - No - - Change - - - - - Was the deceased a sponsored immigrant? - - Yes - - Change - - - - - - Confirm and continue - Back to application overview - -
-
+ /> +

Review your answers

+

Your situation

+ + + + + What was your (the applicant's) relationship to the deceased? + + Other + + Change + + + + + My relationship to the deceased was + + Manager + + Change + + + + + + Was the deceased part of a household that was receiving Assured Income for the + Severely Handicapped (AISH) or Income Support? + + + No + + Change + + + + + Was the deceased a minor? + + No + + Change + + + + + What was the deceased's marital status at time of death? + + Married + + Change + + + + + Did the deceased have any dependents? + + No + + Change + + + + + Was the deceased a sponsored immigrant? + + Yes + + Change + + + + + + Confirm and continue + Back to application overview + + ); -} +} \ No newline at end of file diff --git a/src/examples/review-page/review-page-example.css b/src/examples/review-page/review-page-example.css deleted file mode 100644 index 21a1d4420..000000000 --- a/src/examples/review-page/review-page-example.css +++ /dev/null @@ -1,8 +0,0 @@ -.review-page-example h2.section-title { - margin-top: 0; - margin-bottom: 0; -} -.review-page-example h2.section-title + h3 { - margin-top: var(--goa-space-l); - color: var(--goa-color-text-secondary); -} diff --git a/src/examples/text-field/TextFieldSearchExample.tsx b/src/examples/search.tsx similarity index 98% rename from src/examples/text-field/TextFieldSearchExample.tsx rename to src/examples/search.tsx index af41377aa..7fddace6c 100644 --- a/src/examples/text-field/TextFieldSearchExample.tsx +++ b/src/examples/search.tsx @@ -4,7 +4,7 @@ import { useContext } from "react"; import { LanguageVersionContext } from "@contexts/LanguageVersionContext.tsx"; import { CodeSnippet } from "@components/code-snippet/CodeSnippet.tsx"; -export const TextFieldSearchExample = () => { +export const Search = () => { const {version} = useContext(LanguageVersionContext); const noop = () => {} return ( @@ -89,3 +89,5 @@ export const TextFieldSearchExample = () => { ); } + +export default Search; diff --git a/src/examples/checkbox/CheckboxNoneOrManyExample.tsx b/src/examples/select-one-or-more-from-a-list-of-options.tsx similarity index 98% rename from src/examples/checkbox/CheckboxNoneOrManyExample.tsx rename to src/examples/select-one-or-more-from-a-list-of-options.tsx index 9dff6aadf..dbcd5e857 100644 --- a/src/examples/checkbox/CheckboxNoneOrManyExample.tsx +++ b/src/examples/select-one-or-more-from-a-list-of-options.tsx @@ -4,7 +4,7 @@ import { CodeSnippet } from "@components/code-snippet/CodeSnippet.tsx"; import { useContext } from "react"; import { LanguageVersionContext } from "@contexts/LanguageVersionContext.tsx"; -export default function CheckboxNoneOrManyExample () { +export default function SelectOneOrMoreFromAListOfOptions() { const {version} = useContext(LanguageVersionContext); return ( <> diff --git a/src/examples/set-a-max-width-on-a-long-radio-item.tsx b/src/examples/set-a-max-width-on-a-long-radio-item.tsx new file mode 100644 index 000000000..0f1ce1aa4 --- /dev/null +++ b/src/examples/set-a-max-width-on-a-long-radio-item.tsx @@ -0,0 +1,65 @@ +import { Sandbox } from "@components/sandbox"; +import { GoabFormItem, GoabRadioGroup, GoabRadioItem } from "@abgov/react-components"; +import { useContext, useState } from "react"; +import { LanguageVersionContext } from "@contexts/LanguageVersionContext.tsx"; +import { CodeSnippet } from "@components/code-snippet/CodeSnippet.tsx"; + +export const SetAMaxWidthOnALongRadioItem = () => { + const {version} = useContext(LanguageVersionContext); + const [selectOne, setSelectOne] = useState("1"); + return ( + + {/*We skipRenderOnly React because it is quite complex to remove value (2 els have value: radio-item and radio-group which radio-group is the one should remove value*/} + {version === "old" && ( + + setValue(value)}> + + + + + + `} + /> + )} + + {version === "new" && ( + + setValue(e.value)}> + + + + + + `} + /> + )} + +
+ + setSelectOne(e.value)}> + + + + + +
+
+ ); + +}; + +export default SetAMaxWidthOnALongRadioItem; diff --git a/src/examples/tabs/TabsSetSpecificTabActiveExample.tsx b/src/examples/set-a-specific-tab-to-be-active.tsx similarity index 98% rename from src/examples/tabs/TabsSetSpecificTabActiveExample.tsx rename to src/examples/set-a-specific-tab-to-be-active.tsx index 013e24101..c910cbcb9 100644 --- a/src/examples/tabs/TabsSetSpecificTabActiveExample.tsx +++ b/src/examples/set-a-specific-tab-to-be-active.tsx @@ -3,7 +3,7 @@ import { useContext } from "react"; import { LanguageVersionContext } from "@contexts/LanguageVersionContext.tsx"; import { CodeSnippet } from "@components/code-snippet/CodeSnippet.tsx"; -export const TabsSetSpecificTabActiveExample = () => { +export const SetASpecificTabToBeActive = () => { const review = [0, 1, 2, 3]; const complete = [0, 1]; const {version} = useContext(LanguageVersionContext); @@ -12,7 +12,7 @@ export const TabsSetSpecificTabActiveExample = () => { <>
- + @@ -113,7 +113,7 @@ export const TabsSetSpecificTabActiveExample = () => { tags="angular" allowCopy={true} code={` - +
All
@@ -208,7 +208,7 @@ export const TabsSetSpecificTabActiveExample = () => { tags="angular" allowCopy={true} code={` - + @@ -312,7 +312,7 @@ export const TabsSetSpecificTabActiveExample = () => { tags="react" allowCopy={true} code={` - + @@ -411,7 +411,7 @@ export const TabsSetSpecificTabActiveExample = () => { tags="react" allowCopy={true} code={` - + @@ -508,3 +508,5 @@ export const TabsSetSpecificTabActiveExample = () => { ) } + +export default SetASpecificTabToBeActive; diff --git a/src/examples/form-stepper/FormStepperStepStatusExample.tsx b/src/examples/set-the-status-of-step-on-a-form-stepper.tsx similarity index 96% rename from src/examples/form-stepper/FormStepperStepStatusExample.tsx rename to src/examples/set-the-status-of-step-on-a-form-stepper.tsx index 311e768db..8e79134e1 100644 --- a/src/examples/form-stepper/FormStepperStepStatusExample.tsx +++ b/src/examples/set-the-status-of-step-on-a-form-stepper.tsx @@ -6,16 +6,16 @@ import { GoabFormStepper, GoabPages, GoabSkeleton, - GoabSpacer, + GoabSpacer } from "@abgov/react-components"; import { useContext, useState } from "react"; import { LanguageVersionContext } from "@contexts/LanguageVersionContext.tsx"; import { GoabFormStepStatus } from "@abgov/ui-components-common"; -export const FormStepperStepStatusExample = () => { +export const SetTheStatusOfStepOnAFormStepper = () => { const { version } = useContext(LanguageVersionContext); const [statusStep, setStatusStep] = useState(-1); - const status: GoabFormStepStatus[] = ["complete", "complete", "incomplete", "not-started"]; + const status: GoabFormStepStatus[] = ["complete", "incomplete", "not-started"]; function setStatusPage(page: number) { if (page < 1 || page > 4) return; @@ -28,7 +28,7 @@ export const FormStepperStepStatusExample = () => { skipRender allow={["div"]} note={ - "The status of each step can be configured to “complete”, “incomplete” or ”not-started” using the status property." + "The status of each step can be configured to \"complete\", \"incomplete\" or \"not-started\" using the status property." }> {/*Angular code*/} {version === "old" && ( @@ -254,3 +254,5 @@ export const FormStepperStepStatusExample = () => { ); }; + +export default SetTheStatusOfStepOnAFormStepper; \ No newline at end of file diff --git a/src/examples/tooltip/TooltipShowLabelForIconOnlyButtonExample.tsx b/src/examples/show-a-label-on-an-icon-only-button.tsx similarity index 86% rename from src/examples/tooltip/TooltipShowLabelForIconOnlyButtonExample.tsx rename to src/examples/show-a-label-on-an-icon-only-button.tsx index 07f9444fa..d0939876f 100644 --- a/src/examples/tooltip/TooltipShowLabelForIconOnlyButtonExample.tsx +++ b/src/examples/show-a-label-on-an-icon-only-button.tsx @@ -1,7 +1,7 @@ import { Sandbox } from "@components/sandbox"; import { GoabButtonGroup, GoabIconButton, GoabTooltip } from "@abgov/react-components"; -export const TooltipShowLabelForIconOnlyButtonExample = () => { +export const ShowALabelOnAnIconOnlyButton = () => { return ( @@ -18,3 +18,5 @@ export const TooltipShowLabelForIconOnlyButtonExample = () => { ) } + +export default ShowALabelOnAnIconOnlyButton; diff --git a/src/examples/details/DetailsAdditionalInformationHelpUserExample.tsx b/src/examples/show-a-list-to-help-answer-a-question.tsx similarity index 90% rename from src/examples/details/DetailsAdditionalInformationHelpUserExample.tsx rename to src/examples/show-a-list-to-help-answer-a-question.tsx index 92e32e966..d7bff981f 100644 --- a/src/examples/details/DetailsAdditionalInformationHelpUserExample.tsx +++ b/src/examples/show-a-list-to-help-answer-a-question.tsx @@ -4,7 +4,7 @@ import { CodeSnippet } from "@components/code-snippet/CodeSnippet.tsx"; import { useContext } from "react"; import { LanguageVersionContext } from "@contexts/LanguageVersionContext.tsx"; -export const DetailsAdditionalInformationHelpUserExample = () => { +export const ShowAListToHelpAnswerAQuestion = () => { const {version} = useContext(LanguageVersionContext); const noop = () => {} @@ -43,14 +43,15 @@ export const DetailsAdditionalInformationHelpUserExample = () => { - + - +
Examples of education expenses @@ -77,3 +78,5 @@ export const DetailsAdditionalInformationHelpUserExample = () => { ) } + +export default ShowAListToHelpAnswerAQuestion; diff --git a/src/examples/show-a-notification-with-an-action.tsx b/src/examples/show-a-notification-with-an-action.tsx new file mode 100644 index 000000000..63c2008cb --- /dev/null +++ b/src/examples/show-a-notification-with-an-action.tsx @@ -0,0 +1,93 @@ +import { GoabButton } from "@abgov/react-components"; +import { CodeSnippet } from "@components/code-snippet/CodeSnippet.tsx"; +import { Sandbox } from "@components/sandbox"; +import { TemporaryNotification } from "@abgov/ui-components-common"; + +export const ShowANotificationWithAnAction = () => { + const comment = () => { + const uuid = TemporaryNotification.show( + "Edna Mode commented on your assigned case.", + { + actionText: "View", + action: () => { + TemporaryNotification.dismiss(uuid); + }, + } + ); + }; + + return ( + + Comment + + { + TemporaryNotification.dismiss(uuid); + }, + } + ); + } + } + `} + /> + + { + const uuid = TemporaryNotification.show( + "Edna Mode commented on your assigned case.", + { + actionText: "View", + action: () => { + TemporaryNotification.dismiss(uuid); + }, + } + ); + }; + `} + /> + + + + Comment + + `} + /> + + + + Comment + `} + /> + + ); +}; + +export default ShowANotificationWithAnAction; diff --git a/src/examples/show-a-notification.tsx b/src/examples/show-a-notification.tsx new file mode 100644 index 000000000..2bcdc9d60 --- /dev/null +++ b/src/examples/show-a-notification.tsx @@ -0,0 +1,79 @@ +import { GoabButton } from "@abgov/react-components"; +import { CodeSnippet } from "@components/code-snippet/CodeSnippet.tsx"; +import { Sandbox } from "@components/sandbox"; +import { TemporaryNotification } from "@abgov/ui-components-common"; + +export const ShowANotification = () => { + const save = () => { + TemporaryNotification.show("Your application has been saved.", { + type: "success" + }); + }; + + return ( + + Save + + + + { + await api.save(); + + TemporaryNotification.show("Your application has been saved.", { + type: "success" + }); + }; + `} + /> + + + + Save + + `} + /> + + + + Save + `} + /> + + ); +}; + +export default ShowANotification; diff --git a/src/examples/show-a-section-title-on-a-question-page.tsx b/src/examples/show-a-section-title-on-a-question-page.tsx new file mode 100644 index 000000000..547a04f51 --- /dev/null +++ b/src/examples/show-a-section-title-on-a-question-page.tsx @@ -0,0 +1,74 @@ +import { Sandbox } from "@components/sandbox"; +import "./question-page/question-page-examples.css"; +import { CodeSnippet } from "@components/code-snippet/CodeSnippet.tsx"; +import { + GoabButton, + GoabFormItem, + GoabRadioGroup, + GoabRadioItem +} from "@abgov/react-components"; +import { LanguageVersionContext } from "@contexts/LanguageVersionContext.tsx"; +import { useContext } from "react"; + +export default function ShowASectionTitleOnAQuestionPage() { + useContext(LanguageVersionContext); + return ( +
+ + + {/*CSS Code Snippet*/} + ') 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); + } + + h3.section-title { + margin-bottom: 0; + color: var(--goa-color-text-secondary); + } + + a.back-link + h3 { + margin-top: var(--goa-space-2xl); + } + `} + /> + + + Back + +

Personal information

+ + { + }}> + + + + + + Save and continue + +
+ +
+ ); +} diff --git a/src/examples/show-a-simple-progress-indicator-on-a-question-page-with-multiple-questions.tsx b/src/examples/show-a-simple-progress-indicator-on-a-question-page-with-multiple-questions.tsx new file mode 100644 index 000000000..86f93d65d --- /dev/null +++ b/src/examples/show-a-simple-progress-indicator-on-a-question-page-with-multiple-questions.tsx @@ -0,0 +1,222 @@ +import { Sandbox } from "@components/sandbox"; +import "./question-page/question-page-examples.css"; +import { CodeSnippet } from "@components/code-snippet/CodeSnippet.tsx"; +import { + GoabButton, + GoabFormItem, + GoabInput +} from "@abgov/react-components"; +import { LanguageVersionContext } from "@contexts/LanguageVersionContext.tsx"; +import { useContext } from "react"; + +export default function ShowASimpleProgressIndicatorOnAQuestionPageWithMultipleQuestions() { + const { version } = useContext(LanguageVersionContext); + return ( +
+ + + {/*CSS Code Snippet*/} + ') 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); + } + + h3.section-title { + margin-bottom: 0; + color: var(--goa-color-text-secondary); + } + + a.back-link + h3 { + margin-top: var(--goa-space-2xl); + } + + h3.section-title + h2 { + margin-top: var(--goa-space-xs); + } + `} + /> + + {/*Angular Code Snippet - need for leadingContent slot*/} + + {version === "old" && + Back + +

+ Step 1 of 5 +

+

+ Personal information +

+ + + + + +
+1
+
+
+ + + + + Save and continue + + `} + />} + + {version === "new" && + Back + +

+ Step 1 of 5 +

+

+ Personal information +

+ + + + + +
+1
+
+
+ + + + + Save and continue + + `} + />} + + {/*React Code Snippet - need for leadingContent slot*/} + {version === "old" && + Back + +

Step 1 of 5

+

Personal information

+ + {}} name="name" ariaLabel="what is your name?" width="50ch" /> + + + {}} + name="phone-number" + ariaLabel="what is your phone number?" + leadingContent="+1" + /> + + + {}} + name="postal-code" + width="14ch" + ariaLabel="what is your home postal code"> + + + Save and continue + + `} + />} + + {version === "new" && + Back + +

Step 1 of 5

+

Personal information

+ + {}} name="name" ariaLabel="what is your name?" width="50ch" /> + + + {}} + name="phone-number" + ariaLabel="what is your phone number?" + leadingContent="+1" + /> + + + {}} + name="postal-code" + width="14ch" + ariaLabel="what is your home postal code"> + + + Save and continue + + `} + />} + + + Back + +

Step 1 of 5

+

Personal information

+ + + { + }} name="name" ariaLabel="what is your name?" width="50ch" /> + + + { + }} + name="phone-number" + ariaLabel="what is your phone number?" + leadingContent="+1" + /> + + + { + }} + name="postal-code" + width="14ch" + ariaLabel="what is your home postal code"> + + + Save and continue + +
+
+ ); +} diff --git a/src/examples/show-a-simple-progress-indicator-on-a-question-page.tsx b/src/examples/show-a-simple-progress-indicator-on-a-question-page.tsx new file mode 100644 index 000000000..41d62dd56 --- /dev/null +++ b/src/examples/show-a-simple-progress-indicator-on-a-question-page.tsx @@ -0,0 +1,73 @@ +import { Sandbox } from "@components/sandbox"; +import "./question-page/question-page-examples.css"; +import { CodeSnippet } from "@components/code-snippet/CodeSnippet.tsx"; +import { + GoabButton, + GoabFormItem, + GoabRadioGroup, + GoabRadioItem +} from "@abgov/react-components"; +import { LanguageVersionContext } from "@contexts/LanguageVersionContext.tsx"; +import { useContext } from "react"; + +export default function ShowASimpleProgressIndicatorOnAQuestionPage() { + useContext(LanguageVersionContext); + return ( +
+ + + {/*CSS Code Snippet*/} + ') 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); + } + + a.back-link + h3 { + margin-top: var(--goa-space-2xl); + } + `} + /> + + Back + +

Question 3 of 9

+ + { + }}> + + + + + + Save and continue + +
+ +
+ ); +} diff --git a/src/examples/show-a-user-progress-when-the-time-is-unknown.tsx b/src/examples/show-a-user-progress-when-the-time-is-unknown.tsx new file mode 100644 index 000000000..280eb7dda --- /dev/null +++ b/src/examples/show-a-user-progress-when-the-time-is-unknown.tsx @@ -0,0 +1,175 @@ +import { GoabButton } from "@abgov/react-components"; +import { CodeSnippet } from "@components/code-snippet/CodeSnippet.tsx"; +import { Sandbox } from "@components/sandbox"; +import { TemporaryNotification } from "@abgov/ui-components-common"; + +export const ShowAUserProgressWhenTheTimeIsUnknown = () => { + + const sendApi = (isCancelledRef: { current: boolean; timeoutId?: number }) => { + return new Promise((_resolve, reject) => { + // Simulate search failure after random time (3-6 seconds) + const searchTime = Math.random() * 3000 + 3000; + const timeoutId = setTimeout(() => { + if (isCancelledRef.current) { + reject("cancelled"); + } else { + reject("error"); + } + }, searchTime); + + // Store timeout ID for potential cancellation + isCancelledRef.timeoutId = timeoutId as unknown as number; + }); + }; + + const search = () => { + const isCancelledRef: { current: boolean; timeoutId?: number } = { current: false }; + + const uuid = TemporaryNotification.show("Searching case management system...", { + type: "indeterminate", + actionText: "Cancel", + action: () => { + isCancelledRef.current = true; + if (isCancelledRef.timeoutId) { + clearTimeout(isCancelledRef.timeoutId); + } + TemporaryNotification.dismiss(uuid); + } + }); + + sendApi(isCancelledRef).then(() => { + // This won't be called since sendApi always rejects + }).catch((error) => { + if (error !== "cancelled") { + TemporaryNotification.show("Could not connect to case history", { + type: "failure", + duration: "medium", + cancelUUID: uuid + }); + } + }); + }; + + return ( + + + Search case history + + + { + // perform your API call here + } + + async search() { + const uuid = TemporaryNotification.show("Searching case management system...", { + type: "indeterminate", + actionText: "Cancel", + action: () => { + TemporaryNotification.dismiss(uuid); + }, + }); + + const err = await this.searchCMS(); + if (err) { + TemporaryNotification.show("Could not connect to case history", { + type: "failure", + duration: "medium", + cancelUUID: uuid + }); + } else { + TemporaryNotification.show("Search complete - 47 records found", { + type: "success", + duration: "medium", + actionText: "View", + action: () => { + console.log("View search results clicked!"); + }, + cancelUUID: uuid, + }); + } + } + } + `} + /> + + => { + // perform your API call here + }; + + const search = async () => { + const uuid = TemporaryNotification.show("Searching case management system...", { + type: "indeterminate", + actionText: "Cancel", + action: () => { + TemporaryNotification.dismiss(uuid); + }, + }); + + const err = await searchCMS(); + if (err) { + TemporaryNotification.show("Could not connect to case history", { + type: "failure", + duration: "medium", + cancelUUID: uuid + }); + } else { + TemporaryNotification.show("Search complete - 47 records found", { + type: "success", + duration: "medium", + actionText: "View", + action: () => { + console.log("View search results clicked!"); + }, + cancelUUID: uuid, + }); + } + }; + `} + /> + + + + + Search case history + + + `} + /> + + + + + Search case history + + `} + /> + + ); +}; + +export default ShowAUserProgressWhenTheTimeIsUnknown; diff --git a/src/examples/show-a-user-progress.tsx b/src/examples/show-a-user-progress.tsx new file mode 100644 index 000000000..70d6c39b1 --- /dev/null +++ b/src/examples/show-a-user-progress.tsx @@ -0,0 +1,208 @@ +import { GoabButton } from "@abgov/react-components"; +import { CodeSnippet } from "@components/code-snippet/CodeSnippet.tsx"; +import { Sandbox } from "@components/sandbox"; +import { TemporaryNotification } from "@abgov/ui-components-common"; + +export const ShowAUserProgress = () => { + + const sendApi = (progressCallback: (progress: number) => void, isCancelledRef: { current: boolean }) => { + return new Promise((resolve, reject) => { + let progress = 0; + const interval = setInterval(() => { + if (isCancelledRef.current) { + clearInterval(interval); + reject("cancelled"); + return; + } + + progress += 5; + progressCallback(progress); + + if (progress >= 100) { + clearInterval(interval); + resolve("success"); + } + }, 200); + }); + }; + + const downloadReport = () => { + const isCancelledRef = { current: false }; + + const uuid = TemporaryNotification.show("Downloading report D-23459", { + type: "progress", + actionText: "Cancel", + action: () => { + isCancelledRef.current = true; + TemporaryNotification.dismiss(uuid); + console.log("Download cancelled"); + } + }); + + TemporaryNotification.setProgress(uuid, 0); + + const updateProgress = (progress: number) => { + TemporaryNotification.setProgress(uuid, progress); + + if (progress >= 100) { + setTimeout(() => { + TemporaryNotification.show("Report downloaded", { + type: "success", + duration: "medium", + actionText: "View", + action: () => { + console.log("View report clicked!"); + }, + cancelUUID: uuid + }); + }, 300); + } + }; + + sendApi(updateProgress, isCancelledRef) + .catch(error => { + if (error !== "cancelled") { + TemporaryNotification.dismiss(uuid); + } + }); + }; + + return ( + + + Download report + + + { + // Perform your API call here with progress tracking + // Update progress as download progresses (0-100): setProgress(notificationUuid, 20) means 20% complete + TemporaryNotification.setProgress(notificationUuid, 25); + // ... continue API work ... + TemporaryNotification.setProgress(notificationUuid, 50); + // ... continue API work ... + TemporaryNotification.setProgress(notificationUuid, 75); + // ... complete API work ... + TemporaryNotification.setProgress(notificationUuid, 100); + } + + async download() { + const uuid = TemporaryNotification.show("Downloading report D-23459", { + type: "progress", + actionText: "Cancel", + action: () => { + TemporaryNotification.dismiss(uuid); + }, + }); + + const err = await this.downloadReport(uuid); + + if (err) { + TemporaryNotification.show("Download failed", { + type: "error", + duration: "medium", + cancelUUID: uuid + }); + } else { + TemporaryNotification.show("Report downloaded", { + type: "success", + duration: "medium", + actionText: "View", + action: () => { + console.log("View report clicked!"); + }, + cancelUUID: uuid, + }); + } + } + } + `} + /> + + => { + // Perform your API call here with progress tracking + // Update progress as download progresses (0-100): setProgress(notificationUuid, 20) means 20% complete + TemporaryNotification.setProgress(notificationUuid, 25); + // ... continue API work ... + TemporaryNotification.setProgress(notificationUuid, 50); + // ... continue API work ... + TemporaryNotification.setProgress(notificationUuid, 75); + // ... complete API work ... + TemporaryNotification.setProgress(notificationUuid, 100); + }; + + const downloadReport = async () => { + const uuid = TemporaryNotification.show("Downloading report D-23459", { + type: "progress", + actionText: "Cancel", + action: () => { + TemporaryNotification.dismiss(uuid); + }, + }); + + const err = await downloadReportAPI(uuid); + + if (err) { + TemporaryNotification.show("Download failed", { + type: "error", + duration: "medium", + cancelUUID: uuid + }); + } else { + TemporaryNotification.show("Report downloaded", { + type: "success", + duration: "medium", + actionText: "View", + action: () => { + console.log("View report clicked!"); + }, + cancelUUID: uuid, + }); + } + }; + `} + /> + + + + + Download report + + + `} + /> + + + + Download report + `} + /> + + ); +}; + +export default ShowAUserProgress; diff --git a/src/examples/tabs/TabsDifferentViewsTableExample.tsx b/src/examples/show-different-views-of-data-in-a-table.tsx similarity index 99% rename from src/examples/tabs/TabsDifferentViewsTableExample.tsx rename to src/examples/show-different-views-of-data-in-a-table.tsx index 063442ced..446867320 100644 --- a/src/examples/tabs/TabsDifferentViewsTableExample.tsx +++ b/src/examples/show-different-views-of-data-in-a-table.tsx @@ -3,7 +3,7 @@ import { useContext } from "react"; import { LanguageVersionContext } from "@contexts/LanguageVersionContext.tsx"; import { CodeSnippet } from "@components/code-snippet/CodeSnippet.tsx"; -export const TabsDifferentViewsTableExample = () => { +export const ShowDifferentViewsOfDataInATable = () => { const review = [0, 1, 2, 3]; const complete = [0, 1]; const {version} = useContext(LanguageVersionContext); @@ -12,7 +12,7 @@ export const TabsDifferentViewsTableExample = () => { <>
- + @@ -398,7 +398,7 @@ export const TabsDifferentViewsTableExample = () => { tags="react" allowCopy={true} code={` - + @@ -497,3 +497,5 @@ export const TabsDifferentViewsTableExample = () => { ) } + +export default ShowDifferentViewsOfDataInATable; diff --git a/src/examples/tooltip/TooltipShowFullDateExample.tsx b/src/examples/show-full-date-in-a-tooltip.tsx similarity index 98% rename from src/examples/tooltip/TooltipShowFullDateExample.tsx rename to src/examples/show-full-date-in-a-tooltip.tsx index 49dfd035f..b4ac6f493 100644 --- a/src/examples/tooltip/TooltipShowFullDateExample.tsx +++ b/src/examples/show-full-date-in-a-tooltip.tsx @@ -4,7 +4,7 @@ import { GoabContainer, GoabTooltip } from "@abgov/react-components"; import { useContext } from "react"; import { LanguageVersionContext } from "@contexts/LanguageVersionContext.tsx"; -export const TooltipShowFullDateExample = () => { +export const ShowFullDateInATooltip = () => { const {version} = useContext(LanguageVersionContext); return ( @@ -109,3 +109,5 @@ export const TooltipShowFullDateExample = () => { ) } + +export default ShowFullDateInATooltip; diff --git a/src/examples/app-footer/AppFooterShowNavigationItemsExample.tsx b/src/examples/show-links-to-navigation-items.tsx similarity index 98% rename from src/examples/app-footer/AppFooterShowNavigationItemsExample.tsx rename to src/examples/show-links-to-navigation-items.tsx index 6e37da23a..9234e49e3 100644 --- a/src/examples/app-footer/AppFooterShowNavigationItemsExample.tsx +++ b/src/examples/show-links-to-navigation-items.tsx @@ -17,7 +17,7 @@ type CastingType = { [key: string]: unknown; }; -export const AppFooterShowNavigationItemsExample = () => { +export const ShowLinksToNavigationItems = () => { const {version} = useContext(LanguageVersionContext); const [appFooterNavBindings, setAppFooterNavBindings] = useState([ @@ -201,3 +201,5 @@ export const AppFooterShowNavigationItemsExample = () => { ) } + +export default ShowLinksToNavigationItems; diff --git a/src/examples/show-number-of-results-per-page.tsx b/src/examples/show-number-of-results-per-page.tsx new file mode 100644 index 000000000..6764a0140 --- /dev/null +++ b/src/examples/show-number-of-results-per-page.tsx @@ -0,0 +1,576 @@ +import { Sandbox } from "@components/sandbox"; +import { CodeSnippet } from "@components/code-snippet/CodeSnippet.tsx"; +import { + GoabBlock, + GoabDropdown, + GoabDropdownItem, + GoabPagination, + GoabSpacer, + GoabTable +} from "@abgov/react-components"; +import { useContext, useEffect, useState } from "react"; +import { LanguageVersionContext } from "@contexts/LanguageVersionContext.tsx"; +import { GoabDropdownOnChangeDetail } from "@abgov/ui-components-common"; +import { faker } from "@faker-js/faker"; + +interface User { + id: string; + firstName: string; + lastName: string; + age: number; +} + +export default function ShowResultsPerPageExample() { + const { version } = useContext(LanguageVersionContext); + const [users, setUsers] = useState([]); + const [pageUsers, setPageUsers] = useState([]); + const [page, setPage] = useState(1); + const [perPage, setPerPage] = useState(10); + + useEffect(() => { + const _users = []; + for (let i = 1; i <= 100; i++) { + _users.push({ + id: faker.string.uuid(), + firstName: faker.person.firstName(), + lastName: faker.person.lastName(), + age: faker.number.int({ min: 18, max: 60 }) + }); + } + setUsers(_users); + setPageUsers(_users.slice(0, perPage)); + }, [perPage]); + + function changePage(newPage: number) { + const offset = (newPage - 1) * perPage; + const _users = users.slice(offset, offset + perPage); + setPage(newPage); + setPageUsers(_users); + } + + function handlePerPageCountChangeEvent(event: GoabDropdownOnChangeDetail) { + const perPageValue = parseInt(event.value || "1"); + setPage(1); + setPerPage(perPageValue); + const _users = users.slice(0, perPageValue); + setPageUsers(_users); + } + + return ( + <> + + + {/*============= React code ==============*/} + {version === "old" && ( + ([]); + const [pageUsers, setPageUsers] = useState([]); + const [page, setPage] = useState(1); + const [perPage, setPerPage] = useState(10); + + useEffect(() => { + const _users = []; + for (let i = 1; i <= 100; i++) { + _users.push({ + id: faker.datatype.uuid(), + firstName: faker.name.firstName(), + lastName: faker.name.lastName(), + age: faker.datatype.number({ min: 18, max: 60 }), + }); + } + setUsers(_users); + setPageUsers(_users.slice(0, perPage)); + }, [perPage]); + + function changePage(newPage: number) { + const offset = (newPage - 1) * 10; + const _users = users.slice(offset, offset + perPage); + setPage(newPage); + setPageUsers(_users); + } + + function handlePerPageCountChangeEvent(name: string, value: string | string[]) { + const perPageValue = Array.isArray(value) ? parseInt(value[0]) : parseInt(value); + setPage(1); + setPerPage(perPageValue); + const _users = users.slice(0, perPageValue); + setPageUsers(_users); + } + `} + /> + )} + + {version === "new" && ( + ([]); + const [pageUsers, setPageUsers] = useState([]); + const [page, setPage] = useState(1); + const [perPage, setPerPage] = useState(10); + + useEffect(() => { + const _users = []; + for (let i = 1; i <= 100; i++) { + _users.push({ + id: faker.string.uuid(), + firstName: faker.person.firstName(), + lastName: faker.person.lastName(), + age: faker.number.int({ min: 18, max: 60 }), + }); + } + setUsers(_users); + setPageUsers(_users.slice(0, perPage)); + }, [perPage]); + + function changePage(newPage: number) { + const offset = (newPage - 1) * 10; + const _users = users.slice(offset, offset + perPage); + setPage(newPage); + setPageUsers(_users); + } + + function handlePerPageCountChangeEvent(event: GoabDropdownOnChangeDetail) { + const perPageValue = parseInt(event.value || '1'); + setPage(1); + setPerPage(perPageValue); + const _users = users.slice(0, perPageValue); + setPageUsers(_users); + } + `} + /> + )} + + {version === "old" && ( + + + + First name + Last name + Age + + + + {pageUsers.map((u) => ( + + {u.firstName} + {u.lastName} + {u.age} + + ))} + + + + + + Show + + + + + + of {users.length} + + + + + + + `} + /> + )} + + {version === "new" && ( + + + + First name + Last name + Age + + + + {pageUsers.map((u) => ( + + {u.firstName} + {u.lastName} + {u.age} + + ))} + + + + + + Show + + + + + + of {users.length} + + + + + changePage(event.page)} + /> + + `} + /> + )} + + {/*================ Angular code ==================*/} + {version === "old" && ( + + )} + + {version === "new" && ( + + )} + + {version === "old" && ( + + + + First name + Last name + Age + + + + + {{ user.firstName }} + {{ user.lastName }} + {{ user.age }} + + + + + + + Show + + + + + + + + + + + + + + of {{ this.users.length }} + + + + + + + + + `} + /> + )} + + {version === "new" && ( + + + + First name + Last name + Age + + + + + {{ user.firstName }} + {{ user.lastName }} + {{ user.age }} + + + + + + + Show + + + + + + + + + + + + + of {{ this.users.length }} + + + + + + + + `} + /> + )} + + + + + First name + Last name + Age + + + + {pageUsers.map(u => ( + + {u.firstName} + {u.lastName} + {u.age} + + ))} + + + + + + Show + + {[10, 20, 30].map(value => ( + + ))} + + per page + + + + changePage(event.page)} + /> + + + + ); +} \ No newline at end of file diff --git a/src/examples/app-footer/AppFooterShowQuickLinkExample.tsx b/src/examples/show-quick-links.tsx similarity index 98% rename from src/examples/app-footer/AppFooterShowQuickLinkExample.tsx rename to src/examples/show-quick-links.tsx index f62cd2baa..06448d04e 100644 --- a/src/examples/app-footer/AppFooterShowQuickLinkExample.tsx +++ b/src/examples/show-quick-links.tsx @@ -4,7 +4,7 @@ import { GoabAppFooter, GoabAppFooterMetaSection } from "@abgov/react-components import { useContext } from "react"; import { LanguageVersionContext } from "@contexts/LanguageVersionContext.tsx"; -export const AppFooterShowQuickLinkExample = () => { +export const ShowQuickLinks = () => { const {version} = useContext(LanguageVersionContext); return ( @@ -118,3 +118,5 @@ export const AppFooterShowQuickLinkExample = () => { ) } + +export default ShowQuickLinks; diff --git a/src/examples/badge/BadgeShowStatusInTableExample.tsx b/src/examples/show-status-in-a-table.tsx similarity index 99% rename from src/examples/badge/BadgeShowStatusInTableExample.tsx rename to src/examples/show-status-in-a-table.tsx index 1e633f38b..7b6f56499 100644 --- a/src/examples/badge/BadgeShowStatusInTableExample.tsx +++ b/src/examples/show-status-in-a-table.tsx @@ -5,7 +5,7 @@ import { GoabBadgeType } from "@abgov/ui-components-common"; import { LanguageVersionContext } from "@contexts/LanguageVersionContext.tsx"; import { useContext } from "react"; -export const BadgeShowStatusInTableExample = () => { +export const ShowStatusInATable = () => { const noop = () => {}; const {version} = useContext(LanguageVersionContext); const badgeValues = [ @@ -328,3 +328,5 @@ export const BadgeShowStatusInTableExample = () => { ) } + +export default ShowStatusInATable; diff --git a/src/examples/badge/BadgeShowStatusOnCardExample.tsx b/src/examples/show-status-on-a-card.tsx similarity index 97% rename from src/examples/badge/BadgeShowStatusOnCardExample.tsx rename to src/examples/show-status-on-a-card.tsx index 66ff7288a..4e032182f 100644 --- a/src/examples/badge/BadgeShowStatusOnCardExample.tsx +++ b/src/examples/show-status-on-a-card.tsx @@ -4,7 +4,7 @@ import { GoabBadge, GoabContainer } from "@abgov/react-components"; import { useContext } from "react"; import { LanguageVersionContext } from "@contexts/LanguageVersionContext.tsx"; -export const BadgeShowStatusOnCardExample = () => { +export const ShowStatusOnACard = () => { const {version} = useContext(LanguageVersionContext); return ( @@ -78,3 +78,5 @@ export const BadgeShowStatusOnCardExample = () => { ) } + +export default ShowStatusOnACard; diff --git a/src/examples/show-version-number.tsx b/src/examples/show-version-number.tsx new file mode 100644 index 000000000..2c16a9e97 --- /dev/null +++ b/src/examples/show-version-number.tsx @@ -0,0 +1,22 @@ +import { GoabMicrositeHeader } from "@abgov/react-components"; +import { Sandbox } from "@components/sandbox"; + +export default function ShowVersionNumberExample() { + + return ( + <> + + {/* ...React + Angular code snippets here (same as original)... */} + + Slotted version text. + v1.23 + + } + /> + + + ); +} \ No newline at end of file diff --git a/src/examples/form-item/FormItemSlottedErrorTextExample.tsx b/src/examples/slotted-error-text-in-a-form-item.tsx similarity index 95% rename from src/examples/form-item/FormItemSlottedErrorTextExample.tsx rename to src/examples/slotted-error-text-in-a-form-item.tsx index 7450f1805..b8f7ecc4c 100644 --- a/src/examples/form-item/FormItemSlottedErrorTextExample.tsx +++ b/src/examples/slotted-error-text-in-a-form-item.tsx @@ -4,7 +4,7 @@ import { CodeSnippet } from "@components/code-snippet/CodeSnippet.tsx"; import { useContext } from "react"; import { LanguageVersionContext } from "@contexts/LanguageVersionContext.tsx"; -export const FormItemSlottedErrorTextExample = () => { +export const SlottedErrorTextInAFormItem = () => { const { version } = useContext(LanguageVersionContext); const errorReactNode: React.ReactNode = ( <> @@ -16,7 +16,7 @@ export const FormItemSlottedErrorTextExample = () => { return ( - + {/* *********** React code ************/} @@ -118,3 +118,5 @@ export const FormItemSlottedErrorTextExample = () => { ); }; + +export default SlottedErrorTextInAFormItem; \ No newline at end of file diff --git a/src/examples/form-item/FormItemSlottedHelperTextExample.tsx b/src/examples/slotted-helper-text-in-a-form-item.tsx similarity index 96% rename from src/examples/form-item/FormItemSlottedHelperTextExample.tsx rename to src/examples/slotted-helper-text-in-a-form-item.tsx index 1ecfb1a65..e00e4e7fa 100644 --- a/src/examples/form-item/FormItemSlottedHelperTextExample.tsx +++ b/src/examples/slotted-helper-text-in-a-form-item.tsx @@ -4,7 +4,7 @@ import { CodeSnippet } from "@components/code-snippet/CodeSnippet.tsx"; import { useContext } from "react"; import { LanguageVersionContext } from "@contexts/LanguageVersionContext.tsx"; -export const FormItemSlottedHelperTextExample = () => { +export const SlottedHelperTextInAFormItem = () => { const {version} = useContext(LanguageVersionContext); const noop = () => {} const reactNode = <>This is slotted help text.; @@ -94,3 +94,5 @@ export const FormItemSlottedHelperTextExample = () => { ) } + +export default SlottedHelperTextInAFormItem; diff --git a/src/examples/start-page.tsx b/src/examples/start-page.tsx new file mode 100644 index 000000000..9852a7814 --- /dev/null +++ b/src/examples/start-page.tsx @@ -0,0 +1,172 @@ +import { + GoabGrid, GoabTab, GoabTabs, GoabText +} from "@abgov/react-components"; + +import css from "@routes/examples/patterns.module.css"; +import { ComponentContent } from "@components/component-content/ComponentContent.tsx"; +import { StartPageExamples } from "@examples/start-page/StartPageExamples.tsx"; + +export function StartPage() { + + return ( + + + + + + + + + +
+

+ When to use a start page +

+ + When to use a start page + + + 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. + + + This is the starting point for a citizen to begin your form from within your service + or from Alberta.ca. + + + Provide the user with any information that is important before starting the form such + as how long it should take, list documents or information they may need to complete + the form, if there are any costs involved, or alternative ways to access the service. + +
+
+ form pattern start page image +
+
+

A service's start page should

+
    +
  • + + give the user just enough information to help them understand what the service does + and whether it will meet their need + +
  • +
  • + + a service's name should reflects the problem it solves for users + +
  • +
  • + + be written in plain language — GOA + web writing style guide. + +
  • +
  • + + include a "start button" linking into the service, with text that's consistent with + the action you're asking users to take — for example, "Start now", "Sign in" or + "Register or update your details" + +
  • +
  • + + a service's name should reflects the problem it solves for users + +
  • +
  • + + 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 the + service (eg. 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 +

+ + Page content + + + Consider what is the primary information that the user needs to know before entering + into the service. Provide that information to the user clearly, and 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 into the service. A high level description of what the + service + is and what you can use it to do + + +

Before you begin

+
    +
  • + + how long it will take + +
  • +
  • + + what you 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. + +
+
+ service page content image +
+
+ +
+
+
+ ); +} + +export default StartPage; diff --git a/src/examples/start-page/StartPageExamples.tsx b/src/examples/start-page/StartPageExamples.tsx index 681524ed6..1f37066de 100644 --- a/src/examples/start-page/StartPageExamples.tsx +++ b/src/examples/start-page/StartPageExamples.tsx @@ -1,31 +1,20 @@ import { Sandbox } from "@components/sandbox"; import { - GoabButton, + GoabButton } from "@abgov/react-components"; import { CodeSnippet } from "@components/code-snippet/CodeSnippet.tsx"; -import "./start-page-example.css"; import { useContext } from "react"; import { LanguageVersionContext } from "@contexts/LanguageVersionContext.tsx"; export function StartPageExamples() { - const {version} = useContext(LanguageVersionContext); + const { version } = useContext(LanguageVersionContext); return ( -
-
-

Start page from Alberta.ca

- - View in Figma - -
- - + + /> - {/*Angular code*/} + {/*Angular code*/} - {version === "old" && Name of service @@ -74,13 +63,13 @@ export function StartPageExamples() {

Support

For assistance, email us at  help@gov.ab.ca

`} - />} + />} - {version === "new" && Name of service @@ -109,15 +98,15 @@ export function StartPageExamples() {

Support

For assistance, email us at  help@gov.ab.ca

`} - />} + />} - {/*React code*/} + {/*React code*/} - {version === "old" && Name of service @@ -148,13 +137,13 @@ export function StartPageExamples() {

Support

For assistance, email us at  help@gov.ab.ca

`} - />} + />} - {version === "new" && Name of service @@ -185,45 +174,45 @@ export function StartPageExamples() {

Support

For assistance, email us at  help@gov.ab.ca

`} - />} + />} -

Name of service

-

- A short overview of the service. This is a couple sentences that helps the user understand - what the service is. -

-

Use this service to apply for [service]. You can use this service to:

-
    -
  • see of you or a family member is eligible for [service]
  • -
  • create and submit an application for [service]
  • -
  • continue an application for [service] that you already started
  • -
+

Name of service

+

+ A short overview of the service. This is a couple sentences that helps the user understand + what the service is. +

+

Use this service to apply for [service]. You can use this service to:

+
    +
  • see of you or a family member is eligible for [service]
  • +
  • create and submit an application for [service]
  • +
  • continue an application for [service] that you already started
  • +
-

Before you begin

-

The application form should take about 20 minutes to complete.

-

- In order to complete the application you will need: -

-
    -
  • government issued ID for the person applying
  • -
- {}}> - Get started - +

Before you begin

+

The application form should take about 20 minutes to complete.

+

+ In order to complete the application you will need: +

+
    +
  • government issued ID for the person applying
  • +
+ { + }}> + Get started + -

Other information about the service

-

- This section contains supplementary details about the service, including descriptions of - less common scenarios, exceptions, and additional resources available. It provides context - and additional insights that may be relevant to your specific circumstances or interests, - helping you understand the full scope and utility of the service offered. -

+

Other information about the service

+

+ This section contains supplementary details about the service, including descriptions of + less common scenarios, exceptions, and additional resources available. It provides context + and additional insights that may be relevant to your specific circumstances or interests, + helping you understand the full scope and utility of the service offered. +

-

Support

-

- For assistance, email us at  help@gov.ab.ca -

-
-
+

Support

+

+ For assistance, email us at  help@gov.ab.ca +

+ ); -} +} \ No newline at end of file diff --git a/src/examples/start-page/start-page-example.css b/src/examples/start-page/start-page-example.css deleted file mode 100644 index 5eef5e757..000000000 --- a/src/examples/start-page/start-page-example.css +++ /dev/null @@ -1,10 +0,0 @@ -.start-page-example h1.page-title { - margin-bottom: var(--goa-space-l); -} -.start-page-example h2 { - margin-top: var(--goa-space-xl); - margin-bottom: 0; -} -.start-page-example h2 + p { - margin-top: var(--goa-space-l); -} diff --git a/src/examples/tabs/TabsExamples.tsx b/src/examples/tabs/TabsExamples.tsx index b5cd77c45..06f06ee8f 100644 --- a/src/examples/tabs/TabsExamples.tsx +++ b/src/examples/tabs/TabsExamples.tsx @@ -1,5 +1,5 @@ -import { TabsDifferentViewsTableExample } from "@examples/tabs/TabsDifferentViewsTableExample.tsx"; -import { TabsSetSpecificTabActiveExample } from "@examples/tabs/TabsSetSpecificTabActiveExample.tsx"; +import { ShowDifferentViewsOfDataInATable } from "@examples/show-different-views-of-data-in-a-table.tsx"; +import { SetASpecificTabToBeActive } from "@examples/set-a-specific-tab-to-be-active.tsx"; import { SandboxHeader } from "@components/sandbox/sandbox-header/sandboxHeader.tsx"; export const TabsExamples = () => { @@ -9,13 +9,13 @@ export const TabsExamples = () => { exampleTitle="Show different views of data in a table" figmaExample="https://www.figma.com/design/aIRjvBzpIUH0GbkffjbL04/%E2%9D%96-Patterns-library-%7C-DDD?node-id=6311-135722&t=X0IQW5flDDaj8Vyg-4"> - + - + ) diff --git a/src/examples/task-list-page.tsx b/src/examples/task-list-page.tsx new file mode 100644 index 000000000..799bec3ee --- /dev/null +++ b/src/examples/task-list-page.tsx @@ -0,0 +1,152 @@ +import { + GoabCallout, + GoabTab, + GoabTabs, + GoabText +} from "@abgov/react-components"; +import { ComponentContent } from "@components/component-content/ComponentContent.tsx"; +import css from "@routes/examples/patterns.module.css"; +import { Link } from "react-router-dom"; +import { TaskListPageExamples } from "@examples/task-list-page/TaskListPageExamples.tsx"; + +export function TaskListPage() { + return ( + <> + + + + + + + +
+

+ Overview +

+ task list page overview image +
+ +

When to use a task list page

+ + 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. + + + When using a task list, group related actions into tasks and show the status of the tasks. + + +

How to define a task

+ + 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 can be as big as an entire + section of a form with multiple question pages and a review page. + + + 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. + + +
+ show status of tasks image +
+ +

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. + + +
+ + You have completed 0 of 3 sections. + +
+ +

How is a task list different than 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

+
+ status page anatomy image +
+
    +
  1. + + Page tile: heading-large + +
  2. +
  3. + + Status of completed sections: goa-callout + +
  4. +
  5. + + Section: task-list-section + +
  6. +
  7. + + Section heading: heading-medium + +
  8. +
  9. + + Task: goa-table + +
  10. +
+
+
+
+ + ); +} + +export default TaskListPage; diff --git a/src/examples/task-list-page/TaskListPageExamples.tsx b/src/examples/task-list-page/TaskListPageExamples.tsx index b0cc6b96a..5ddf96497 100644 --- a/src/examples/task-list-page/TaskListPageExamples.tsx +++ b/src/examples/task-list-page/TaskListPageExamples.tsx @@ -1,24 +1,16 @@ import { Sandbox } from "@components/sandbox"; import { GoabBadge, GoabCallout, GoabTable } from "@abgov/react-components"; -import "./task-list-page-example.css"; import { CodeSnippet } from "@components/code-snippet/CodeSnippet.tsx"; export function TaskListPageExamples() { return ( -
-
-

Task list page

- - View in Figma - -
- - {/*CSS Code Snippet*/} - + {/*CSS Code Snippet*/} + -

Apply for a service

-
- - You have completed 1 of 3 sections. - -
+ /> +

Apply for a service

+
+ + You have completed 1 of 3 sections. + +
-

1. Before you start

- - - - - Reads terms of use - - - - - - - +

1. Before you start

+ + + + + Reads terms of use + + + + + + + -

2. Prepare application

- - - - - Your contact details - - - - - - - - Your family - - - - - - - - Verify your identity - - - - - - - +

2. Prepare application

+ + + + + Your contact details + + + + + + + + Your family + + + + + + + + Verify your identity + + + + + + + -

3. Schedule service

-

- You need to complete the previous section before you can start this task. -

- - - - Receive email confirmation - - - - - - Pay service fee - - - - - - -
-
+

3. Schedule service

+

+ You need to complete the previous section before you can start this task. +

+ + + + Receive email confirmation + + + + + + Pay service fee + + + + + + + ); -} +} \ No newline at end of file diff --git a/src/examples/temporary-notification/TemporaryNotificationExamples.tsx b/src/examples/temporary-notification/TemporaryNotificationExamples.tsx new file mode 100644 index 000000000..eab001668 --- /dev/null +++ b/src/examples/temporary-notification/TemporaryNotificationExamples.tsx @@ -0,0 +1,37 @@ +import { SandboxHeader } from "@components/sandbox/sandbox-header/sandboxHeader.tsx"; +import { ShowANotification } from "@examples/show-a-notification.tsx"; +import { ShowAUserProgress } from "@examples/show-a-user-progress.tsx"; +import { ShowAUserProgressWhenTheTimeIsUnknown } from "@examples/show-a-user-progress-when-the-time-is-unknown.tsx"; +import { ShowANotificationWithAnAction } from "@examples/show-a-notification-with-an-action.tsx"; + +export const TemporaryNotificationExamples = () => { + return ( + <> + + + + + + + + + + + + + + + + + ); +}; + +export default TemporaryNotificationExamples; diff --git a/src/examples/text-field/TextFieldExamples.tsx b/src/examples/text-field/TextFieldExamples.tsx index 83c1df74e..94179cc0a 100644 --- a/src/examples/text-field/TextFieldExamples.tsx +++ b/src/examples/text-field/TextFieldExamples.tsx @@ -1,10 +1,12 @@ -import { TextFieldAskBirthdayExample } from "@examples/text-field/TextFieldAskBirthdayExample.tsx"; -import { TextFieldSearchExample } from "@examples/text-field/TextFieldSearchExample.tsx"; -import { TextFieldAskUserAmountExample } from "@examples/text-field/TextFieldAskUserAmountExample.tsx"; -import { TextFieldAskUserIndianRegistrationExample } from "@examples/text-field/TextFieldAskUserIndianRegistrationExample.tsx"; +import { AskAUserForABirthday } from "@examples/ask-a-user-for-a-birthday.tsx"; +import { Search } from "@examples/search.tsx"; +import { AskAUserForDollarAmounts } from "@examples/ask-a-user-for-dollar-amounts.tsx"; +import { + AskAUserForAnIndianRegistrationNumber +} from "@examples/ask-a-user-for-an-indian-registration-number.tsx"; import { TextFieldRightAlignExample } from "@examples/text-field/TextFieldRightAlignExample.tsx"; import { SandboxHeader } from "@components/sandbox/sandbox-header/sandboxHeader.tsx"; -import { ButtonAskUserAddressExample } from "@examples/button/ButtonAskUserAddressExample.tsx"; +import { AskAUserForAnAddress } from "@examples/ask-a-user-for-an-address.tsx"; export default function TextFieldExamples() { return ( @@ -12,33 +14,39 @@ export default function TextFieldExamples() { {/*Examples*/} - + figmaExample="https://www.figma.com/design/aIRjvBzpIUH0GbkffjbL04/%E2%9D%96-Patterns-library-%7C-DDD?node-id=6304-43250&t=X0IQW5flDDaj8Vyg-4"> + + - + figmaExample="https://www.figma.com/design/aIRjvBzpIUH0GbkffjbL04/%E2%9D%96-Patterns-library-%7C-DDD?node-id=6334-80568&t=X0IQW5flDDaj8Vyg-44"> + + - + figmaExample="https://www.figma.com/design/aIRjvBzpIUH0GbkffjbL04/%E2%9D%96-Patterns-library-%7C-DDD?node-id=6311-68872&t=X0IQW5flDDaj8Vyg-4"> + + - + figmaExample="https://www.figma.com/design/aIRjvBzpIUH0GbkffjbL04/%E2%9D%96-Patterns-library-%7C-DDD?node-id=1896-179629&t=X0IQW5flDDaj8Vyg-4"> + + + figmaExample="https://www.figma.com/design/aIRjvBzpIUH0GbkffjbL04/%E2%9D%96-Patterns-library-%7C-DDD?node-id=1896-179633&t=X0IQW5flDDaj8Vyg-4"> + - + figmaExample="https://www.figma.com/design/aIRjvBzpIUH0GbkffjbL04/%E2%9D%96-Patterns-library-%7C-DDD?node-id=1896-179631&t=X0IQW5flDDaj8Vyg-4"> + + ); -} +} \ No newline at end of file diff --git a/src/examples/textarea/TextAreaAskLongQuestionExample.tsx b/src/examples/textarea/TextAreaAskLongQuestionExample.tsx deleted file mode 100644 index a09628a04..000000000 --- a/src/examples/textarea/TextAreaAskLongQuestionExample.tsx +++ /dev/null @@ -1,20 +0,0 @@ -import { Sandbox } from "@components/sandbox"; -import { - GoabFormItem, - GoabTextarea -} from "@abgov/react-components"; - -export const TextAreaAskLongQuestionExample = () => { - const noop = () => {} - return ( - - - - - - - - ) -} diff --git a/src/examples/textarea/TextAreaExamples.tsx b/src/examples/textarea/TextAreaExamples.tsx index 59e2ce599..d81186898 100644 --- a/src/examples/textarea/TextAreaExamples.tsx +++ b/src/examples/textarea/TextAreaExamples.tsx @@ -1,8 +1,9 @@ import { - TextAreaAskQuestionMoreInformationExample -} from "@examples/textarea/TextAreaAskQuestionMoreInformationExample.tsx"; - -import { TextAreaAskLongQuestionExample } from "@examples/textarea/TextAreaAskLongQuestionExample.tsx"; + GiveContextBeforeAskingALongAnswerQuestion +} from "@examples/give-context-before-asking-a-long-answer-question.tsx"; +import { + AskALongAnswerQuestionWithAMaximumWordCount +} from "@examples/ask-a-long-answer-question-with-a-maximum-word-count.tsx"; import { SandboxHeader } from "@components/sandbox/sandbox-header/sandboxHeader.tsx"; export const TextAreaExamples = () => { @@ -12,13 +13,13 @@ export const TextAreaExamples = () => { exampleTitle="Ask a question and give more information" figmaExample="https://www.figma.com/design/aIRjvBzpIUH0GbkffjbL04/%E2%9D%96-Patterns-library-%7C-DDD?node-id=6311-137633&t=X0IQW5flDDaj8Vyg-4"> - + - + ) } diff --git a/src/examples/tooltip/TooltipExamples.tsx b/src/examples/tooltip/TooltipExamples.tsx index 0cb27006b..3ee7c7b46 100644 --- a/src/examples/tooltip/TooltipExamples.tsx +++ b/src/examples/tooltip/TooltipExamples.tsx @@ -1,7 +1,7 @@ -import { TooltipShowFullDateExample } from "@examples/tooltip/TooltipShowFullDateExample.tsx"; +import { ShowFullDateInATooltip } from "@examples/show-full-date-in-a-tooltip.tsx"; import { - TooltipShowLabelForIconOnlyButtonExample -} from "@examples/tooltip/TooltipShowLabelForIconOnlyButtonExample.tsx"; + ShowALabelOnAnIconOnlyButton +} from "@examples/show-a-label-on-an-icon-only-button.tsx"; import { SandboxHeader } from "@components/sandbox/sandbox-header/sandboxHeader.tsx"; export const TooltipExamples = () => { @@ -12,13 +12,13 @@ export const TooltipExamples = () => { exampleTitle="Show a full date when shortened" figmaExample=""> - + - + {/* This example won't import from styling.ts for some reason...

Click to copy something to your clipboard

diff --git a/src/examples/filter-chip/FilterChipTypedChipExample.tsx b/src/examples/type-to-create-a-new-filter.tsx similarity index 99% rename from src/examples/filter-chip/FilterChipTypedChipExample.tsx rename to src/examples/type-to-create-a-new-filter.tsx index 9c892bcf3..520de6dd0 100644 --- a/src/examples/filter-chip/FilterChipTypedChipExample.tsx +++ b/src/examples/type-to-create-a-new-filter.tsx @@ -4,7 +4,7 @@ import { useContext, useState } from "react"; import { LanguageVersionContext } from "@contexts/LanguageVersionContext.tsx"; import { GoabInputOnChangeDetail, GoabInputOnKeyPressDetail } from "@abgov/ui-components-common"; -export const FilterChipTypedChipExample = () => { +export const TypeToCreateANewFilter = () => { const {version} = useContext(LanguageVersionContext); const [typedChips, setTypedChips] = useState([]); const [inputValue, setInputValue] = useState(""); @@ -323,3 +323,5 @@ export class FilterChipComponent { // ); } + +export default TypeToCreateANewFilter; \ No newline at end of file diff --git a/src/examples/modal/ModalWarnUserDeadlineExample.tsx b/src/examples/warn-a-user-of-a-deadline.tsx similarity index 98% rename from src/examples/modal/ModalWarnUserDeadlineExample.tsx rename to src/examples/warn-a-user-of-a-deadline.tsx index ffb42a4a3..d15c0f066 100644 --- a/src/examples/modal/ModalWarnUserDeadlineExample.tsx +++ b/src/examples/warn-a-user-of-a-deadline.tsx @@ -4,7 +4,7 @@ import { CodeSnippet } from "@components/code-snippet/CodeSnippet.tsx"; import { useContext, useState } from "react"; import { LanguageVersionContext } from "@contexts/LanguageVersionContext.tsx"; -export const ModalWarnUserDeadlineExample = () => { +export const WarnAUserOfADeadline = () => { const {version} = useContext(LanguageVersionContext); const [warnCalloutModalOpen, setWarnCalloutModalOpen] = useState(); return ( @@ -156,3 +156,5 @@ export const ModalWarnUserDeadlineExample = () => { ) } + +export default WarnAUserOfADeadline; diff --git a/src/global-constants.ts b/src/global-constants.ts index 449ee6cab..43744e07d 100644 --- a/src/global-constants.ts +++ b/src/global-constants.ts @@ -1,3 +1,6 @@ -export const MAX_CONTENT_WIDTH = "1360px"; +export const MAX_CONTENT_WIDTH = "1440px"; export const DEFAULT_VERSION = "old"; export const DEFAULT_LANGUAGE = "react"; + +// Array of 'New' components +export const NEW_COMPONENTS = ["Drawer", "Temporary notification"]; diff --git a/src/routes/components/AllComponents.tsx b/src/routes/components/AllComponents.tsx index 3059cb5ad..5801e8066 100644 --- a/src/routes/components/AllComponents.tsx +++ b/src/routes/components/AllComponents.tsx @@ -1,509 +1,111 @@ import { useEffect, useState } from "react"; -import { ComponentStatus } from "@components/component-card/ComponentCard"; -import { toSentenceCase, fetchAllIssueCounts } from "../../utils"; +import { toSentenceCase, fetchAllIssueCounts, fetchComponentMetadataFromProject } from "../../utils"; import { GoabTable, GoabTableSortHeader, GoabTabs, GoabTab, - GoabGrid, GoabText, GoabFormItem, GoabInput, - GoabBadge + GoabBadge, + GoabSkeleton, GoabButton, GoabBlock } from "@abgov/react-components"; -import { ComponentCard, Props as ComponentProps } from "@components/component-card/ComponentCard"; +import { + ComponentCard, + ComponentCardProps as RawComponentProps, + ComponentStatus +} from "@components/component-card/ComponentCard"; +import { useDebounce } from "use-debounce"; +import { useContext } from "react"; +import { LanguageVersionContext } from "@contexts/LanguageVersionContext.tsx"; +import { ANGULAR_VERSIONS, REACT_VERSIONS } from "@components/version-language-switcher/version-language-constants.ts"; +import { GoabBadgeType } from "@abgov/ui-components-common"; +import { NEW_COMPONENTS } from "../../global-constants"; + +type ComponentProps = Omit & { + status: ComponentStatus; + designComponentFigmaUrl?: string; + designContributionFigmaUrl?: string; + openIssuesUrl?: string; + metatags?: string[]; + groups?: string[]; +}; + +const getBadgeType = (status: ComponentStatus): GoabBadgeType => { + if (status === "Available") return "success"; + if (status === "Legacy") return "information"; + if (status === "In Progress") return "important"; + return "light"; // Default or "Not Published" +}; + +//order the components based on the status rank (ascending) +const getStatusRank = (status: ComponentStatus): number => { + if (status === "Available" || status === "Legacy") return 0; + if (status === "In Progress") return 1; + return 2; // Not Published and others +}; const AllComponents = () => { + const { version, language } = useContext(LanguageVersionContext); const [filter, setFilter] = useState(""); + const [debouncedFilter] = useDebounce(filter, 300); const [issueCounts, setIssueCounts] = useState>({}); - const [cards, setCards] = useState(() => { - const initialCards: ComponentProps[] = [ - { - name: "accordion", - groups: ["Content layout"], - tags: ["blind", "collapse", "content layout", "expandable panel", "expand"], - description: "Let users show and hide sections of related content on a page.", - status: "Published", - }, - { - name: "callout", - groups: ["Content layout"], - tags: ["alert", "feedback and alerts", "show more information"], - description: "Communicate important information through a strong visual emphasis.", - status: "Published", - }, - { - name: "container", - groups: ["Content layout"], - tags: ["card", "content", "content layout", "group", "structure"], - description: "Group information, create hierarchy, and show related information.", - status: "Published", - }, - { - name: "details", - groups: ["Content layout"], - tags: [ - "accordion details", - "additional info", - "additional information", - "content layout", - "detail accordion", - "details expander", - "details toggle", - "disclosure", - "expand", - "expander", - "expanding detail", - "expandable details", - "expandable help text", - "more info", - "see more", - "show more", - "show more information", - ], - description: "Let users reveal more detailed information when they need it.", - status: "Published", - }, - { - name: "hero banner", - groups: ["Content layout"], - tags: ["promotion banner", "hero panel", "structure and navigation"], - description: "A visual band of text, including an image and a call to action.", - status: "Published", - }, - { - name: "list", - groups: ["Content layout"], - tags: ["content layout"], - description: "Organize information into brief and clear groups.", - status: "Published", - }, - { - name: "popover", - groups: ["Content layout"], - tags: ["content layout", "show more information"], - description: "A small overlay that opens on demand, used in other components.", - status: "Published", - }, - { - name: "table", - groups: ["Content layout"], - tags: ["data table", "content layout", "interactive table", "sortable table"], - description: - "A set of structured data that is easy for a user to scan, examine, and compare.", - status: "Published", - }, - { - name: "badge", - groups: ["Feedback and alerts"], - tags: ["feedback and alerts", "label", "lozenge", "status", "tag", "token"], - description: - "Small labels which hold small amounts of information, system feedback, or states.", - status: "Published", - }, - { - name: "filter chip", - groups: ["Feedback and alerts"], - tags: ["inputs and actions", "pill"], - description: "Allow the user to enter information, filter content, and make selections.", - status: "Published", - }, - { - name: "modal", - groups: ["Feedback and alerts"], - tags: [ - "feedback and alerts", - "popup modal", - "popup box", - "modal dialog", - "show more information", - ], - description: - "An overlay that appears in front of all other content, and requires a user to take an action before continuing.", - status: "Published", - }, - { - name: "notification banner", - groups: ["Feedback and alerts"], - tags: ["alert banner", "banner", "feedback and alerts"], - description: "Display important page level information or notifications.", - status: "Published", - }, - { - name: "progress indicator", - groups: ["Feedback and alerts"], - tags: [ - "feedback and alerts", - "loading", - "loader", - "loading indicator", - "progress spinner", - "process timer", - "spinner", - ], - description: "Provide feedback of progress to users while loading.", - status: "Published", - }, - { - name: "skeleton loader", - groups: ["Feedback and alerts"], - tags: ["content layout", "loading"], - description: - "Provide visual feedback to users while loading a content heavy page or page element.", - status: "Published", - }, - { - name: "tooltip", - groups: ["Feedback and alerts"], - tags: ["feedback and alerts"], - description: "A small popover that displays more information about an item.", - status: "Published", - }, - { - name: "button", - groups: ["Inputs and actions"], - tags: ["action", "inputs and actions", "submit"], - description: "Carry out an important action or navigate to another page.", - status: "Published", - }, - { - name: "button group", - groups: ["Inputs and actions"], - tags: ["action", "inputs and actions", "submit"], - description: - "Display multiple related actions stacked or in a horizontal row to help with arrangement and spacing.", - status: "Published", - }, - { - name: "checkbox", - groups: ["Inputs and actions"], - tags: ["checkbox", "checklist", "input", "inputs and actions", "options"], - description: "Let the user select one or more options.", - status: "Published", - }, - { - name: "date picker", - groups: ["Inputs and actions"], - tags: ["calendar, date, date picker, inputs and actions, input"], - description: - "Lets users select a date through a calendar without the need to manually type it in a field.", - status: "Published", - }, - { - name: "drawer", - groups: ["Structure and navigation"], - tags: ["sections", "structure and navigation", "Sheet", "Sidesheet", "Sidepanel"], - 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: "Published", - isNew: true, - }, - { - name: "dropdown", - groups: ["Inputs and actions"], - tags: ["inputs and actions", "select", "single select dropdown"], - description: "Present a list of options to the user to select from.", - status: "Published", - }, - { - name: "file uploader", - groups: ["Inputs and actions"], - tags: ["drag and drop", "file upload", "inputs and actions", "uploader"], - description: "Help users select and upload a file.", - status: "Published", - }, - { - name: "icon button", - groups: ["Inputs and actions"], - tags: ["action", "inputs and actions", "submit"], - description: "A compact button with an icon and no text.", - status: "Published", - }, - { - name: "input", - groups: ["Inputs and actions"], - tags: ["inputs and actions", "text field", "text box", "search", "text input"], - description: "A single-line field where users can input and edit text.", - status: "Published", - }, - { - name: "radio", - groups: ["Inputs and actions"], - tags: ["inputs and actions", "option button", "radio button group", "radio buttons"], - description: "Allow users to select one option from a set.", - status: "Published", - }, - { - name: "text area", - groups: ["Inputs and actions"], - tags: [ - "inputs and actions", - "long answer input field", - "multi line text input", - "multiple text box", - "text box", - "text input area", - ], - description: "A multi-line field where users can input and edit text.", - status: "Published", - }, - { - name: "footer", - groups: ["Structure and navigation"], - tags: ["page footer", "structure and navigation"], - description: "Provides information related your service at the bottom of every page.", - status: "Published", - }, - { - name: "form stepper", - groups: ["Structure and navigation"], - tags: [ - "form stepper", - "horizontal step navigation", - "process overview", - "progress indicator", - "steps", - "structure and navigation", - "wizard", - ], - description: "Provides a visual representation of a form through a series of steps.", - status: "Published", - }, - { - name: "header", - groups: ["Structure and navigation"], - tags: [ - "app header", - "global navigation", - "header", - "header and navigation", - "main navigation", - "navigation header", - "navigation menu", - "primary navigation", - "service header", - "structure and navigation", - "top navigation", - ], - description: "Provide structure to help users find their way around the service.", - status: "Published", - }, - { - name: "microsite header", - groups: ["Structure and navigation"], - tags: [ - "banner", - "development header", - "feedback bar", - "microheader", - "microsite banner", - "service header", - "service bar", - "service stage banner", - "service state banner", - "status bar", - "structure and navigation", - ], - description: - "Communicate what stage the service is at, connect to Alberta.ca, and gather feedback on your service.", - status: "Published", - }, - { - name: "pagination", - groups: ["Structure and navigation"], - tags: ["pager", "pagination controls", "structure and navigation"], - description: - "Help users navigation between multiple pages or screens as part of a set.", - status: "Published", - }, - { - name: "side menu", - groups: ["Structure and navigation"], - tags: ["secondary navigation", "side nav", "side bar", "structure and navigation"], - description: "A side navigation that helps the user navigate between pages.", - status: "Published", - }, - { - name: "tabs", - groups: ["Structure and navigation"], - tags: ["sections", "structure and navigation", "tabbed interface"], - description: - "Let users navigate between related sections of content, displaying one section at a time.", - status: "Published", - }, - { - name: "block", - groups: ["Utilities"], - tags: ["utility"], - description: - "Used when grouping components into a block with consistent space between.", - status: "Published", - }, - { - name: "divider", - groups: ["Utilities"], - tags: ["dividing line", "page divider", "utilities"], - description: - "Indicate a separation of layout, or to distinguish large chunks of information on a page.", - status: "Published", - }, - { - name: "form item", - groups: ["Utilities"], - tags: ["form", "input", "inputs and actions"], - description: - "Wraps an input control with a text label, requirement label, helper text, and error text.", - status: "Published", - }, - { - name: "grid", - groups: ["Utilities"], - tags: ["utilities"], - description: "Arrange a number of components into a responsive grid pattern.", - status: "Published", - }, - { - name: "icons", - groups: ["Utilities"], - tags: ["utilities"], - description: - "A simple and universal graphic symbol representing an action, object, or concept to help guide the user.", - status: "Published", - }, - { - name: "link", - groups: ["Utilities"], - tags: ["utilities"], - description: "Wraps an anchor element to add icons or margins.", - status: "Published", - }, - { - name: "spacer", - groups: ["Utilities"], - tags: ["gap", "margin", "padding", "space", "utilities"], - description: "Negative area between the components and the interface.", - status: "Published", - }, - { - name: "toggle button", - groups: ["Inputs and actions"], - tags: ["button", "inputs and actions"], - description: "Currently tracking this need in services.", - status: "Not Published", - }, - { - name: "back button", - groups: ["Inputs and actions"], - tags: ["button", "inputs and actions"], - description: "Related to form pattern, currently tracking this need in services.", - status: "Not Published", - }, - { - name: "breadcrumb", - groups: ["Structure and navigation"], - tags: ["breadcrumb"], - description: "Currently tracking this need in services.", - status: "Not Published", - }, - { - name: "error summary", - groups: ["Feedback and alerts"], - tags: ["Error"], - description: "Related to form pattern, currently tracking this need in services.", - status: "Not Published", - }, - { - name: "floating action button", - groups: ["Inputs and actions"], - tags: ["FAB"], - description: "Currently tracking this need in services.", - status: "Not Published", - }, - { - name: "quick exit", - groups: ["Structure and navigation"], - tags: ["Quick exit"], - description: "Currently tracking this need in services.", - status: "Not Published", - }, - { - name: "skip to content", - groups: ["Structure and navigation"], - tags: ["Skip to content", "accessibility"], - description: "Currently tracking this need in services.", - status: "Not Published", - }, - { - name: "rich text editor", - groups: ["Inputs and actions"], - tags: ["Skip to content", "accessibility"], - description: "Currently tracking this need in services.", - status: "Not Published", - }, - { - name: "temporary notification", - groups: ["Feedback and alerts"], - tags: ["Snackbar", "Toast", "Temporary notification"], - description: "Planned for development", - status: "Not Published", - }, - { - name: "menu button", - groups: ["Inputs and actions"], - tags: ["Menu button", "split button"], - description: "Planned for development.", - status: "Not Published", - }, - { - name: "time picker", - groups: ["Inputs and actions"], - tags: ["Time picker", "date picker"], - description: "Currently tracking this need in services.", - status: "Not Published", - }, - { - name: "text", - groups: ["Content layout"], - tags: ["text", "body", "copy"], - description: "Provides consistent sizing, spacing, and colour to written content.", - status: "Published" - }, - ]; + const [cards, setCards] = useState([]); + const resetFilters = () => { + setFilter(""); + }; + + useEffect(() => { + const fetchData = async () => { + const metadata = await fetchComponentMetadataFromProject(); + const sorted = metadata.sort((a, b) => { + const aRank = getStatusRank(a.status as ComponentStatus); + const bRank = getStatusRank(b.status as ComponentStatus); + if (aRank !== bRank) return aRank - bRank; + return a.name.localeCompare(b.name); + }); + setCards(sorted); + const issueCounts = await fetchAllIssueCounts("Components", sorted); + setIssueCounts(issueCounts); + }; + fetchData(); + }, []); - return initialCards.sort((a, b) => { - const statusOrder: ComponentStatus[] = ["Published", "In Progress", "Not Published"]; - const statusComparison = statusOrder.indexOf(a.status) - statusOrder.indexOf(b.status); - if (statusComparison !== 0) return statusComparison; - return a.name.localeCompare(b.name); - }); - }); const [sortDirection, setSortDirection] = useState<{ [key: string]: number }>({ status: -1, name: 1, }); - const filteredCards = cards.filter((card) => { - const filterLowerCase = (filter || "").toLowerCase(); - const nameMatches = card.name.toLowerCase().includes(filterLowerCase); - const tagsMatch = card.tags?.some((tag) => tag.toLowerCase().includes(filterLowerCase)); - return !filter || nameMatches || tagsMatch; - }); + const filteredCards = (() => { + const search = debouncedFilter.toLowerCase(); + const result = cards.filter((card) => { + return ( + card.name.toLowerCase().includes(search) || + card.description.toLowerCase().includes(search) || + card.tags?.some((tag) => tag.toLowerCase().includes(search)) || + card.metatags?.some((tag) => tag.toLowerCase().includes(search)) + ); + }); - const sortData = (detailOrSortBy: string | { sortBy: string }) => { - // If a string is passed, use it directly; otherwise extract the sortBy property - const sortBy = typeof detailOrSortBy === "string" ? detailOrSortBy : detailOrSortBy.sortBy; - const newDirection = sortDirection[sortBy] === 1 ? -1 : 1; - const sorted = [...cards].sort((a, b) => { + const sortBy = Object.keys(sortDirection)[0]; + const newDirection = sortDirection[sortBy]; + + const sortedFiltered = [...result].sort((a, b) => { if (sortBy === "status") { - const statusOrder: ComponentStatus[] = ["Published", "In Progress", "Not Published"]; - const statusComparison = statusOrder.indexOf(a.status) - statusOrder.indexOf(b.status); - if (statusComparison !== 0) return statusComparison * newDirection; + const aRank = getStatusRank(a.status as ComponentStatus); + const bRank = getStatusRank(b.status as ComponentStatus); + + if (aRank !== bRank) return (aRank - bRank) * newDirection; + + // If same status rank, sort by name + return a.name.localeCompare(b.name) * newDirection; } + const key = sortBy as keyof ComponentProps; - const aField = a[key]; - const bField = b[key]; + const aField = (a as any)[key]; + const bField = (b as any)[key]; const aValue = sortBy === "name" @@ -523,7 +125,13 @@ const AllComponents = () => { return 0; }); - setCards(sorted); + return sortedFiltered; + })(); + + const sortData = (detailOrSortBy: string | { sortBy: string }) => { + // If a string is passed, use it directly; otherwise extract the sortBy property + const sortBy = typeof detailOrSortBy === "string" ? detailOrSortBy : detailOrSortBy.sortBy; + const newDirection = sortDirection[sortBy] === 1 ? -1 : 1; setSortDirection({ [sortBy]: newDirection }); }; @@ -533,16 +141,6 @@ const AllComponents = () => { return formatted.includes(" ") ? `"${formatted}"` : formatted; }; - // Helper to format the label query for GraphQL (escaping inner quotes) - useEffect(() => { - const loadIssueCounts = async () => { - const issueCounts = await fetchAllIssueCounts(cards); - setIssueCounts(issueCounts); - }; - - loadIssueCounts(); - }, [cards]); - const renderTable = () => ( @@ -569,16 +167,92 @@ const AllComponents = () => { - {filteredCards.map((card) => ( - + {cards.length === 0 && ( + <> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + )} + + {cards.length > 0 && filteredCards.length === 0 && ( + + +
+ No matching components found. + Reset filters +
+ + + )} + + {filteredCards.map((card, index) => ( + + type={ + version === "old" && NEW_COMPONENTS.includes(card.name) + ? "important" + : getBadgeType(card.status) + } + content={ + version === "old" && NEW_COMPONENTS.includes(card.name) + ? "Available in " + + (language === "angular" + ? ANGULAR_VERSIONS.NEW.label.substring(0, 2).toUpperCase() + : REACT_VERSIONS.NEW.label.substring(0, 2).toUpperCase()) + : card.status + } + /> - {card.status === "Published" ? ( + {card.status === "Available" || card.status === "Legacy" ? ( {toSentenceCase(card.name)} @@ -586,7 +260,7 @@ const AllComponents = () => { {toSentenceCase(card.name)} )} - {card.groups.join(", ")} + {card.groups?.[0] || ""} { Components - Components are reusable parts of the user interface that have been made to support a variety of applications. You can use individual components in many different patterns and contexts. + Reusable parts of the user interface that have been made to support a variety of applications. You can use + individual components in many different patterns and contexts. @@ -619,25 +294,61 @@ const AllComponents = () => { type="text" value={filter} width="100%" - onChange={({ value }) => setFilter(value || "")} /> + onChange={({ value }) => setFilter(value || "")} + /> - +
+ + {cards.length === 0 && ( + <> + + + + + + + + + + )} + + {cards.length > 0 && filteredCards.length === 0 && ( + + +
+ No matching examples found.{" "} +
+
+ Reset filters +
+ )} + {filteredCards.map((card) => ( ))} - +
{renderTable()}
diff --git a/src/routes/components/AppFooter.tsx b/src/routes/components/AppFooter.tsx index 64db3a71f..2c71b9c19 100644 --- a/src/routes/components/AppFooter.tsx +++ b/src/routes/components/AppFooter.tsx @@ -26,7 +26,7 @@ const description = "Provides information related your service at the bottom of const componentCategory = Category.STRUCTURE_AND_NAVIGATION; const relatedComponents = [ { link: "/components/header", name: "Header" }, - { link: "/patterns/layout", name: "Layout" }, + { link: "/examples/layout", name: "Layout" }, ]; type ComponentPropsType = GoabAppFooterProps; diff --git a/src/routes/components/AppHeader.tsx b/src/routes/components/AppHeader.tsx index 09eb0d853..cdbdd36d8 100644 --- a/src/routes/components/AppHeader.tsx +++ b/src/routes/components/AppHeader.tsx @@ -25,7 +25,7 @@ const description = const componentCategory = Category.STRUCTURE_AND_NAVIGATION; const relatedComponents = [ { link: "/components/footer", name: "Footer" }, - { link: "/patterns/layout", name: "Layout" }, + { link: "/examples/layout", name: "Layout" }, { link: "/components/microsite-header", name: "Microsite header" } ]; type ComponentPropsType = GoabAppHeaderProps; diff --git a/src/routes/components/Block.tsx b/src/routes/components/Block.tsx index bcc00597b..d2eea46ac 100644 --- a/src/routes/components/Block.tsx +++ b/src/routes/components/Block.tsx @@ -109,7 +109,7 @@ export default function BlockPage() { relatedComponents={[ { link: "/components/divider", name: "Divider" }, { link: "/components/grid", name: "Grid" }, - { link: "/patterns/layout", name: "Layout" }, + { link: "/examples/layout", name: "Layout" }, { link: "/components/spacer", name: "Spacer" }, ]} githubLink="Block" diff --git a/src/routes/components/Components.tsx b/src/routes/components/Components.tsx index 7fa5fcc0f..4b3062fb4 100644 --- a/src/routes/components/Components.tsx +++ b/src/routes/components/Components.tsx @@ -1,17 +1,20 @@ import { GoabBadge, GoabBlock, - GoabNotification, GoabSideMenu, GoabSideMenuGroup, - GoabSpacer + GoabSpacer, } from "@abgov/react-components"; import { Link, Outlet } from "react-router-dom"; import { SupportInfo } from "@components/support-info/SupportInfo.tsx"; import { useContext } from "react"; import { LanguageVersionContext } from "@contexts/LanguageVersionContext.tsx"; -import { getVersionedUrlPath, ANGULAR_VERSIONS, REACT_VERSIONS } from "@components/version-language-switcher/version-language-constants.ts"; -import { MAX_CONTENT_WIDTH } from "../../global-constants.ts"; +import { + getVersionedUrlPath, + ANGULAR_VERSIONS, + REACT_VERSIONS, +} from "@components/version-language-switcher/version-language-constants.ts"; +import { NEW_COMPONENTS } from "../../global-constants"; export function Components() { const { language, version } = useContext(LanguageVersionContext); @@ -22,7 +25,6 @@ export function Components() { return prefixUrl.length > 0 ? `${prefixUrl}/${path}` : path; }; - const newComponentLabel = (componentName: string) => { const getBadgeLabel = () => { if (version === "new") return "New"; @@ -30,27 +32,31 @@ export function Components() { ? ANGULAR_VERSIONS.NEW.label.substring(0, 2).toUpperCase() : REACT_VERSIONS.NEW.label.substring(0, 2).toUpperCase(); }; + + const getBadgeType = () => { + if (version === "new" && NEW_COMPONENTS.includes(componentName)) { + return "success"; + } + return "important"; + }; + + return ( + + {componentName} + + ); + }; + + const legacyComponentLabel = (componentName: string) => { return ( - {componentName} + {componentName} ); }; return ( <> - {version === "old" && ( - - Support for the Long Term Support (LTS) version of the Design system will be available until September - 2025.
View the upgrade guide - - )} - {version === "new" && ( - - Upgrading to the latest version of the design system?{" "} - View the upgrade guide - - )}
@@ -66,7 +72,6 @@ export function Components() { Popover Table Text - Badge @@ -75,6 +80,7 @@ export function Components() { Notification banner Progress indicator Skeleton loader + {newComponentLabel("Temporary notification")} Tooltip @@ -92,7 +98,7 @@ export function Components() { {newComponentLabel("Drawer")} Footer - Form stepper + {legacyComponentLabel("Form stepper")} Header Microsite header Pagination diff --git a/src/routes/components/Dropdown.tsx b/src/routes/components/Dropdown.tsx index e1747fbf4..160473ab3 100644 --- a/src/routes/components/Dropdown.tsx +++ b/src/routes/components/Dropdown.tsx @@ -2,10 +2,11 @@ import { useContext, useState } from "react"; import { GoabBadge, GoabDropdown, - GoabDropdownItem, GoabDropdownProps, + GoabDropdownItem, + GoabDropdownProps, GoabFormItem, GoabTab, - GoabTabs + GoabTabs, } from "@abgov/react-components"; import { ComponentBinding, Sandbox } from "@components/sandbox"; import ICONS from "./icons.json"; @@ -19,11 +20,15 @@ import { ComponentContent } from "@components/component-content/ComponentContent import { DropdownExamples } from "@examples/dropdown/DropdownExamples"; import { GoabDropdownOnChangeDetail } from "@abgov/ui-components-common"; import { LanguageVersionContext } from "@contexts/LanguageVersionContext.tsx"; -import { LegacyMarginProperty, MarginProperty } from "@components/component-properties/common-properties.ts"; +import { + LegacyMarginProperty, + MarginProperty, +} from "@components/component-properties/common-properties.ts"; import { DesignEmpty } from "@components/empty-states/design-empty/DesignEmpty.tsx"; import { AccessibilityEmpty } from "@components/empty-states/accessibility-empty/AccessibilityEmpty.tsx"; -const FIGMA_LINK = "https://www.figma.com/design/3pb2IK8s2QUqWieH79KdN7/%E2%9D%96-Component-library-%7C-DDD?node-id=105-42"; +const FIGMA_LINK = + "https://www.figma.com/design/3pb2IK8s2QUqWieH79KdN7/%E2%9D%96-Component-library-%7C-DDD?node-id=105-42"; // == Page props == const componentName = "Dropdown"; @@ -41,10 +46,10 @@ type CastingType = { value: string; [key: string]: unknown; onChange: (event: GoabDropdownOnChangeDetail) => void; -} +}; export default function DropdownPage() { - const {version} = useContext(LanguageVersionContext); + const { version } = useContext(LanguageVersionContext); const [dropdownProps, setDropdownProps] = useState({ name: "item", value: "", @@ -82,7 +87,9 @@ export default function DropdownPage() { { label: "Filterable", type: "boolean", name: "filterable", value: false }, { label: "ARIA label", type: "string", name: "ariaLabel", value: "" }, ]); - const { formItemBindings, formItemProps, onFormItemChange } = useSandboxFormItem({ label: "Basic dropdown" }); + const { formItemBindings, formItemProps, onFormItemChange } = useSandboxFormItem({ + label: "Basic dropdown", + }); const oldDropdownProperties: ComponentProperty[] = [ { @@ -217,6 +224,12 @@ export default function DropdownPage() { type: "string", description: "Stores the value of the item selected from the dropdown.", }, + { + name: "autoComplete", + type: "string", + description: "Specifies the autocomplete attribute for the dropdown input. Native only.", + }, + { name: "leadingIcon", type: "GoAIconType", @@ -315,15 +328,15 @@ export default function DropdownPage() { lang: "react", type: "append | prepend | reset", description: "The mount type for the dropdown item.", - defaultValue: "append" + defaultValue: "append", }, { - name:"mount", + name: "mount", lang: "angular", type: "append | prepend | reset", description: "The mount type for the dropdown item.", - defaultValue: "append" - } + defaultValue: "append", + }, ]; const dropdownItemProperties: ComponentProperty[] = [ { @@ -348,8 +361,8 @@ export default function DropdownPage() { name: "mountType", type: "GoabDropdownItemMountType (append | prepend | reset)", description: "The mount type for the dropdown item.", - defaultValue: "append" - } + defaultValue: "append", + }, ]; function onSandboxChange(bindings: ComponentBinding[], props: Record) { @@ -376,10 +389,11 @@ export default function DropdownPage() { githubLink="Dropdown" /> - -

Playground

+

+ Playground +

- + - } - > + }>
diff --git a/src/routes/components/FormStepper.tsx b/src/routes/components/FormStepper.tsx index 9dbc17209..bf6d43a8a 100644 --- a/src/routes/components/FormStepper.tsx +++ b/src/routes/components/FormStepper.tsx @@ -26,6 +26,8 @@ import { import { FormStepperExamples } from "@examples/form-stepper/FormStepperExamples.tsx"; import { DesignEmpty } from "@components/empty-states/design-empty/DesignEmpty.tsx"; import { AccessibilityEmpty } from "@components/empty-states/accessibility-empty/AccessibilityEmpty.tsx"; +import { LegacyCalloutBanner } from "@components/legacy-callout-banner/LegacyCalloutBanner.tsx"; +import { Link } from "react-router-dom"; const FIGMA_LINK = "https://www.figma.com/design/3pb2IK8s2QUqWieH79KdN7/%E2%9D%96-Component-library-%7C-DDD?node-id=1014-6629"; @@ -116,40 +118,48 @@ export default function FormStepperPage() { figmaLink={FIGMA_LINK} githubLink="Form Stepper" /> - - - -

- Playground -

- {/*Must use Container because Form Stepper cannot be rendered correctly inside sandbox*/} - -
- setStep(+event.step)} - {...formStepProps}> - - - - - - -
Page 1 content
-
Page 2 content
-
Page 3 content
-
Page 4 content
-
-
-
- {/*Angular code*/} - {version === "old" && ( - + The component is stable and supported in the latest major release. However, we recommend + using the public form pattern for a more modular, + flexible, and accessible approach. + + + {version === "old" && ( + + + +

+ Playground +

+ {/*Must use Container because Form Stepper cannot be rendered correctly inside sandbox*/} + +
+ setStep(+event.step)} + {...formStepProps}> + + + + + + +
Page 1 content
+
Page 2 content
+
Page 3 content
+
Page 4 content
+
+
+
+ + {/*Angular code*/} + {version === "old" && ( + - )} - {version === "new" && ( - - )} + /> + )} - {version === "old" && ( - @@ -195,46 +189,24 @@ export default function FormStepperPage() {
Page 4 content
`} - /> - )} + /> + )} - {version === "new" && ( + {/*React code*/} - - - - - - -
Page 1 content
-
Page 2 content
-
Page 3 content
-
Page 4 content
-
- `} - /> - )} - - {/*React code*/} - (-1); `} - /> - {version === "old" && ( - + {version === "old" && ( + @@ -248,62 +220,41 @@ export default function FormStepperPage() {
Page 4 content
`} - /> - )} + /> + )} - {version === "new" && ( - setStep(+event.step)}> - - - - - - -
Page 1 content
-
Page 2 content
-
Page 3 content
-
Page 4 content
-
- `} + - )} - - - -
+ +
- - Examples - - - }> - - + + Examples + + + }> + + - - - + + + - - - -
-
+ + + +
+
+ )} ); } diff --git a/src/routes/components/Grid.tsx b/src/routes/components/Grid.tsx index 3b97876b6..0b16ef2c8 100644 --- a/src/routes/components/Grid.tsx +++ b/src/routes/components/Grid.tsx @@ -94,7 +94,7 @@ export default function GridPage() { relatedComponents={[ { link: "/components/block", name: "Block" }, { link: "/components/divider", name: "Divider" }, - { link: "/patterns/layout", name: "Layout" }, + { link: "/examples/layout", name: "Layout" }, { link: "/components/spacer", name: "Spacer" }, ]} githubLink="Grid" diff --git a/src/routes/components/Link.tsx b/src/routes/components/Link.tsx index c8c3d97a4..70f5ad8c0 100644 --- a/src/routes/components/Link.tsx +++ b/src/routes/components/Link.tsx @@ -6,7 +6,7 @@ import { } from "@components/component-properties/ComponentProperties.tsx"; import { Category, ComponentHeader } from "@components/component-header/ComponentHeader.tsx"; import { GoabBadge, GoabTab, GoabTabs, GoabLink } from "@abgov/react-components"; -import { LinkExamples } from "@examples/link/LinkExamples.tsx"; +import LinkExamples from "@examples/link/LinkExamples.tsx"; import { DesignEmpty } from "@components/empty-states/design-empty/DesignEmpty.tsx"; import { AccessibilityEmpty } from "@components/empty-states/accessibility-empty/AccessibilityEmpty.tsx"; import ICONS from "@routes/components/icons.json"; diff --git a/src/routes/components/MicrositeHeader.tsx b/src/routes/components/MicrositeHeader.tsx index bb8583fd1..3d664cdee 100644 --- a/src/routes/components/MicrositeHeader.tsx +++ b/src/routes/components/MicrositeHeader.tsx @@ -18,7 +18,8 @@ import { GoabServiceLevel } from "@abgov/ui-components-common"; import { DesignEmpty } from "@components/empty-states/design-empty/DesignEmpty.tsx"; import { AccessibilityEmpty } from "@components/empty-states/accessibility-empty/AccessibilityEmpty.tsx"; -const FIGMA_LINK = "https://www.figma.com/design/3pb2IK8s2QUqWieH79KdN7/%E2%9D%96-Component-library-%7C-DDD?node-id=2-81"; +const FIGMA_LINK = + "https://www.figma.com/design/3pb2IK8s2QUqWieH79KdN7/%E2%9D%96-Component-library-%7C-DDD?node-id=2-81"; const componentName = "Microsite header"; const description = @@ -158,7 +159,7 @@ export default function MicrositeHeaderPage() { "Set to true to handle the feedback click via _feedbackClick custom event handler.", }, { - name: "_feedbackclick", + name: "_feedbackClick", lang: "angular", type: "CustomEvent", description: "Function invoked when feedback link is clicked.", @@ -235,14 +236,18 @@ export default function MicrositeHeaderPage() { /> - -

Playground

+

+ Playground +

- +
- } - > + }> diff --git a/src/routes/components/Modal.tsx b/src/routes/components/Modal.tsx index ccdd5b582..d2a504652 100644 --- a/src/routes/components/Modal.tsx +++ b/src/routes/components/Modal.tsx @@ -6,7 +6,7 @@ import { GoabModal, GoabModalProps, GoabTab, - GoabTabs, + GoabTabs } from "@abgov/react-components"; import { ComponentBinding, Sandbox } from "@components/sandbox"; import { useContext, useEffect, useState } from "react"; @@ -291,7 +291,6 @@ export default function ModalPage() { figmaLink={FIGMA_LINK} githubLink="Modal" /> - diff --git a/src/routes/components/Popover.tsx b/src/routes/components/Popover.tsx index f2e254328..33c5f6b9f 100644 --- a/src/routes/components/Popover.tsx +++ b/src/routes/components/Popover.tsx @@ -12,17 +12,20 @@ import { ComponentContent } from "@components/component-content/ComponentContent import { LanguageVersionContext } from "@contexts/LanguageVersionContext.tsx"; import { LegacyMarginProperty, - LegacyTestIdProperties, MarginProperty, - TestIdProperty + LegacyTestIdProperties, + MarginProperty, + TestIdProperty, } from "@components/component-properties/common-properties.ts"; import { DesignEmpty } from "@components/empty-states/design-empty/DesignEmpty.tsx"; import { AccessibilityEmpty } from "@components/empty-states/accessibility-empty/AccessibilityEmpty.tsx"; -import { ExamplesEmpty } from "@components/empty-states/examples-empty/ExamplesEmpty.tsx"; +//import { ExamplesEmpty } from "@components/empty-states/examples-empty/ExamplesEmpty.tsx"; +import { PopoverExamples } from "@examples/popover/PopoverExamples"; -const FIGMA_LINK = "https://www.figma.com/design/3pb2IK8s2QUqWieH79KdN7/%E2%9D%96-Component-library-%7C-DDD?node-id=27301-302109"; +const FIGMA_LINK = + "https://www.figma.com/design/3pb2IK8s2QUqWieH79KdN7/%E2%9D%96-Component-library-%7C-DDD?node-id=27301-302109"; export default function PopoverPage() { - const {version} = useContext(LanguageVersionContext); + const { version } = useContext(LanguageVersionContext); const [popoverProps, setPopoverProps] = useState({}); const [popoverBindings, setPopoverBindings] = useState([ { @@ -119,7 +122,7 @@ export default function PopoverPage() { name: "maxWidth", type: "string", description: "Sets the maximum width of the popover container.", - defaultValue: "320px" + defaultValue: "320px", }, { name: "minWidth", @@ -183,18 +186,20 @@ export default function PopoverPage() { /> - -

Playground

+

+ Playground +

{/*Must be skipRender because Sandbox doesn't support slot target*/} {/*Angular*/} - {version === "old" &&

This is a popover

It can be used for a number of different contexts. @@ -203,13 +208,15 @@ export default function PopoverPage() {
`} - />} + /> + )} - {version === "new" &&

This is a popover

It can be used for a number of different contexts. @@ -218,58 +225,67 @@ export default function PopoverPage() { `} - />} + /> + )} {/*React*/} - {version === "old" && Click me ); `} - />} + /> + )} - {version === "new" && Click me ); `} - />} + /> + )} - {version === "old" &&

This is a popover

It can be used for a number of different contexts. `} - />} + /> + )} - {version === "new" &&

This is a popover

It can be used for a number of different contexts. `} - />} + /> + )} Click me - } - > + }>

This is a popover

It can be used for a number of different contexts.
- + Examples - + - } - > - + }> + diff --git a/src/routes/components/SideMenu.tsx b/src/routes/components/SideMenu.tsx index a21aa1915..fc754dba8 100644 --- a/src/routes/components/SideMenu.tsx +++ b/src/routes/components/SideMenu.tsx @@ -28,7 +28,7 @@ const description = const componentCategory = Category.STRUCTURE_AND_NAVIGATION; const relatedComponents = [ { link: "/components/header", name: "Header" }, - { link: "/patterns/layout", name: "Layout" } + { link: "/examples/layout", name: "Layout" } ]; export default function SideMenuPage() { diff --git a/src/routes/components/Spacer.tsx b/src/routes/components/Spacer.tsx index eec8017ab..e2259a043 100644 --- a/src/routes/components/Spacer.tsx +++ b/src/routes/components/Spacer.tsx @@ -113,7 +113,7 @@ export default function SpacerPage() { { link: "/components/block", name: "Block" }, { link: "/components/divider", name: "Divider" }, { link: "/components/grid", name: "Grid" }, - { link: "/patterns/layout", name: "Layout" }, + { link: "/examples/layout", name: "Layout" }, ]} figmaLink={FIGMA_LINK} githubLink="Spacer" diff --git a/src/routes/components/Table.tsx b/src/routes/components/Table.tsx index 0698f1cf0..0fab4f93d 100644 --- a/src/routes/components/Table.tsx +++ b/src/routes/components/Table.tsx @@ -18,7 +18,7 @@ import { GoabTableProps } from "@abgov/react-components"; import { ComponentContent } from "@components/component-content/ComponentContent"; import { GoabTableOnSortDetail } from "@abgov/ui-components-common"; import { LanguageVersionContext } from "@contexts/LanguageVersionContext.tsx"; -import { TableWithGlobalFiltersExample } from "@examples/filter-chip/TableWithGlobalFiltersExample.tsx"; +import { FilterDataInATable } from "@examples/filter-data-in-a-table.tsx"; import { omit } from "lodash"; import { DesignEmpty } from "@components/empty-states/design-empty/DesignEmpty.tsx"; import { AccessibilityEmpty } from "@components/empty-states/accessibility-empty/AccessibilityEmpty.tsx"; @@ -627,7 +627,7 @@ export default function TablePage() { exampleTitle="Filter data in a table" figmaExample="https://www.figma.com/design/aIRjvBzpIUH0GbkffjbL04/%E2%9D%96-Patterns-library-%7C-DDD?node-id=7104-1626357&t=WrSJODVw0mryQrrA-4"> - + diff --git a/src/routes/components/TemporaryNotification.tsx b/src/routes/components/TemporaryNotification.tsx index 2e4b9ee68..8f4237181 100644 --- a/src/routes/components/TemporaryNotification.tsx +++ b/src/routes/components/TemporaryNotification.tsx @@ -1,82 +1,498 @@ +import { useState, useContext } from "react"; +import { + GoabBadge, + GoabButton, + GoabTab, + GoabTabs, + GoabTemporaryNotificationCtrl, +} from "@abgov/react-components"; import { Category, ComponentHeader } from "@components/component-header/ComponentHeader.tsx"; -import { ComponentBinding, Sandbox } from "@components/sandbox"; -import { useState } from "react"; import { ComponentProperties, ComponentProperty, } from "@components/component-properties/ComponentProperties.tsx"; - -import { GoabBadge, GoabTab, GoabTabs, GoabCalloutProps } from "@abgov/react-components"; +import { ComponentContent } from "@components/component-content/ComponentContent"; +import { TestIdProperty } from "@components/component-properties/common-properties.ts"; +import { DesignEmpty } from "@components/empty-states/design-empty/DesignEmpty.tsx"; +import { AccessibilityEmpty } from "@components/empty-states/accessibility-empty/AccessibilityEmpty.tsx"; +import { CodeSnippet } from "@components/code-snippet/CodeSnippet.tsx"; +import { Sandbox, ComponentBinding } from "@components/sandbox"; +import { LanguageVersionContext } from "@contexts/LanguageVersionContext.tsx"; +import { OldComponentBanner } from "@components/old-component-banner/OldComponentBanner.tsx"; +import { TemporaryNotification } from "@abgov/ui-components-common"; +import { TemporaryNotificationExamples } from "@examples/temporary-notification/TemporaryNotificationExamples.tsx"; +import { FunctionProperties } from "@components/function-properties/FunctionProperties.tsx"; // == Page props == const componentName = "Temporary notification"; -const description = "A temporary notification showing a process started or completed."; +const description = "Temporary notifications provide brief feedback about an action or event. They appear temporarily and can include an action for users to take."; +const category = Category.FEEDBACK_AND_ALERTS; const relatedComponents = [ { link: "/components/callout", name: "Callout" }, { link: "/components/notification-banner", name: "Notification banner" } ]; -type ComponentPropsType = GoabCalloutProps; -type CastingType = { - // add any required props here - [key: string]: unknown; -}; - -export default function TEMPLATE_Page() { - const [_componentProps, setComponentProps] = useState({}); +const FIGMA_LINK = "https://www.figma.com/design/3pb2IK8s2QUqWieH79KdN7/%E2%9D%96-Component-library-%7C-DDD?node-id=64940-255303"; +const ACCESSIBILITY_FIGMA_LINK = "https://www.figma.com/design/3pb2IK8s2QUqWieH79KdN7/%E2%9D%96-Component-library-%7C-DDD?node-id=64940-255303"; +export default function TemporaryNotificationPage() { + const { version, language } = useContext(LanguageVersionContext); + const [componentBindings, setComponentBindings] = useState([ + { + label: "Horizontal position", + type: "dropdown", + name: "horizontalPosition", + options: ["left", "center", "right"], + value: "center", + }, + { + label: "Message", + type: "string", + name: "message", + value: "This is a notification message", + width: "40ch", + }, { label: "Type", - type: "list", + type: "dropdown", name: "type", - options: ["basic"], + options: ["basic", "success", "failure", "indeterminate", "progress"], value: "basic", }, - // ... + { + label: "Duration", + type: "dropdown", + name: "duration", + options: ["short", "medium", "long"], + value: "short", + }, + { + label: "Action text", + type: "string", + name: "actionText", + value: "", + helpText: "Optional action button text", + }, ]); - const componentProperties: ComponentProperty[] = [ + const handleShowNotification = () => { + const props = componentBindings.reduce((acc, binding) => { + if (binding.value !== "" && binding.value !== undefined) { + acc[binding.name] = binding.value; + } + return acc; + }, {} as Record); + + const options: any = { + type: props.type || "basic", + duration: props.duration !== undefined ? props.duration : 4000, + }; + + let notificationId: string; + + if (props.actionText) { + options.actionText = props.actionText; + options.action = () => { + if (notificationId) { + TemporaryNotification.dismiss(notificationId); + } + TemporaryNotification.show("Action performed!", { type: "success", duration: 2000 }); + }; + } + + notificationId = TemporaryNotification.show(props.message || "Default message", options); + }; + + function onSandboxChange(bindings: ComponentBinding[]) { + setComponentBindings(bindings); + } + + const controllerProperties: ComponentProperty[] = [ { - name: "type", - type: "basic", - description: "", + name: "verticalPosition", + type: "SnackbarVerticalPosition (top | bottom)", + defaultValue: "bottom", + description: "Vertical position of notifications on the screen.", + }, + { + name: "horizontalPosition", + type: "SnackbarHorizontalPosition (left | center | right)", + defaultValue: "center", + description: "Horizontal position of notifications on the screen.", }, - // ... + TestIdProperty, ]; - function onSandboxChange(bindings: ComponentBinding[], props: Record) { - setComponentBindings(bindings); - setComponentProps(props as CastingType); - } + const showMethodProperties: ComponentProperty[] = [ + { + name: "message", + type: "string", + description: "The message to display in the notification.", + }, + { + name: "options", + type: "Partial", + description: "Optional configuration object for the notification.", + }, + { + name: "options.type", + type: "GoabTemporaryNotificationType (basic | success | failure | indeterminate | progress)", + defaultValue: "basic", + description: "The type of notification which determines styling and icon.", + }, + { + name: "options.duration", + type: "long | medium | short | number", + defaultValue: "short", + description: "Duration before auto-dismissal. Use 'short' (~3s), 'medium' (~4s), 'long' (~6s), or custom milliseconds.", + }, + { + name: "options.actionText", + type: "string", + description: "Text for the action button. When provided, displays an action button.", + }, + { + name: "options.action", + type: "() => void", + description: "Function to execute when the action button is clicked.", + }, + { + name: "options.cancelUUID", + type: "string", + description: "UUID of an existing notification to cancel when showing this one.", + }, + ]; + + const dismissMethodProperties: ComponentProperty[] = [ + { + name: "uuid", + type: "string", + description: "The UUID of the notification to dismiss. This is the value returned by TemporaryNotification.show().", + }, + ]; + + const progressMethodProperties: ComponentProperty[] = [ + { + name: "uuid", + type: "string", + description: "The UUID of the progress notification to update. This is the value returned by TemporaryNotification.show().", + }, + { + name: "progress", + type: "number", + description: "The progress percentage (0-100) to display in the progress notification.", + }, + ]; return ( <> - - - - <> - {/* */} - - - - - - Design guidelines - - - } - > - + {version === "old" && } + + {version === "new" && ( + + + +

+ Component +

+ + + b.name === 'message')?.value}", { + type: "${componentBindings.find(b => b.name === 'type')?.value}", + duration: "${componentBindings.find(b => b.name === 'duration')?.value}"${componentBindings.find(b => b.name === 'actionText')?.value ? `, + actionText: "${componentBindings.find(b => b.name === 'actionText')?.value}", + action: () => { + TemporaryNotification.show("Action performed!", { type: "success", duration: 2000 }); + }` : ''} + }); + } + }`} + /> + + + + + + Show Notification + `} + /> + + { + TemporaryNotification.show("${componentBindings.find(b => b.name === 'message')?.value}", { + type: "${componentBindings.find(b => b.name === 'type')?.value}", + duration: "${componentBindings.find(b => b.name === 'duration')?.value}"${componentBindings.find(b => b.name === 'actionText')?.value ? `, + actionText: "${componentBindings.find(b => b.name === 'actionText')?.value}", + action: () => { + TemporaryNotification.show("Action performed!", { type: "success", duration: 2000 }); + }` : ''} + }); + };`} + /> + + + + + Show Notification + + `} + /> + + Show Notification + b.name === 'verticalPosition')?.value as any || "bottom"} + horizontalPosition={componentBindings.find(b => b.name === 'horizontalPosition')?.value as any || "center"} + /> + + + + show(message, options) is a helper function to display temporary notifications in your component. View the table below to learn about the available options.} + properties={showMethodProperties} + codeSnippets={{ + angular: <> + + + Show Notification + `} + /> + , + react: { + TemporaryNotification.show("Your message here", { + type: "success", + duration: "medium", + }); + }; + + return <> + + Show Notification + + }`} + /> + }} + /> + dismiss(uuid) is a helper function to hide a notification in your component. View the table below to learn about the available options.} + properties={dismissMethodProperties} + codeSnippets={{ + angular: <> + + + Save + `} + /> + , + react: + + Save + + }`} + /> + }} + /> + setProgress(uuid, progress) is a helper function to update the progress of a progress notification. View the table below to learn about the available options.} + properties={progressMethodProperties} + codeSnippets={{ + angular: <> + + + Save + `} + /> + , + react: + + Save + + }`} + /> + }} + /> +
+ + + Examples + + + }> + + + + + + + + + + +
+
+ )} ); } diff --git a/src/routes/components/TextArea.tsx b/src/routes/components/TextArea.tsx index 0b4766e25..f737f4eea 100644 --- a/src/routes/components/TextArea.tsx +++ b/src/routes/components/TextArea.tsx @@ -5,13 +5,7 @@ import { ComponentProperty, } from "@components/component-properties/ComponentProperties.tsx"; import { Category, ComponentHeader } from "@components/component-header/ComponentHeader.tsx"; -import { - GoabBadge, - GoabFormItem, - GoabTab, - GoabTabs, - GoabTextarea, -} from "@abgov/react-components"; +import { GoabBadge, GoabFormItem, GoabTab, GoabTabs, GoabTextarea } from "@abgov/react-components"; import { CodeSnippet } from "@components/code-snippet/CodeSnippet.tsx"; import { useSandboxFormItem } from "@hooks/useSandboxFormItem.tsx"; import { ComponentContent } from "@components/component-content/ComponentContent"; @@ -20,7 +14,7 @@ import { LanguageVersionContext } from "@contexts/LanguageVersionContext.tsx"; import { LegacyMarginProperty, MarginProperty, - TestIdProperty + TestIdProperty, } from "@components/component-properties/common-properties.ts"; import { TextAreaExamples } from "@examples/textarea/TextAreaExamples.tsx"; import { DesignEmpty } from "@components/empty-states/design-empty/DesignEmpty.tsx"; @@ -28,7 +22,8 @@ import { AccessibilityEmpty } from "@components/empty-states/accessibility-empty // == Page props == -const FIGMA_LINK = "https://www.figma.com/design/3pb2IK8s2QUqWieH79KdN7/%E2%9D%96-Component-library-%7C-DDD?node-id=133-186"; +const FIGMA_LINK = + "https://www.figma.com/design/3pb2IK8s2QUqWieH79KdN7/%E2%9D%96-Component-library-%7C-DDD?node-id=133-186"; const componentName = "Text area"; const description = "A multi-line field where users can input and edit text."; const category = Category.INPUTS_AND_ACTIONS; @@ -45,7 +40,7 @@ type CastingType = { }; export default function TextAreaPage() { - const {version} = useContext(LanguageVersionContext); + const { version } = useContext(LanguageVersionContext); const [componentProps, setComponentProps] = useState({ name: "item", value: "", @@ -255,6 +250,11 @@ export default function TextAreaPage() { type: "string", description: "Bound to value", }, + { + name: "autoComplete", + type: "string", + description: "Specifies the autocomplete attribute for the textarea input.", + }, { name: "placeholder", type: "string", @@ -508,8 +508,7 @@ export default function TextAreaPage() { Examples - } - > + }>
diff --git a/src/routes/components/TextField.tsx b/src/routes/components/TextField.tsx index 99c45cc6a..b9c407d9e 100644 --- a/src/routes/components/TextField.tsx +++ b/src/routes/components/TextField.tsx @@ -451,6 +451,11 @@ export default function TextFieldPage() { required: true, description: "Name of input value that is received in the onChange event.", }, + { + name: "autoComplete", + type: "string", + description: "Specifies the autocomplete attribute for the input field.", + }, { name: "value", type: "string||null", diff --git a/src/routes/content/ContentLayout.tsx b/src/routes/content/ContentLayout.tsx index 24a64c32e..fd3d141d9 100644 --- a/src/routes/content/ContentLayout.tsx +++ b/src/routes/content/ContentLayout.tsx @@ -1,6 +1,6 @@ import { GoabSideMenu, GoabSpacer } from "@abgov/react-components"; import { Link, Outlet } from "react-router-dom"; -import "./content.css"; +import "../foundations/content.css"; import { SupportInfo } from "@components/support-info/SupportInfo"; export default function ContentLayout() { diff --git a/src/routes/examples/ExamplePageTemplate.tsx b/src/routes/examples/ExamplePageTemplate.tsx new file mode 100644 index 000000000..d8fa22103 --- /dev/null +++ b/src/routes/examples/ExamplePageTemplate.tsx @@ -0,0 +1,69 @@ +import { useParams } from "react-router-dom"; +import { Link } from "react-router-dom"; +import { lazy, Suspense, useEffect, useState, useMemo } from "react"; +import { GoabBlock, GoabSkeleton, GoabLink } from "@abgov/react-components"; +import { fetchExampleMetadataFromProject } from "../../utils"; +import { ExampleHeader } from "@components/example-header/ExampleHeader.tsx"; + + +export default function ExamplePageTemplate() { + const { slug } = useParams(); // assumes route like /examples/:slug + const [example, setExample] = useState(null); + + // Dynamic import based on slug + const ExampleComponent = useMemo(() => { + if (!slug) return () =>
Invalid slug
; + return lazy(() => + import(`../../examples/${slug}.tsx`).catch(() => + import("@routes/examples/FallbackExample.tsx") + ) + ); + }, [slug]); + console.log("Loaded example metadata:", example); + useEffect(() => { + if (!slug) return; + console.log("Looking for slug:", slug); + fetchExampleMetadataFromProject().then(data => { + console.log("Fetched metadata:", data); + const match = data.find((item: any) => item.slug === slug); + console.log("Matched example:", match); + setExample(match); + }).catch(error => { + console.error("Error fetching metadata:", error); + }); + }, [slug]); + return ( +
+
+ + + + Back + + + {!example ? ( + + + + + + + + ) : ( + + )} + + }> + + +
+
+ ); +} \ No newline at end of file diff --git a/src/routes/examples/ExamplesCardView.tsx b/src/routes/examples/ExamplesCardView.tsx new file mode 100644 index 000000000..e69de29bb diff --git a/src/routes/examples/ExamplesFilterPanel.tsx b/src/routes/examples/ExamplesFilterPanel.tsx new file mode 100644 index 000000000..e69de29bb diff --git a/src/routes/examples/ExamplesLayout.tsx b/src/routes/examples/ExamplesLayout.tsx new file mode 100644 index 000000000..c55900941 --- /dev/null +++ b/src/routes/examples/ExamplesLayout.tsx @@ -0,0 +1,66 @@ +import { GoabSideMenu, GoabSideMenuGroup, GoabSpacer } from "@abgov/react-components"; +import {Link, Outlet} from "react-router-dom"; +import {SupportInfo} from "@components/support-info/SupportInfo.tsx"; +import { LanguageVersionContext } from "@contexts/LanguageVersionContext.tsx"; +import { useContext } from "react"; +import { getVersionedUrlPath } from "@components/version-language-switcher/version-language-constants.ts"; + +export default function ExamplesLayout() { + const {language, version} = useContext(LanguageVersionContext); + getVersionedUrlPath(version, language); + + return ( +
+
+ + + All + + Overview + Start page + Task list page + Question page + Review page + Result page + + Basic layout + {/* + + Approve or reject a submission + Assign a case or task + Check application status + Check eligibility + Filter and refine search results + Generate or download a PDF or certificate + Onboarding for new users or features + Pay a fee or complete payment + Provide feedback or comments + Review, Revise, and Resubmit + Schedule a task or appointment + Search for a record + Update personal information + + + + A + B + C + D + E + + + + + Upgrade to the latest component version + Generate a review page from branch form questions + + */} + +
+
+ + +
+
+ ); +} diff --git a/src/routes/examples/ExamplesList.tsx b/src/routes/examples/ExamplesList.tsx new file mode 100644 index 000000000..e69de29bb diff --git a/src/routes/examples/ExamplesOverview.tsx b/src/routes/examples/ExamplesOverview.tsx new file mode 100644 index 000000000..294e22a75 --- /dev/null +++ b/src/routes/examples/ExamplesOverview.tsx @@ -0,0 +1,472 @@ +import { useEffect, useState } from "react"; +import { Link } from "react-router-dom"; +import { toSentenceCase, fetchAllIssueCounts, fetchExampleMetadataFromProject } from "../../utils"; +import { + GoabTable, + GoabTableSortHeader, + GoabTabs, + GoabTab, + GoabText, + GoabFormItem, + GoabInput, + GoabBadge, + GoabSkeleton, GoabBlock +} from "@abgov/react-components"; +import { GoabCheckbox, GoabButton } from "@abgov/react-components"; +import { useDebounce } from "use-debounce"; +import { + ExampleCard, + ExampleCardProps as RawExampleProps, + ComponentStatus +} from "@components/example-card/ExampleCard.tsx"; + +type ExampleProps = Omit & { + status: ComponentStatus; + designComponentFigmaUrl?: string; + designContributionFigmaUrl?: string; + openIssuesUrl?: string; + metatags?: string[]; + url?: string; + slug?: string; + groups?: string[]; +}; + +export default function ExamplesOverviewPage() { + const [filter, setFilter] = useState(""); + const [debouncedFilter] = useDebounce(filter, 300); + const [issueCounts, setIssueCounts] = useState>({}); + const [cards, setCards] = useState([]); + + const [showFilters, setShowFilters] = useState(false); + const sizes = ["Interaction", "Task", "Page", "Service"]; + const userGoals = ["Ask a user for...", "Help a user to..."]; + const categories = [ + "Content layout", + "Feedback and alerts", + "Inputs and actions", + "Public form", + "Structure and navigation", + "Technical" + ]; + const [selectedFilters, setSelectedFilters] = useState<{ + size: string[]; + userGoal: string[]; + category: string[]; + }>({ + size: [], + userGoal: [], + category: [] + }); + + function handleCheckboxChange(category: "size" | "userGoal" | "category", value: string, checked: boolean) { + setSelectedFilters((prev) => { + const prevSet = new Set(prev[category]); + if (checked) { + prevSet.add(value); + } else { + prevSet.delete(value); + } + return { ...prev, [category]: Array.from(prevSet) }; + }); + } + + const resetFilters = () => { + setSelectedFilters({ + size: [], + userGoal: [], + category: [] + }); + setFilter(""); + }; + + // Calculate if all or any filters are selected + userGoals.every((p) => selectedFilters.userGoal.includes(p)) && + categories.every((t) => selectedFilters.category.includes(t)); + userGoals.some((p) => selectedFilters.userGoal.includes(p)) || + categories.some((t) => selectedFilters.category.includes(t)); + + useEffect(() => { + const fetchData = async () => { + const metadata = await fetchExampleMetadataFromProject(); + const withSlugs = metadata.map((item) => ({ + ...item, + slug: item.name + .toLowerCase() + .replace(/[^\w\s-]/g, "") + .replace(/\s+/g, "-") + })); + const sorted = withSlugs.sort((a, b) => { + const statusOrder: ComponentStatus[] = ["Available", "In Progress", "Not Published"]; + const statusComparison = + statusOrder.indexOf(a.status as ComponentStatus) - statusOrder.indexOf(b.status as ComponentStatus); + if (statusComparison !== 0) return statusComparison; + return a.name.localeCompare(b.name); + }); + setCards(sorted); + + const issueCounts = await fetchAllIssueCounts("Examples", sorted); + setIssueCounts(issueCounts); + }; + fetchData(); + }, [selectedFilters]); + + const [sortDirection, setSortDirection] = useState<{ [key: string]: number }>({ + status: -1, + name: 1, + }); + + const filteredCards = (() => { + const search = debouncedFilter.toLowerCase(); + + const matchesSearch = (card: ExampleProps) => + card.name.toLowerCase().includes(search) || + card.description.toLowerCase().includes(search) || + card.tags?.some((tag) => tag.toLowerCase().includes(search)) || + card.metatags?.some((tag) => tag.toLowerCase().includes(search)); + + const safeIncludes = (tags: string[] | undefined, value: string) => (tags ?? []).includes(value); + + const strictMatch = (card: ExampleProps) => { + const tags = card.tags ?? []; + + const sizeMatch = + selectedFilters.size.length === 0 || + selectedFilters.size.every((sz) => safeIncludes(tags, sz)); + + const userGoalMatch = + selectedFilters.userGoal.length === 0 || + selectedFilters.userGoal.every((goal) => safeIncludes(tags, goal)); + + const categoryMatch = + selectedFilters.category.length === 0 || + selectedFilters.category.every((cat) => safeIncludes(tags, cat)); + + return sizeMatch && userGoalMatch && categoryMatch && matchesSearch(card); + }; + + const looseMatch = (card: ExampleProps) => { + const tags = card.tags ?? []; + + const sizeMatch = + selectedFilters.size.length > 0 && + selectedFilters.size.some((sz) => safeIncludes(tags, sz)); + + const userGoalMatch = + selectedFilters.userGoal.length > 0 && + selectedFilters.userGoal.some((goal) => safeIncludes(tags, goal)); + + const categoryMatch = + selectedFilters.category.length > 0 && + selectedFilters.category.some((cat) => safeIncludes(tags, cat)); + + return (sizeMatch || userGoalMatch || categoryMatch) && matchesSearch(card); + }; + + const strictFiltered = cards.filter(strictMatch); + const looseFiltered = cards.filter((card) => looseMatch(card) && !strictMatch(card)); + + const result = [...strictFiltered, ...looseFiltered]; + + const sortBy = Object.keys(sortDirection)[0]; + const newDirection = sortDirection[sortBy]; + + const sortedFiltered = [...result].sort((a, b) => { + if (sortBy === "status") { + const statusOrder: ComponentStatus[] = ["Available", "In Progress", "Not Published"]; + const statusComparison = + statusOrder.indexOf(a.status as ComponentStatus) - statusOrder.indexOf(b.status as ComponentStatus); + if (statusComparison !== 0) return statusComparison * newDirection; + } + const key = sortBy as keyof ExampleProps; + const aField = (a as any)[key]; + const bField = (b as any)[key]; + + const aValue = sortBy === "name" + ? a.name.toLowerCase() + : Array.isArray(aField) ? (aField.length > 0 ? aField[0] : "") : (aField ?? ""); + const bValue = sortBy === "name" + ? b.name.toLowerCase() + : Array.isArray(bField) ? (bField.length > 0 ? bField[0] : "") : (bField ?? ""); + + if (aValue > bValue) return newDirection; + if (aValue < bValue) return -newDirection; + return 0; + }); + + return sortedFiltered; + })(); + + const sortData = (detailOrSortBy: string | { sortBy: string }) => { + const sortBy = typeof detailOrSortBy === "string" ? detailOrSortBy : detailOrSortBy.sortBy; + const newDirection = sortDirection[sortBy] === 1 ? -1 : 1; + setSortDirection({ [sortBy]: newDirection }); + }; + + const renderTable = () => ( + + + + + + Status + + + + + Name + + + Category + Github + + + + {cards.length === 0 ? ( + <> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ) : filteredCards.length === 0 ? ( + + + + + No matching examples found.{" "} + + Reset filters + + + + ) : ( + filteredCards.map((card, index) => ( + + + + + + {card.status === "Available" ? ( + + {toSentenceCase(card.name)} + + ) : ( + {toSentenceCase(card.name)} + )} + + + {card.tags?.map((tag) => ( + + ))} + + + {card.url ? ( + + View issue + + ) : ( + + View issue + + )} + + + )) + )} + + + ); + + return ( +
+ + Examples + + + Common patterns, pages, tasks, component configurations, flows, and more to use as a starting point when + creating government digital services. + + + setFilter(value || "")} + /> + +
+ setShowFilters((prev) => !prev)}> + {showFilters ? "Hide filters" : "Filter"} + +
+ + {showFilters && ( +
+ + {sizes.map((sz) => ( + { + handleCheckboxChange("size", sz, detail.checked); + }} + /> + ))} + + + + {userGoals.map((goal) => ( + { + handleCheckboxChange("userGoal", goal, detail.checked); + }} + /> + ))} + + + + {categories.map((cat) => ( + { + handleCheckboxChange("category", cat, detail.checked); + }} + /> + ))} + +
+ )} + + + +
+ + {cards.length === 0 ? ( + <> + + + + + + + + + + ) : filteredCards.length === 0 ? ( + + + +
+ No matching examples found.{" "} +
+
+ Reset filters +
+ + ) : ( + filteredCards.map((card) => ( + + )) + )} +
+
+ {renderTable()} +
+
+ ); +} \ No newline at end of file diff --git a/src/routes/examples/FallbackExample.tsx b/src/routes/examples/FallbackExample.tsx new file mode 100644 index 000000000..fb13f09b7 --- /dev/null +++ b/src/routes/examples/FallbackExample.tsx @@ -0,0 +1,11 @@ +import { GoabText } from "@abgov/react-components"; + +export default function FallbackExample() { + return ( +
+ + Example not loading. + +
+ ); +} \ No newline at end of file diff --git a/src/routes/examples/examplesFilterUtils.ts b/src/routes/examples/examplesFilterUtils.ts new file mode 100644 index 000000000..e69de29bb diff --git a/src/routes/patterns/patterns.module.css b/src/routes/examples/patterns.module.css similarity index 100% rename from src/routes/patterns/patterns.module.css rename to src/routes/examples/patterns.module.css diff --git a/src/routes/foundations/Accessibility.tsx b/src/routes/foundations/Accessibility.tsx index 742783f18..c033c8e47 100644 --- a/src/routes/foundations/Accessibility.tsx +++ b/src/routes/foundations/Accessibility.tsx @@ -1,12 +1,18 @@ -import { GoabDivider } from "@abgov/react-components"; +import { GoabDivider, GoabText } from "@abgov/react-components"; import { Link } from "react-router-dom"; import { ComponentContent } from "@components/component-content/ComponentContent.tsx"; export default function AccessibilityPage() { return ( -

Accessibility

-

We aim to create digital products that everyone can use, no matter their abilities or situation. This guide outlines key principles, design tips, and tools to help create accessible and inclusive experiences.

+ + Accessibility + + + We aim to create digital products that everyone can use, no matter their abilities or situation. This guide + outlines key principles, design tips, and tools to help create accessible and inclusive experiences. + +

Every component in our design system meets meets WCAG 2.2 Level AA standards. While the system has accessibility features, teams should take extra steps to ensure consistent and accessible experiences across all products and platforms.

diff --git a/src/routes/foundations/BrandGuidelines.tsx b/src/routes/foundations/BrandGuidelines.tsx index 8072e675c..9b593436c 100644 --- a/src/routes/foundations/BrandGuidelines.tsx +++ b/src/routes/foundations/BrandGuidelines.tsx @@ -1,11 +1,17 @@ -import { GoabDivider } from "@abgov/react-components"; +import { GoabDivider, GoabText } from "@abgov/react-components"; import { ComponentContent } from "@components/component-content/ComponentContent.tsx"; export default function BrandGuidelinesPage() { return ( -

Brand guidelines

-

Communications and Public Engagement (CPE) plays an important role in providing and maintaining brand identity guidelines across the Government of Alberta. These guidelines ensure all digital products are consistent and easily recognizable, building trust with users.

+ + Brand guidelines + + + Communications and Public Engagement (CPE) plays an important role in providing and maintaining brand identity + guidelines across the Government of Alberta. These guidelines ensure all digital products are consistent and + easily recognizable, building trust with users. +
diff --git a/src/routes/content/Capitalization.tsx b/src/routes/foundations/Capitalization.tsx similarity index 85% rename from src/routes/content/Capitalization.tsx rename to src/routes/foundations/Capitalization.tsx index 5628e943c..a159e7d1d 100644 --- a/src/routes/content/Capitalization.tsx +++ b/src/routes/foundations/Capitalization.tsx @@ -1,27 +1,32 @@ -import { GoabBlock, GoabDivider, GoabFormItem, GoabGrid, GoabSideMenu } from "@abgov/react-components"; -import { DoDont } from "@components/do-dont/DoDont"; -import { ComponentContent } from "@components/component-content/ComponentContent"; +import { GoabBlock, GoabDivider, GoabFormItem, GoabGrid, GoabSideMenu, GoabText } from "@abgov/react-components"; +import { DoDont } from "@components/do-dont/DoDont.tsx"; +import { ComponentContent } from "@components/component-content/ComponentContent.tsx"; const minGridWidth = "36ch"; export default function CapitalizationPage() { return ( -

Capitalization

-

Use sentence case for all headings, labels, and content.

+ + + Capitalization + + + Use sentence case for all headings, labels, and content. +

Sentence case

-

+ Sentence case means everything is lowercase except for the first word in a label, phrase, or sentence. Sentence case follows the natural patterns of written language, which makes text easier to scan and comprehend. -

-

+ + Use sentence case in most titles and headings. Only capitalize the first word of a sentence or title. -

+
@@ -56,18 +61,18 @@ export default function CapitalizationPage() {

Title case

-

+ Title case may be used in certain situations including: proper nouns, brands, products, and service names. -

-

+ + A proper noun is the name of a particular person, place, organization, or thing.
eg. “Margaret”, “Calgary”, “Government of Alberta”, or “Community Initiatives Program” -

-

+ + If a title, label, or heading includes a colon or ampersand, capitalize the first word after it. -

+

Capital case

-

+ When displaying information pulled from legacy systems there may be information that must remain in capital case due to limitations with integration. -

-

+ + Use this style only where necessary by the legacy system, since capital case is less readable, less accessible, and has the perception of emphasis. -

-

+ + Example:
Display the following information in sentence case when possible for better readability. -

+ @@ -128,20 +133,20 @@ export default function CapitalizationPage() {

References

-

+ Making a case for letter case - Medium -

-

+ + Why letter casing is important to consider during design decisions - Medium -

+ ); } diff --git a/src/routes/foundations/Color.tsx b/src/routes/foundations/Color.tsx index 07cf0624e..0cf00f8a0 100644 --- a/src/routes/foundations/Color.tsx +++ b/src/routes/foundations/Color.tsx @@ -1,13 +1,18 @@ -import { GoabDivider, GoabGrid, GoabContainer, GoabSpacer, GoabTable } from "@abgov/react-components"; +import { GoabDivider, GoabGrid, GoabContainer, GoabSpacer, GoabTable, GoabText } from "@abgov/react-components"; import { ComponentContent } from "@components/component-content/ComponentContent.tsx"; export default function FoundationsColorPage() { return ( - -

Color

-

Colors play a major role in how the Government of Alberta communicates. They serve as a tool to convey clarity, express emotions, and promote inclusivity.

- + + + Color + + + Colors play a major role in how the Government of Alberta communicates. They serve as a tool to convey + clarity, + express emotions, and promote inclusivity. +

Our palette is divided into these categories:

    diff --git a/src/routes/content/DateFormat.tsx b/src/routes/foundations/DateFormat.tsx similarity index 70% rename from src/routes/content/DateFormat.tsx rename to src/routes/foundations/DateFormat.tsx index deb7bd510..03623321b 100644 --- a/src/routes/content/DateFormat.tsx +++ b/src/routes/foundations/DateFormat.tsx @@ -1,40 +1,42 @@ -import { GoabCallout, GoabContainer, GoabDivider, GoabGrid } from "@abgov/react-components"; -import { DoDont } from "@components/do-dont/DoDont"; -import { ComponentContent } from "@components/component-content/ComponentContent"; +import { GoabCallout, GoabContainer, GoabDivider, GoabGrid, GoabText } from "@abgov/react-components"; +import { DoDont } from "@components/do-dont/DoDont.tsx"; +import { ComponentContent } from "@components/component-content/ComponentContent.tsx"; const minGridWidth = "36ch"; export default function DateFormatPage() { return ( -

    Date format

    -

    - Configuration which contains date information that includes the specification of the form - and structure of the date data within the date format in different scenarios. -

    + + Date format + + + Configuration which contains date information that includes the specification of the form and structure of the + date data within the date format in different scenarios. + - +
    + March 14, 2021 +

    Conversational and long-form

    -

    + When the date is written out in long-form (i.e. narrative, instructions, commentary, information), it is recommended that you use a more conversational and more natural “readable” tone. -

    + - +
    -

    + This presents the date in a conventional “speaking” way and aligns with the Canadian Style Guide 5.14 Dates. -

    +
    -
    March 14, 2021
    -
    + + March 14, 2021 +
    -
    March 14
    -
    March 14th
    + + March 14 + + + March 14th +
    -
    March 14th, 2021
    + + March 14th, 2021 +
    -
    MARCH 14TH, 2021
    + + MARCH 14TH, 2021 +
    -
    March 12, 21
    + + March 12, 21 +
    @@ -79,17 +92,18 @@ export default function DateFormatPage() {

    Short-hand

    -

    + When space is limited (e.g., example forms, tables, summary pages, mobile) it may be necessary to have a more condensed date displayed. -

    -

    The format remains the same, but a three-letter abbreviation for the month may be used.

    -

    + + The format remains the same, but a three-letter abbreviation for the month + may be used. + Examples:
    Jul 14, 2022
    Nov 6, 2024 -

    -

    + + Three-letter month abbreviations:
    @@ -109,38 +123,50 @@ export default function DateFormatPage() {
    Dec
    -

    +
    - + + + -
    Mar 14, 2021
    + + Mar 14, 2021 +
    -
    - - -
    Mar 12, 21
    + + Mar 12, 21 +
    -
    Mar. 12, 2021
    + + Mar. 12, 2021 +
    -
    MAR 12, 21
    + + MAR 12, 21 +
    -
    Mar 07, 21
    -
    + + Mar 07, 21 +
    -
    03/07/21
    -
    07/03/2021
    + + 03/07/21 + + + 07/03/2021 +
    @@ -148,17 +174,19 @@ export default function DateFormatPage() {

    Day of the week

    -

    + Days of the week can be included. It helps to bring clarity and comprehension of the date. The format described above is extended, with the day of the week appearing first, followed by a comma, then the date expression. -

    -

    + + Either long-form or short-form may be used, but not mixed.

    Day, Month date, Year (e.g., Friday, March 14, 2021)
    - Examples: + + Examples: + @@ -169,7 +197,9 @@ export default function DateFormatPage() {
    Tuesday, July 14, 2022Wed, November 6, 2024
    - Three-letter day abbreviations + + Three-letter day abbreviations + @@ -181,81 +211,97 @@ export default function DateFormatPage() {
    MonSun
    -

    +
    -
    Monday, March 14, 2021
    -
    Mon, Mar 14, 2021
    + + Monday, March 14, 2021 + + + Mon, Mar 14, 2021 +
    -
    Monday, Mar 12, 2021
    -
    Mon, March 12, 2021
    + + Monday, Mar 12, 2021 + + + Mon, March 12, 2021 +
    -
    Mon, Mar 12, 2021
    + + Mon, Mar 12, 2021 +
    -
    Monday March 12, 2021
    + + Monday March 12, 2021 +
    -
    - -

    + Avoid using day of the week in tabular, form, summary, or other concise displays, as it would crowd the already limited space with unnecessary information. -

    -

    Time

    -

    + When displaying time, the Government of Alberta prefers to use the 12-hour clock format. -

    -

    + + Both also prefer “am” and “pm” be written with a space after the time, without the periods as per the Canadian Style Guide. -

    -

    + + Examples:
    8:00 am
    11:45 pm{" "} -

    -

    + + When the time is written with a date, the date comes first and the time follows, after “at”. -

    -

    + + Day, Month date, Year at XX:XX am/pm -

    -

    (e.g., Friday, March 14, 2021 at 2:26 pm)

    + + (e.g., Friday, March 14, 2021 at 2:26 pm)
    -
    Monday, March 14, 2021 at 3:30 pm
    + + Monday, March 14, 2021 at 3:30 pm +
    -
    08:15 am
    + + 08:15 am +
    -
    4:43 p.m.
    + + 4:43 p.m. +
    -
    7:55 am on Saturday, May 15, 2021
    + + 7:55 am on Saturday, May 15, 2021 +
    @@ -263,17 +309,17 @@ export default function DateFormatPage() {

    Time zones

    -

    + When needed, the time zone can be written after the time in long-form or short-form. The long-form is always in parenthesis and the short-form is always a capitalized three-letter abbreviation. -

    -

    + + Examples:
    8:00 am (Eastern standard time)
    11:45 pm PDT -

    -

    + + Canadian time zones
    Pacific standard / daylight time
    @@ -282,9 +328,9 @@ export default function DateFormatPage() { Eastern standard / daylight time
    Atlantic standard / daylight time
    Newfoundland standard / daylight time
    -

    + -

    + Three letter abbreviations @@ -304,60 +350,39 @@ export default function DateFormatPage() {
    NDT
    -

    -

    + + Standard and Daylight time -

    -

    + + In the regions of Canada where daylight saving time is used, it begins on the second Sunday of March at 2 a.m. and ends on the first Sunday in November at 2 a.m. As a result, daylight saving time lasts for 34 weeks (238 days) every year, or about 65 percent of the entire year. -

    +
    - - -
    -
    Jan
    -
    Feb
    -
    Mar
    -
    Apr
    -
    May
    -
    Jun
    -
    Jul
    -
    Aug
    -
    Sep
    -
    Oct
    -
    Nov
    -
    Dec
    -
    -
    -
    - - + - + - - -
    4:43pm (MST)
    + + 4:43pm (MST) +
    - + From April to October Alberta participates in daylight saving time.
    @@ -366,14 +391,14 @@ export default function DateFormatPage() {

    Accessibility and Screen readers

    -

    + Using a npm module (accessible-date), we are able to ensure that dates displayed are readable and accessible for screen readers:
    https://github.com/MikesBarto/accessible-date -

    + Consider the following html
    @@ -396,7 +421,7 @@ export default function DateFormatPage() {
    - + The date time variables entered into the module for producing “readable” and “conversational” need to be rendered in the ISO 8601 format. diff --git a/src/routes/foundations/DesignAtGoA.tsx b/src/routes/foundations/DesignAtGoA.tsx index 0a6be92b0..b6a74b8b3 100644 --- a/src/routes/foundations/DesignAtGoA.tsx +++ b/src/routes/foundations/DesignAtGoA.tsx @@ -1,11 +1,17 @@ -import { GoabDivider } from "@abgov/react-components"; +import { GoabDivider, GoabText } from "@abgov/react-components"; import { ComponentContent } from "@components/component-content/ComponentContent.tsx"; export default function DesignAtGoAPage() { return ( -

    Design at the Government of Alberta

    -

    Citizens expect digital products that are modern, easy to use, and consistent. To meet these needs, our digital products must follow our user experience guidelines and should be tested frequently to make continuous improvement and stay relevant.

    + + Design at the Government of Alberta + + + Citizens expect digital products that are modern, easy to use, and consistent. To meet these needs, our + digital products must follow our user experience guidelines and should be tested frequently to make continuous + improvement and stay relevant. +

    User experience guidelines

    diff --git a/src/routes/content/ErrorMessages.tsx b/src/routes/foundations/ErrorMessages.tsx similarity index 87% rename from src/routes/content/ErrorMessages.tsx rename to src/routes/foundations/ErrorMessages.tsx index 4d3ddd312..2e9c7da85 100644 --- a/src/routes/content/ErrorMessages.tsx +++ b/src/routes/foundations/ErrorMessages.tsx @@ -1,4 +1,4 @@ -import { DoDont } from "@components/do-dont/DoDont"; +import { DoDont } from "@components/do-dont/DoDont.tsx"; import { GoabCheckbox, GoabDivider, @@ -7,9 +7,10 @@ import { GoabInput, GoabRadioGroup, GoabRadioItem, + GoabText } from "@abgov/react-components"; import { Link } from "react-router-dom"; -import { ComponentContent } from "@components/component-content/ComponentContent"; +import { ComponentContent } from "@components/component-content/ComponentContent.tsx"; const minGridWidth = "36ch"; @@ -17,16 +18,19 @@ export default function ErrorMessagesPage() { const noop = () => { }; return ( -

    Error messages

    -

    Error messages appear when the user’s proposed action fails.

    + + Error messages + + + Error messages appear when the user’s proposed action fails. + @@ -34,29 +38,29 @@ export default function ErrorMessagesPage() { - + error="Choose how you would like to be contacted"> + - + + + error="Confirm that the contact information is correct">

    Anatomy

    -

    + When a user inputs an unexpected value in the input field, an error message will appear below the field followed by a 16 pixels error icon. Both the icon and the error text are in red. The input field frame is displayed in red. -

    -

    Helper text

    -

    + + Helper text + When helper text and error message are both shown, the error message always appears above the helper text. -

    +
    @@ -91,7 +95,7 @@ export default function ErrorMessagesPage() {
    -

    Border

    + Border
    @@ -105,7 +109,7 @@ export default function ErrorMessagesPage() {
    -

    Button/upload area

    + Button/upload area
    @@ -134,38 +138,38 @@ export default function ErrorMessagesPage() {

    Language and tone

    -

    Be clear and concise

    -

    + Be clear and concise + Communicate errors with a brief, clear, positive and solution-oriented approach. Be direct and natural. -

    -

    Be specific

    -

    + + Be specific + Be specific about required information and what users should do to recover from the error. -

    -

    Provide a solution

    -

    + + Provide a solution + Always provide a solution to the user through clear instruction. When applicable, provide an example. -

    -

    Be empathetic

    -

    + + Be empathetic + Speak in a humanized tone to be empathetic to the user. Let the user know that you understand their frustration. -

    +

    Common error message templates

    -

    + Follow the templates and examples below for common errors to create an error message that fits your context. -

    +

    Input is empty

    -

    This error appears when user leaves a required field blank.

    + This error appears when user leaves a required field blank.
    @@ -175,7 +179,7 @@ export default function ErrorMessagesPage() {
    - + @@ -200,14 +204,14 @@ export default function ErrorMessagesPage() {

    Incorrect information format

    -

    + This error appears when the user fails to input valid/correct information such as entering an invalid postal code or phone number. -

    -

    + + To keep messages clear and concise, provide the solution to the user and include an example of a valid entry. -

    +
    @@ -217,7 +221,7 @@ export default function ErrorMessagesPage() {
    - +
    Enter a valid postal code, @@ -246,13 +250,13 @@ export default function ErrorMessagesPage() {

    Error with a date input

    -

    + This error appears when the user fails to input a valid/correct date. Date range/duration information should be provided in the error message. -

    -

    + + View more information on date formatting. -

    +
    @@ -262,7 +266,7 @@ export default function ErrorMessagesPage() {
    - +
    The student must be 16 years old or older to be eligible for funding. @@ -290,7 +294,8 @@ export default function ErrorMessagesPage() {

    Error within a value range

    -

    This error appears when user fails to input a valid/correct amount.

    + This error appears when user fails to input a valid/correct + amount.
    @@ -300,7 +305,7 @@ export default function ErrorMessagesPage() {
    - +
    Books and Materials cost must be lower than $4,000.
    @@ -309,16 +314,18 @@ export default function ErrorMessagesPage() {
    +
    +

    Input outside accepted values

    - +
    - +
    PID must be between 10 and 15 digits.
    @@ -331,14 +338,14 @@ export default function ErrorMessagesPage() {

    Upload errors

    -

    + When there is an error with the requested file, error message appears below the file upload button or area. -

    -

    + + View more information on file upload. -

    -

    + + File upload errors can appear when a user does any of the following:

    • Wrong file format uploaded.
    • @@ -347,18 +354,18 @@ export default function ErrorMessagesPage() {
    • Duplicate file is uploaded.
    • Required file is missing.
    -

    +

    Wrong file type

    - +
    - +
    The selected file must be a PDF, JPG, PNG, or TIFF.
    @@ -373,14 +380,14 @@ export default function ErrorMessagesPage() {

    File too large

    - +
    - +
    The selected file must be less than 5MB.
    @@ -394,14 +401,14 @@ export default function ErrorMessagesPage() {

    File upload failed

    - +
    - + @@ -419,14 +426,14 @@ export default function ErrorMessagesPage() {

    Duplicate file uploaded

    - +
    - + @@ -444,14 +451,14 @@ export default function ErrorMessagesPage() {

    No file selected

    - +
    - +
    Upload a work permit.
    @@ -464,10 +471,10 @@ export default function ErrorMessagesPage() {

    Invalid characters used

    -

    + This error appears when user inputs invalid characters. To keep messages clear and concise, provide a guided solution. -

    +
    @@ -494,7 +501,8 @@ export default function ErrorMessagesPage() {
    -

    When the accepted characters are known, include an example in the error message.

    + When the accepted characters are known, include an example in the error + message.
    @@ -503,7 +511,7 @@ export default function ErrorMessagesPage() {
    - +
    Alberta Bar ID must include numbers only, such as “12345.” @@ -519,7 +527,7 @@ export default function ErrorMessagesPage() {

    Incorrect number of characters

    - +
    diff --git a/src/routes/foundations/FoundationsLayout.tsx b/src/routes/foundations/FoundationsLayout.tsx index 2eb804a69..653862cad 100644 --- a/src/routes/foundations/FoundationsLayout.tsx +++ b/src/routes/foundations/FoundationsLayout.tsx @@ -1,4 +1,4 @@ -import { GoabSideMenu, GoabSideMenuHeading } from "@abgov/react-components"; +import { GoabSideMenu, GoabSideMenuGroup, GoabSpacer } from "@abgov/react-components"; import { Link, Outlet } from "react-router-dom"; import "./foundations.css"; import { SupportInfo } from "@components/support-info/SupportInfo.tsx"; @@ -8,17 +8,24 @@ export default function GetStartedLayout() {
    - Foundations + Design at GoA Accessibility Brand guidelines - Style Guide + Color Iconography Photography Logo Typography Layout + + + Capitalization + Date format + Error messages + Helper text +
    diff --git a/src/routes/content/HelperText.tsx b/src/routes/foundations/HelperText.tsx similarity index 70% rename from src/routes/content/HelperText.tsx rename to src/routes/foundations/HelperText.tsx index f52d0bd31..62fd5c909 100644 --- a/src/routes/content/HelperText.tsx +++ b/src/routes/foundations/HelperText.tsx @@ -7,30 +7,36 @@ import { GoabGrid, GoabInput, GoabTable, + GoabText } from "@abgov/react-components"; -import { DoDont } from "@components/do-dont/DoDont"; +import { DoDont } from "@components/do-dont/DoDont.tsx"; import { Link } from "react-router-dom"; -import { ComponentContent } from "@components/component-content/ComponentContent"; +import { ComponentContent } from "@components/component-content/ComponentContent.tsx"; const minGridWidth = "36ch"; export default function HelperTextPage() { return ( -

    Helper text

    -

    - Helper text is additional context and guidance that is always visible below an input. The + + + Helper text + + + Additional context and guidance that is always visible below an input. The text instructs a user on what needs to be completed to move to the next question in the form or process. -

    - Helper text is available within: - + + + + Helper text is available within: + Text Input,{" "} Radio, Dropdown,{" "} Checkbox, Button - -

    - + + +

    Considerations

    -

    Consider the following ways to convey more information:

    + Consider the following ways to convey more information: @@ -170,36 +176,48 @@ export default function HelperTextPage() { -

    View a pattern and guide on how to show more information.

    + View a pattern and guide on how to show more information.

    Anatomy

    -

    Helper text can be used with any input.

    + Helper text can be used with any input.
      -
    1. Input label + optional / required
    2. -
    3. Text Input
    4. -
    5. Helper Text
    6. +
    7. + Input label + optional / required +
    8. +
    9. + Text Input +
    10. +
    11. + Helper Text +
    -

    Examples of helper text within different inputs

    + Examples of helper text within different inputs
      -
    1. Input label + optional / required
    2. -
    3. Input control(s)
    4. -
    5. Helper Text
    6. +
    7. + Input label + optional / required +
    8. +
    9. + Input control(s) +
    10. +
    11. + Helper Text +

    Language and Tone

    -

    Keep it concise

    -

    + Keep it concise + Helper text should be short and to the point. Avoid long paragraphs or complicated explanations. -

    -

    Use plain language

    -

    + + Use plain language + Write in a language that is easy to understand for your target audience. Avoid technical jargon or complex terms.
    @@ -208,31 +226,34 @@ export default function HelperTextPage() { target="_blank"> Web writing style guide - Plain language -

    -

    Provide examples

    -

    + + Provide examples + Examples can help clarify the type of input you are looking for. For example: if you are asking for a phone number, provide an example of the format you are expecting. -

    -

    Be specific

    -

    Use specific language to describe what type of information you are looking for.

    -

    Use specific language to describe what type of information you are looking for.

    -

    + + Be specific + Use specific language to describe what type of information you are looking + for. + Use specific language to describe what type of information you are + looking for. + Write numbers using digits E.g. “342” except when the number starts the sentence or is the number ‘one’. -
    +
    + Web writing style guide – Numbers and measurements -

    +

    Usage

    -

    + Helper text generally falls into 3 different categories. Examine the patterns and examples below to use helper text properly. -

    + Disclosure Instructional @@ -240,24 +261,36 @@ export default function HelperTextPage() {

    Disclosure – Why are we asking this question

    -

    + Disclosive helper text helps a user understand the data, task or system associated with the input. It can be used to provide context or to explain what is expected from the user and can help users understand what information they need to provide and why it is needed. -

    -

    - Examples of disclosive helper text: + + + Examples of disclosure helper text:

      -
    • Your full name is used for verification
    • -
    • Emails will be sent in your language of choice
    • -
    • This will be viewable to clients
    • -
    • Providing optional info helps us assist you better
    • -
    • This address will receive your printed certificate
    • -
    • Your birthdate is used to verify your eligibility
    • +
    • + Your full name is used for verification +
    • +
    • + Emails will be sent in your language of choice +
    • +
    • + This will be viewable to clients +
    • +
    • + Providing optional info helps us assist you better +
    • +
    • + This address will receive your printed certificate +
    • +
    • + Your birthdate is used to verify your eligibility +
    -

    +
    - + @@ -289,26 +322,43 @@ export default function HelperTextPage() {

    Instructional – Directions for how to use the input

    -

    + Instructional helper text is used to provide instructions on how to interact with a particular input field or control. It can be used to explain how to use a particular feature, what actions are possible, or what the result of a certain action will be. -

    -

    + + Examples of instructional helper text:

      -
    • Search by staff name or certification number
    • -
    • Select an existing project or create a new project name
    • -
    • Use arrow keys to choose from options
    • -
    • Type in your search terms to see results
    • -
    • Select a file to upload for verification
    • -
    • Select a date from the calendar for scheduling
    • -
    • Drag and drop files to upload for review
    • -
    • Select an option from the dropdown menu to filter results
    • +
    • + Search by staff name or certification number +
    • +
    • + Select an existing project or create a new project name +
    • +
    • + Use arrow keys to choose from options +
    • +
    • + Type in your search terms to see results +
    • +
    • + Select a file to upload for verification +
    • +
    • + Select a date from the calendar for scheduling +
    • +
    • + Drag and drop files to upload for review +
    • +
    • + Select an option from the dropdown menu to filter + results +
    -

    +
    - + @@ -336,22 +386,33 @@ export default function HelperTextPage() {

    Restrictive – Rules and requirements that the input needs to meet

    -

    + Restrictive helper text indicates limitations or requirements that must be met when filling out a form or using a control. It can be used to communicate restrictions on input format, length, or content. Restrictive helper text can help users avoid errors and ensure that their input meets the required criteria. -

    -

    + + Examples of restrictive helper text:

      -
    • Must be 8 or more characters with one uppercase letter and one number
    • -
    • Must be 5MB or smaller
    • -
    • Choose a date within the last six months
    • -
    • Password must contain 1 uppercase letter and 1 number
    • -
    • File size limit: 5MB
    • +
    • + Must be 8 or more characters with one uppercase letter and one + number +
    • +
    • + Must be 5MB or smaller +
    • +
    • + Choose a date within the last six months +
    • +
    • + Password must contain 1 uppercase letter and 1 number +
    • +
    • + File size limit: 5MB +
    -

    +
    @@ -382,10 +443,10 @@ export default function HelperTextPage() {

    Formatting

    -

    + Helper text should be a short succinct statement, sentence case, with no period or punctuation. -

    +

    Accessibility

    -

    + For screen reader accessibility, consider using the aria-describedby attribute as helper text for the input control. This allows screen readers to provide additional context that would be present for a sighted user. -

    +

    References

    -

    + W3C - Using the aria-describedby property to provide a descriptive label for ui controls @@ -419,7 +480,7 @@ export default function HelperTextPage() { Aria described by Introduction to Accessibility -

    + ); } diff --git a/src/routes/foundations/Iconography.tsx b/src/routes/foundations/Iconography.tsx index cc18869fa..6241a75be 100644 --- a/src/routes/foundations/Iconography.tsx +++ b/src/routes/foundations/Iconography.tsx @@ -1,4 +1,13 @@ -import { GoabDivider, GoabContainer, GoabTable, GoabSpacer, GoabIcon, GoabBlock, GoabGrid } from "@abgov/react-components"; +import { + GoabDivider, + GoabContainer, + GoabTable, + GoabSpacer, + GoabIcon, + GoabBlock, + GoabGrid, + GoabText +} from "@abgov/react-components"; import { useContext } from "react"; import { Link } from "react-router-dom"; import { DeviceWidthContext } from "../../contexts/DeviceWidthContext"; @@ -66,9 +75,16 @@ export default function IconographyPage() { return ( -

    Iconography

    -

    Icons are simple and universal graphic symbols that communicate and enhance both the aesthetic and functional aspects of our products. While they can be used with descriptors, they can also be self-expressive and convey meaning where words cannot.

    - + + Iconography + + + Icons are simple and universal graphic symbols that communicate and enhance both the aesthetic and functional + aspects + of our products. While they can be used with descriptors, they can also be self-expressive and convey meaning + where + words cannot. +
    diff --git a/src/routes/foundations/Layout.tsx b/src/routes/foundations/Layout.tsx index b1000fbf3..86c9e8156 100644 --- a/src/routes/foundations/Layout.tsx +++ b/src/routes/foundations/Layout.tsx @@ -1,4 +1,4 @@ -import { GoabDivider, GoabTable, GoabContainer, GoabSpacer } from "@abgov/react-components"; +import { GoabDivider, GoabTable, GoabContainer, GoabSpacer, GoabText } from "@abgov/react-components"; import { Link } from "react-router-dom"; import { ComponentContent } from "@components/component-content/ComponentContent.tsx"; @@ -6,9 +6,14 @@ export default function FoundationsLayoutPage() { return ( -

    Layout

    -

    We use the layout as a structural template to support consistency across our products. By defining visual grids, spacing, and sections, we create intuitive products for our users.

    - + + Layout + + + We use the layout as a structural template to support consistency across our products. By defining visual + grids, + spacing, and sections, we create intuitive products for our users. +

    The spacing scale

    The Design System uses a spacing scale with a 16px base value to be used within layout spacing and spacing within components. See spacing for more information.

    diff --git a/src/routes/foundations/Logo.tsx b/src/routes/foundations/Logo.tsx index 651cff1a4..1c187745f 100644 --- a/src/routes/foundations/Logo.tsx +++ b/src/routes/foundations/Logo.tsx @@ -1,12 +1,18 @@ -import { GoabDivider, GoabGrid, GoabContainer, GoabSpacer } from "@abgov/react-components" +import { GoabDivider, GoabGrid, GoabContainer, GoabSpacer, GoabText } from "@abgov/react-components"; import { ComponentContent } from "@components/component-content/ComponentContent.tsx"; export default function LogoPage() { return ( -

    Logo

    -

    Our logo is an important part of our brand identity and serves as a symbol that distinguishes our digital products from others. To keep our brand consistent and recognizable, we encourage following the guidelines for proper usage.

    - + + Logo + + + Our logo is an important part of our brand identity and serves as a symbol that distinguishes our digital + products + from others. To keep our brand consistent and recognizable, we encourage following the guidelines for proper + usage. +

    Anatomy

    diff --git a/src/routes/foundations/Photography.tsx b/src/routes/foundations/Photography.tsx index e0f389f8b..3871d9a62 100644 --- a/src/routes/foundations/Photography.tsx +++ b/src/routes/foundations/Photography.tsx @@ -1,12 +1,17 @@ -import { GoabDivider } from "@abgov/react-components"; +import { GoabDivider, GoabText } from "@abgov/react-components"; import { ComponentContent } from "@components/component-content/ComponentContent.tsx"; export default function ImagesPage() { return ( -

    Photography

    -

    The Government of Alberta maintains a library of photos specifically taken for government use, ensuring they are relevant to our citizens. This collection meets our established criteria for quality and accessibility.

    - + + Photography + + + The Government of Alberta maintains a library of photos specifically taken for government use, ensuring they + are + relevant to our citizens. This collection meets our established criteria for quality and accessibility. +
    diff --git a/src/routes/foundations/Typography.tsx b/src/routes/foundations/Typography.tsx index 506943e9d..75ea5f563 100644 --- a/src/routes/foundations/Typography.tsx +++ b/src/routes/foundations/Typography.tsx @@ -1,4 +1,4 @@ -import { GoabDivider, GoabContainer, GoabSpacer } from "@abgov/react-components"; +import { GoabDivider, GoabContainer, GoabSpacer, GoabText } from "@abgov/react-components"; import { Link } from "react-router-dom"; import { ComponentContent } from "@components/component-content/ComponentContent.tsx"; @@ -6,9 +6,16 @@ export default function FoundationsTypographyPage() { return ( -

    Typography

    -

    Our typography system is designed to create a consistent and accessible experience across all Government of Alberta digital products. When paired with an effective content strategy, it enhances accessibility and makes content easy to navigate, enabling citizens to find information quickly.

    - + + Typography + + + Our typography system is designed to create a consistent and accessible experience across all Government of + Alberta + digital products. When paired with an effective content strategy, it enhances accessibility and makes content + easy to + navigate, enabling citizens to find information quickly. +

    Our fonts

    diff --git a/src/routes/content/content.css b/src/routes/foundations/content.css similarity index 98% rename from src/routes/content/content.css rename to src/routes/foundations/content.css index d9a3fa891..a8df17fe6 100644 --- a/src/routes/content/content.css +++ b/src/routes/foundations/content.css @@ -6,6 +6,7 @@ p { font: var(--goa-typography-body-l); text-align: center; min-height: 28px; + display: flex; } .month-container { diff --git a/src/routes/get-started/ComponentLifecycle.tsx b/src/routes/get-started/ComponentLifecycle.tsx index 71c617fd4..318bc667f 100644 --- a/src/routes/get-started/ComponentLifecycle.tsx +++ b/src/routes/get-started/ComponentLifecycle.tsx @@ -7,9 +7,11 @@ export default function ComponentLifecyclePage() { Component lifecycle - + This lifecycle defines the stages every component in the Design System undergoes, from Alpha to Production to Legacy. Each stage describes the component's maturity, adoption level, and support status.

    - To request new components or enhancements, please follow the{' '} +
    + + To request new components or enhancements, please follow the{" "} Design contribution process. diff --git a/src/routes/get-started/GetStartedOverview.tsx b/src/routes/get-started/GetStartedOverview.tsx index e3126d61f..6481bb6fa 100644 --- a/src/routes/get-started/GetStartedOverview.tsx +++ b/src/routes/get-started/GetStartedOverview.tsx @@ -90,7 +90,7 @@ export default function GetStartedOverviewPage() {

    How do I use the design system in my service?

    Start by using the design system components and patterns. You should expect that this will cover about 80% of your needs in a service. + href={"/examples"}>patterns. You should expect that this will cover about 80% of your needs in a service. When usability testing shows that a new solution or an improvement to an existing solution is needed, design a better solution. Use a 3rd party library, code your own, and/or share solutions with other teams. diff --git a/src/routes/get-started/developers/DevelopersTechnologies.tsx b/src/routes/get-started/developers/DevelopersTechnologies.tsx index 8f73f579f..b667b2df7 100644 --- a/src/routes/get-started/developers/DevelopersTechnologies.tsx +++ b/src/routes/get-started/developers/DevelopersTechnologies.tsx @@ -9,7 +9,7 @@ export default function DevelopersTechnologiesPage() { An overview of the technologies that make up the design system.
    - +

    Web components

    diff --git a/src/routes/get-started/developers/upgrade-guide/DevelopersUpgrade.tsx b/src/routes/get-started/developers/upgrade-guide/DevelopersUpgrade.tsx index d31e5c395..c4fc903c3 100644 --- a/src/routes/get-started/developers/upgrade-guide/DevelopersUpgrade.tsx +++ b/src/routes/get-started/developers/upgrade-guide/DevelopersUpgrade.tsx @@ -2,7 +2,7 @@ import { GoabCallout, GoabContainer } from "@abgov/react-components"; import { GoabText } from "@abgov/react-components"; import "../Developers.css"; import { ComponentContent } from "@components/component-content/ComponentContent"; -import css from "@routes/patterns/patterns.module.css"; +import css from "@routes/examples/patterns.module.css"; import { ReactGuide } from "@routes/get-started/developers/upgrade-guide/ReactGuide.tsx"; import { AngularGuide } from "@routes/get-started/developers/upgrade-guide/AngularGuide.tsx"; import { InlineCode } from "@components/inline-code/InlineCode.tsx"; @@ -70,7 +70,26 @@ export default function DevelopersUpgradePage() {
+ + See a real government service go through a version update in this short, three-part video series: +
    +
  1. + Updating versions – two ways to install the latest packages +
  2. +
  3. + Renaming components – update old names to new names +
  4. +
  5. + Updating component props – adjust component properties and clean up warnings +
  6. +
+

+ + View the upgrade videos + +

+
diff --git a/src/routes/home.tsx b/src/routes/home.tsx index 0a47c718e..777be2c42 100644 --- a/src/routes/home.tsx +++ b/src/routes/home.tsx @@ -52,10 +52,16 @@ const HomePage = () => { + { linkTo="/design-tokens" linkDisplay="View tokens" /> - @@ -114,7 +114,7 @@ const HomePage = () => { rel="noopener noreferrer" className="no-external-icon" > - Design system workflow diagram diff --git a/src/routes/patterns/PatternsLayout.tsx b/src/routes/patterns/PatternsLayout.tsx deleted file mode 100644 index dd518341d..000000000 --- a/src/routes/patterns/PatternsLayout.tsx +++ /dev/null @@ -1,39 +0,0 @@ -import { GoabSideMenu, GoabSideMenuHeading, GoabSpacer } from "@abgov/react-components"; -import {Link, Outlet} from "react-router-dom"; -import {SupportInfo} from "@components/support-info/SupportInfo.tsx"; -import { LanguageVersionContext } from "@contexts/LanguageVersionContext.tsx"; -import { useContext } from "react"; -import { getVersionedUrlPath } from "@components/version-language-switcher/version-language-constants.ts"; - -export default function PatternsLayout() { - const {language, version} = useContext(LanguageVersionContext); - const prefixUrl = getVersionedUrlPath(version, language); - - const getUrl = (path: string) => { - return prefixUrl.length > 0 ? `${prefixUrl}/${path}`: path; - } - - return ( -
-
- - - All - Public form - - Pages - Basic page layout - Start page - Task list page - Question pages - Review page - Results page - -
-
- - -
-
- ); -} diff --git a/src/routes/patterns/PatternsOverview.tsx b/src/routes/patterns/PatternsOverview.tsx deleted file mode 100644 index d55083960..000000000 --- a/src/routes/patterns/PatternsOverview.tsx +++ /dev/null @@ -1,42 +0,0 @@ -import { ComponentContent } from "@components/component-content/ComponentContent"; -import css from "./patterns.module.css"; -import { Link } from "react-router-dom"; - -export default function PatternsOverviewPage() { - return ( - -

Patterns

-

- Common patterns and page templates to use as a starting point for a government service. -

-
-

Patterns

-
    -
  • - Public form -
  • -
-
-
-

Pages

-
    -
  • - Start page -
  • -
  • - Task list page -
  • -
  • - Question page -
  • -
  • - Review page -
  • -
  • - Results page -
  • -
-
-
- ); -} diff --git a/src/routes/patterns/PublicFormPage.tsx b/src/routes/patterns/PublicFormPage.tsx deleted file mode 100644 index 29c49ef3b..000000000 --- a/src/routes/patterns/PublicFormPage.tsx +++ /dev/null @@ -1,184 +0,0 @@ -import { ComponentContent } from "@components/component-content/ComponentContent"; -import { GoabDetails } from "@abgov/react-components"; -import css from "./patterns.module.css"; -import { Link } from "react-router-dom"; - -export default function PublicFormPage() { - return ( - -

Public form

-

- Design forms that help Albertan citizens understand the task, focus on the question and its - answer, and complete the form. -

- -

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

-
- -

Form structure

-

- Use the public form structure focused on content, and asking the right questions to your user - to keep 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're telling a user
  • -
-
- -
-

Starting with one thing per page helps users to:

-
    -
  • understand what you're asking them to do
  • -
  • focus on specific questions 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:

-
    -
  • 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 doesn’t necessarily mean you should use one form field. For example, - asking a user for their address is best captured all on the same page with multiple fields. -

- -

Accessibility

-
-

- Structuring your form with one idea per page simplifies the experience, and makes your - form 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. -
  3. - 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. -
  4. -
  5. - 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 for users, particularly those with cognitive impairments and those - using assistive technologies. -
  6. -
  7. - Progressive disclosure: One idea per page allows the user to focus on - the current task and move through more information slowly. This can be especially - beneficial to users who are easily distracted or overwhelmed by too much information. -
  8. -
-
- -

Adding complexity

-

- Start by making sure that 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 to communicate progress
  • -
  • breaking the form into sections on a task list page
  • -
-
- -

Form stepper

-

- Avoid using traditional horizontal form steppers for every form. Research has shown that - horizontal form 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
  • -
  • follow the one idea per page approach, and break the form into sections as needed using a task list page
  • -
-
- -

Pages

-
- public form pages overview image -
- -
-

- 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/src/routes/patterns/ResultPage.tsx b/src/routes/patterns/ResultPage.tsx deleted file mode 100644 index 3daa3261c..000000000 --- a/src/routes/patterns/ResultPage.tsx +++ /dev/null @@ -1,50 +0,0 @@ -import { - GoabTab, - GoabTabs -} from "@abgov/react-components"; -import { ComponentContent } from "@components/component-content/ComponentContent"; -import css from "./patterns.module.css"; -import { ResultPageExamples } from "@examples/result-page/ResultPageExamples"; - -export default function ResultPage() { - return ( - <> -

Result page

-

- Let users know that they’ve completed a form, application, or task and tell them what to do next. -

- - - - - - - -

Overview

-
- result page overview image -
- -

When to use a results page

-

Use a results page when a user has submitted a form, application, or task, and there is a result to show them.

- -

What content to include

-
    -
  • details of what happens next, and when
  • -
  • a reference number (if applicable)
  • -
  • a link to save a record of the confirmation, for examples as a PDF
  • -
  • link to give feedback
  • -
  • contact details for the service
  • -
  • links to information or services that users are likely to need next
  • -
-
-
-
- - ); -} diff --git a/src/routes/patterns/StartPage.tsx b/src/routes/patterns/StartPage.tsx deleted file mode 100644 index 537c9a0d8..000000000 --- a/src/routes/patterns/StartPage.tsx +++ /dev/null @@ -1,124 +0,0 @@ -import { - GoabTab, - GoabTabs, -} from "@abgov/react-components"; -import { ComponentContent } from "@components/component-content/ComponentContent"; -import { StartPageExamples } from "@examples/start-page/StartPageExamples"; -import css from "./patterns.module.css"; - -export default function StartPage() { - return ( - <> -

Start page

-

- This is the starting point for a citizen to begin your form from within your service or from - Alberta.ca. -

- - - - - - - -
-

- Overview -

- form pattern start page image -
-

When to use a start page

-

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

-

- This is the starting point for a citizen to begin your form from within your service - or from Alberta.ca. -

-

- Provide the user with any information that is important before starting the form such - as how long it should take, list documents or information they may need to complete - the form, if there are any costs involved, or alternative ways to access the service. -

- -

A service's start page should

-
    -
  • - give the user just enough information to help them understand what the service does - and whether it will meet their need -
  • -
  • a service's name should reflects the problem it solves for users
  • -
  • be written in plain language — GOA web writing style guide.
  • -
  • - include a "start button" linking into the service, with text that's consistent with - the action you're asking users to take — for example, "Start now", "Sign in" or - "Register or update your details" -
  • -
  • - If relevant let users resume an application they've already started or update their - 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 the - service (eg. 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 what is the primary information that the user needs to know before entering - into the service. Provide that information to the user clearly, and then provide a - link to start using the service. Provide additional secondary information below the - call to action. -

-
- service page content image -
- -

Overview

-

- What the user needs to know before they enter into the service. A high level description of what the service is and what you can use it to do -

- -

Before you begin

-
    -
  • how long it will take
  • -
  • what you 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/src/routes/patterns/TaskListPage.tsx b/src/routes/patterns/TaskListPage.tsx deleted file mode 100644 index e6a0b9d79..000000000 --- a/src/routes/patterns/TaskListPage.tsx +++ /dev/null @@ -1,122 +0,0 @@ -import { - GoabCallout, - GoabTab, - GoabTabs -} from "@abgov/react-components"; -import { ComponentContent } from "@components/component-content/ComponentContent"; -import { TaskListPageExamples } from "@examples/task-list-page/TaskListPageExamples"; -import css from "./patterns.module.css"; -import { Link } from "react-router-dom"; - -export default function TaskListPage() { - return ( - <> -

Task list page

-

- This is the starting point for a citizen to begin your form from within your service or from - Alberta.ca. -

- - - - - - - -
-

- Overview -

- task list page overview image -
- -

When to use a task list page

-

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.

-

When using a task list, group related actions into tasks and show the status of the tasks.

- -

How to define a task

-

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 can be as big as an entire section of a form with multiple question pages and a review page.

-

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

- -
- show status of tasks image -
- -

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

- -
- - You have completed 0 of 3 sections. - -
- - -

How is a task list different than 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

-
- status page anatomy image -
-
    -
  1. - Page tile: heading-large -
  2. -
  3. - Status of completed sections: goa-callout -
  4. -
  5. - Section: task-list-section -
  6. -
  7. - Section heading: heading-medium -
  8. -
  9. - Task: goa-table -
  10. -
-
-
-
- - ); -} diff --git a/src/routes/root.css b/src/routes/root.css index c4d61fac5..5228c84f0 100644 --- a/src/routes/root.css +++ b/src/routes/root.css @@ -26,8 +26,8 @@ Side Menu ==================*/ .side-menu { - min-width: 180px; - width: 180px; + min-width: 250px; + width: 250px; border-right: 1px solid var(--goa-color-greyscale-200); padding-bottom: var(--goa-space-l); } diff --git a/src/routes/root.tsx b/src/routes/root.tsx index 7102b8d85..576a1ef84 100644 --- a/src/routes/root.tsx +++ b/src/routes/root.tsx @@ -3,20 +3,29 @@ import { GoabAppFooterMetaSection, GoabAppFooterNavSection, GoabAppHeader, - GoabMicrositeHeader, GoabNotification, - GoabOneColumnLayout + GoabMicrositeHeader, + GoabOneColumnLayout, + GoabTemporaryNotificationCtrl } from "@abgov/react-components"; import { useEffect, useState } from "react"; -import { Link, Outlet } from "react-router-dom"; -import Cookies from "js-cookie"; +import { Link, Outlet, useLocation } from "react-router-dom"; import "./root.css"; -import { useLocation } from "react-router-dom"; import { MAX_CONTENT_WIDTH, } from "../global-constants.ts"; -import { VersionLanguageSwitcher } from "@components/version-language-switcher/VersionLanguageSwitcher.tsx"; + + +import VersionUpdateNotification from "@components/version-language-switcher/VersionUpdateNotification"; +import { HelpButton } from "@components/version-language-switcher/HelpButton"; +import { + VersionLanguageSwitcher +} from "@components/version-language-switcher/VersionLanguageSwitcher"; +import { LanguageVersionContext } from "@contexts/LanguageVersionContext"; +import { useContext } from "react"; +import SiteWideNotification from "@components/version-language-switcher/SiteWideNotification"; + function ScrollToTop() { const { pathname } = useLocation(); @@ -29,8 +38,17 @@ function ScrollToTop() { } export default function Root() { - const isFirstVisit = Cookies.get("hasVisited"); + const { version } = useContext(LanguageVersionContext); + const location = useLocation(); + const showNotification = + location.pathname.startsWith("/components") || location.pathname.startsWith("/examples"); const [visible, setVisibility] = useState(false); + + // to show temporary notification on examples route, except temporary-notification playground which needs playground bindings + const shouldRenderTemporaryNotificationCtrl = !( + location.pathname.includes("/temporary-notification") && + (location.hash === "#tab-0" || location.hash === "" || !location.hash.includes("#tab-")) + ); useEffect(() => { @@ -39,12 +57,6 @@ export default function Root() { }, 50); }); - useEffect(() => { - setTimeout(() => { - Cookies.set("hasVisited", "true", {expires: 3650}); // increase the time everytime ppl land on so it won't expire - }, 600); // update later - }, []); - return (
@@ -54,33 +66,34 @@ export default function Root() { type={"live"} feedbackUrl="https://forms.microsoft.com/r/8Zp7zSJS6W" maxContentWidth={MAX_CONTENT_WIDTH} - version={} - /> - + version={ + <> + + + + } /> + Get started Foundations - Patterns + Examples Components Tokens - Content Get support + {showNotification && } + + - {isFirstVisit == null && - Select your development framework to see all code in your development languages. You can change this in the top right of the screen. - } - - -
Get started - Patterns + Foundations + Examples Components Design tokens - Content Submit an issue @@ -94,6 +107,13 @@ export default function Root() {
+ + {shouldRenderTemporaryNotificationCtrl && ( + + )}
); } diff --git a/src/utils/index.ts b/src/utils/index.ts index afb57330a..081c1042a 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -1,37 +1,70 @@ +import { + ComponentCardProps as ComponentProps, + ComponentStatus, + Group +} from "@components/component-card/ComponentCard.tsx"; + +type IssueGroup = "Components" | "Examples"; + export function toKebabCase(str: string) { return str - .replace(/\s+/g, '-') // Replace spaces with - - .replace(/_/g, '-') // Replace underscores with - - .replace(/([a-z])([A-Z])/g, '$1-$2') // Convert camelCase to kebab-case - .toLowerCase(); // Convert to lowercase + .replace(/\s+/g, "-") // Replace spaces with - + .replace(/_/g, "-") // Replace underscores with - + .replace(/([a-z])([A-Z])/g, "$1-$2") // Convert camelCase to kebab-case + .toLowerCase(); // Convert to lowercase } export const toSentenceCase = (str: string) => { return str.charAt(0).toUpperCase() + str.slice(1).toLowerCase(); }; -export async function fetchAllIssueCounts(cards: { name: string }[]): Promise> { +// Set cache with expiration (in ms) +function setCache(name: string, data: any, ttlMs: number = 1000 * 60 * 60 * 24) { // default: 24 hours + const record = { + data, + expiry: Date.now() + ttlMs, + }; + window.localStorage.setItem(`goa-github-${name}`, JSON.stringify(record)); +} + +// Get cache and check expiration +function getCache(name: string): any | null { + const cachedData = window.localStorage.getItem(`goa-github-${name}`); + if (cachedData) { + try { + const record = JSON.parse(cachedData); + if (record.expiry && Date.now() < record.expiry) { + return record.data; + } else { + // Expired, remove from cache + window.localStorage.removeItem(`goa-github-${name}`); + return null; + } + } catch { + // If parsing fails, treat as no cache + window.localStorage.removeItem(`goa-github-${name}`); + return null; + } + } + return null; +} + +// Enhanced GraphQL execution with caching +async function executeGraphQLQuery(cacheName: string, query: string): Promise { const token = import.meta.env.VITE_GITHUB_TOKEN || import.meta.env.VITE_GITHUB_TOKEN_ALTERNATE; if (!token) { console.error("GitHub token not provided"); - return {}; + return null; } - const queryFields = cards.map((card) => { - const alias = card.name.replace(/\s+/g, "").toLowerCase(); - const label = card.name.charAt(0).toUpperCase() + card.name.slice(1).toLowerCase(); - const labelQuery = label.includes(" ") ? `\\"${label}\\"` : label; - return `${alias}: search(query: "is:issue is:open repo:GovAlta/ui-components label:${labelQuery}", type: ISSUE, first: 1) { issueCount }`; - }).join("\n"); - - const graphQLQuery = ` - query { - ${queryFields} - } - `; + // Check cache first + const cachedData = getCache(cacheName); + if (cachedData) { + return cachedData; + } try { const response = await fetch("https://api.github.com/graphql", { @@ -40,71 +73,219 @@ export async function fetchAllIssueCounts(cards: { name: string }[]): Promise = {}; - cards.forEach((card) => { - const alias = card.name.replace(/\s+/g, "").toLowerCase(); - issueCounts[card.name] = - result.data[alias] && result.data[alias].issueCount - ? result.data[alias].issueCount - : 0; - }); - - return issueCounts; + // Cache the successful result + setCache(cacheName, result.data); + return result.data; } catch (error) { - console.error("Error fetching issue counts:", error); - return {}; + console.error("Error executing GraphQL query:", error); + return null; } } -export async function fetchIssueCount(label: string): Promise { - const token = - import.meta.env.VITE_GITHUB_TOKEN || - import.meta.env.VITE_GITHUB_TOKEN_ALTERNATE; +// Unified mapping function (Benji's consolidation approach) +function mapItemsToMetadata(items: any[], group: IssueGroup): ComponentProps[] { + const validStatuses: ComponentStatus[] = ["Available", "In Progress", "Legacy", "Not Published"]; - if (!token) { - console.error("GitHub token not provided"); - return null; + return items + .filter((item: any) => + item.fieldValues.nodes.some( + (f: any) => f.field?.name === "Category" && f.name === group + ) + ) + .map((item: any) => { + const title = item.content?.title || ""; + const name = toSentenceCase(title.trim()); + const slug = name.toLowerCase().replace(/[^\w\s-]/g, "").replace(/\s+/g, "-"); + const body = item.content?.body || ""; + const labels = item.content?.labels?.nodes.map((l: any) => toSentenceCase(l.name.trim())) || []; + + // Only apply groups for Components, not Examples + const componentGroup = group === "Components" ? labels.find((l: string) => + ["Content layout", "Inputs and actions", "Feedback and alerts", "Structure and navigation", "Utilities"] + .map(toSentenceCase) + .includes(toSentenceCase(l)) + ) : undefined; + + const statusField = item.fieldValues.nodes.find((f: any) => f.field?.name === "Status"); + const descriptionField = item.fieldValues.nodes.find((f: any) => f.field?.name === "Description"); + + const rawStatus = statusField?.name; + const status: ComponentStatus = + validStatuses.includes(rawStatus as ComponentStatus) + ? (rawStatus as ComponentStatus) + : "Not Published"; + + const designSystemUrl = item.fieldValues.nodes.find((f: any) => f.field?.name === "Design System website URL")?.text; + const designComponentFigmaUrl = item.fieldValues.nodes.find((f: any) => f.field?.name === "Design component (Figma)")?.text; + const designContributionFigmaUrl = item.fieldValues.nodes.find((f: any) => f.field?.name === "Design contribution file (Figma)")?.text; + const openIssuesUrl = item.fieldValues.nodes.find((f: any) => f.field?.name === "Open issues (Github)")?.text; + + let metatags: string[] = []; + const metatagField = item.fieldValues.nodes.find((f: any) => f.field?.name === "Metatags"); + if (metatagField?.text) { + metatags = metatagField.text.split(",").map((t: string) => t.trim().toLowerCase()); + } + + return { + name, + slug, + groups: componentGroup ? [componentGroup as Group] : [], + tags: labels.filter((l: string) => l !== componentGroup), + metatags, + description: descriptionField?.text || body, + status, + designSystemUrl, + designComponentFigmaUrl, + designContributionFigmaUrl, + openIssuesUrl, + url: item.content?.url + }; + }); +} + +// Core data fetching with caching +export async function fetchMetadataFromProject(): Promise { + const allItems: any[] = []; + let hasNextPage = true; + let endCursor = null; + let pageNumber = 0; + + while (hasNextPage) { + const cacheName = `project-items-page-${pageNumber}`; + + const query = ` + query { + node(id: "PVT_kwDOBQjO6M4A1oga") { + ... on ProjectV2 { + items(first: 100${endCursor ? `, after: \"${endCursor}\"` : ""}) { + pageInfo { + hasNextPage + endCursor + } + nodes { + content { + ... on Issue { + title + body + url + labels(first: 10) { + nodes { + name + } + } + } + } + fieldValues(first: 20) { + nodes { + ... on ProjectV2ItemFieldSingleSelectValue { + name + field { + ... on ProjectV2SingleSelectField { + name + } + } + } + ... on ProjectV2ItemFieldTextValue { + text + field { + ... on ProjectV2FieldCommon { + name + } + } + } + } + } + } + } + } + } + } + `; + + const result = await executeGraphQLQuery(cacheName, query); + if (!result) return []; + + const pageItems = result.node.items.nodes; + allItems.push(...pageItems); + + hasNextPage = result.node.items.pageInfo.hasNextPage; + endCursor = result.node.items.pageInfo.endCursor; + pageNumber++; } - const labelQuery = label.includes(" ") ? `\\"${label}\\"` : label; + return allItems; +} + +// Benji's unified approach +export async function fetchItemsFromProject(group: IssueGroup): Promise { + const allItems = await fetchMetadataFromProject(); + return mapItemsToMetadata(allItems, group); +} + +// Your original specific functions (maintained for backwards compatibility) +export async function fetchComponentMetadataFromProject(): Promise { + return fetchItemsFromProject("Components"); +} + +export async function fetchExampleMetadataFromProject(): Promise { + return fetchItemsFromProject("Examples"); +} + +// Issue count fetching with caching +export async function fetchAllIssueCounts(group: IssueGroup, cards: { name: string }[]): Promise> { + const cacheName = `all-${group.toLowerCase()}-issue-counts`; + + const queryFields = cards.map((card) => { + const alias = card.name.replace(/\s+/g, "").replace(/[^a-zA-Z ]/g, "").toLowerCase(); + const label = card.name.charAt(0).toUpperCase() + card.name.slice(1).toLowerCase(); + const labelQuery = label.includes(" ") ? `\\"${label}\\"` : label; + return `${alias}: search(query: "is:issue is:open repo:GovAlta/ui-components label:${labelQuery}", type: ISSUE, first: 1) { issueCount }`; + }).join('\n '); const query = ` query { - issues: search(query: "is:issue is:open repo:GovAlta/ui-components label:${labelQuery}", type: ISSUE, first: 1) { - issueCount - } + ${queryFields} } `; - try { - const response = await fetch("https://api.github.com/graphql", { - method: "POST", - headers: { - "Content-Type": "application/json", - Authorization: `Bearer ${token}` - }, - body: JSON.stringify({ query }) - }); + const result = await executeGraphQLQuery(cacheName, query); + if (result.errors) { + console.error("GraphQL errors:", result.errors); + return {}; + } - const result = await response.json(); + const issueCounts: Record = {}; + cards.forEach((card) => { + const alias = card.name.replace(/\s+/g, "").replace(/[^a-zA-Z ]/g, "").toLowerCase(); + issueCounts[card.name] = + result[alias] && result[alias]?.issueCount + ? result[alias].issueCount + : 0; + }); - if (result.errors) { - console.error("GraphQL errors:", result.errors); - return null; - } + return issueCounts; +} - return result.data.issues.issueCount; +// Utility function to clear cache (useful for development/debugging) +export function clearCache(): void { + try { + const keys = Object.keys(localStorage); + keys.forEach(key => { + if (key.startsWith("github-")) { + localStorage.removeItem(key); + } + }); } catch (error) { - console.error("Error fetching issue count:", error); - return null; + console.warn("Failed to clear cache:", error); } } \ No newline at end of file diff --git a/src/versioned-router.tsx b/src/versioned-router.tsx index 007d5c6cd..9cac192f0 100644 --- a/src/versioned-router.tsx +++ b/src/versioned-router.tsx @@ -44,19 +44,19 @@ import { VERSIONED_ANGULAR_URL_SEGMENT, VERSIONED_REACT_URL_SEGMENT, } from "@components/version-language-switcher/version-language-constants.ts"; -import PatternsLayout from "@routes/patterns/PatternsLayout.tsx"; -import PatternsOverviewPage from "@routes/patterns/PatternsOverview.tsx"; -import LayoutPage from "@routes/patterns/LayoutPage.tsx"; -import StartPage from "@routes/patterns/StartPage.tsx"; -import TaskListPage from "@routes/patterns/TaskListPage.tsx"; -import QuestionPage from "@routes/patterns/QuestionPage.tsx"; -import ReviewPage from "@routes/patterns/ReviewPage.tsx"; -import ResultPage from "@routes/patterns/ResultPage.tsx"; -import PublicFormPage from "@routes/patterns/PublicFormPage.tsx"; +import ExamplesLayout from "@routes/examples/ExamplesLayout.tsx"; +import PatternsOverviewPage from "@routes/examples/ExamplesOverview.tsx"; +import BasicPageLayout from "@examples/basic-page-layout.tsx"; +import TaskListPage from "@examples/task-list-page.tsx"; +import QuestionPage from "@examples/question-page.tsx"; +import ReviewPage from "@examples/review-page.tsx"; +import ResultPage from "@examples/result-page.tsx"; +import PublicForm from "@examples/public-form.tsx"; import FilterChipPage from "@routes/components/FilterChip.tsx"; import TextPage from "@routes/components/Text.tsx"; import { DrawerPage } from "@routes/components/Drawer.tsx"; import LinkPage from "@routes/components/Link.tsx"; +import TemporaryNotificationPage from "@routes/components/TemporaryNotification.tsx"; const ComponentRoute: React.FC<{ versionedPaths: Record; @@ -121,6 +121,7 @@ export const ComponentsRouter = () => { "spacer": , "table": , "tabs": , + "temporary-notification": , "text": , "text-area": , "tooltip": , @@ -146,8 +147,7 @@ export const ComponentsRouter = () => { export const PatternsRouter = () => { const patternsPaths = { - "layout": , - "start-page": , + "layout": , "task-list-page": , "question-page": , "review-page": , @@ -156,10 +156,10 @@ export const PatternsRouter = () => { return ( - } errorElement={}> + } errorElement={}> {/* Non-versioned paths components */} } /> - } /> + } /> } /> {/* Versioned paths components */} } />