From 7bf7d904b9cd368ca94300a3d6c87f4d33b9f573 Mon Sep 17 00:00:00 2001 From: Vanessa Tran Date: Fri, 23 Jan 2026 11:58:58 -0700 Subject: [PATCH 1/4] chore: update GoabIconType --- src/routes/components/Badge.tsx | 4 +- src/routes/components/Button.tsx | 6 +-- src/routes/components/Dropdown.tsx | 4 +- src/routes/components/IconButton.tsx | 4 +- src/routes/components/Icons.tsx | 48 +++++++------------ src/routes/components/Link.tsx | 6 +-- src/routes/components/MenuButton.tsx | 17 ++++++- src/routes/components/TextField.tsx | 6 +-- .../icons.json => utils/iconUtils.ts} | 23 +++++++-- tsconfig.json | 3 ++ vite.config.ts | 1 + 11 files changed, 70 insertions(+), 52 deletions(-) rename src/{routes/components/icons.json => utils/iconUtils.ts} (93%) diff --git a/src/routes/components/Badge.tsx b/src/routes/components/Badge.tsx index 611c974a8..0fc5dcc4c 100644 --- a/src/routes/components/Badge.tsx +++ b/src/routes/components/Badge.tsx @@ -10,7 +10,7 @@ import { ComponentContent } from "@components/component-content/ComponentContent import BadgeExamples from "@examples/badge/BadgeExamples.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"; +import { getIconOptions } from "@utils/iconUtils"; // == Page props == @@ -89,7 +89,7 @@ export default function BadgePage() { label: "Icon type", type: "combobox", name: "iconType", - options: [""].concat(ICONS), + options: getIconOptions(), value: "", }, { diff --git a/src/routes/components/Button.tsx b/src/routes/components/Button.tsx index 88b0ae7b6..b221c866f 100644 --- a/src/routes/components/Button.tsx +++ b/src/routes/components/Button.tsx @@ -12,7 +12,7 @@ import { ComponentProperties, ComponentProperty, } from "@components/component-properties/ComponentProperties"; -import ICONS from "@routes/components/icons.json"; +import { getIconOptions } from "@utils/iconUtils"; import { ComponentContent } from "@components/component-content/ComponentContent"; import { ButtonExamples } from "@examples/button/ButtonExamples.tsx"; import { @@ -55,14 +55,14 @@ export default function ButtonPage() { label: "Leading icon", type: "combobox", name: "leadingIcon", - options: [""].concat(ICONS), + options: getIconOptions(), value: "", }, { label: "Trailing Icon", type: "combobox", name: "trailingIcon", - options: [""].concat(ICONS), + options: getIconOptions(), value: "", }, {label: "Width", type: "string", name: "width", value: ""}, diff --git a/src/routes/components/Dropdown.tsx b/src/routes/components/Dropdown.tsx index acbb213d7..ebbe31495 100644 --- a/src/routes/components/Dropdown.tsx +++ b/src/routes/components/Dropdown.tsx @@ -9,7 +9,7 @@ import { GoabTabs, } from "@abgov/react-components"; import { ComponentBinding, Sandbox } from "@components/sandbox"; -import ICONS from "./icons.json"; +import { getIconOptions } from "@utils/iconUtils"; import { Category, ComponentHeader } from "@components/component-header/ComponentHeader.tsx"; import { ComponentProperties, @@ -60,7 +60,7 @@ export default function DropdownPage() { label: "Leading icon", type: "combobox", name: "leadingIcon", - options: [""].concat(ICONS), + options: getIconOptions(), value: "", }, { diff --git a/src/routes/components/IconButton.tsx b/src/routes/components/IconButton.tsx index d5174638a..8149a5eb6 100644 --- a/src/routes/components/IconButton.tsx +++ b/src/routes/components/IconButton.tsx @@ -12,7 +12,7 @@ import { } from "@components/component-properties/ComponentProperties.tsx"; import { ComponentBinding, Sandbox } from "@components/sandbox"; import { useState } from "react"; -import ICONS from "./icons.json"; +import { getIconOptions } from "@utils/iconUtils"; import { ComponentContent } from "@components/component-content/ComponentContent"; import { GoabIconType } from "@abgov/ui-components-common"; import { DesignEmpty } from "@components/empty-states/design-empty/DesignEmpty.tsx"; @@ -46,7 +46,7 @@ export default function IconButtonPage() { label: "Icon", type: "combobox", name: "icon", - options: [""].concat(ICONS), + options: getIconOptions(), value: "refresh", }, { diff --git a/src/routes/components/Icons.tsx b/src/routes/components/Icons.tsx index 1c83db032..7b8be9382 100644 --- a/src/routes/components/Icons.tsx +++ b/src/routes/components/Icons.tsx @@ -1,4 +1,3 @@ -import ICONS from "./icons.json"; import { useState } from "react"; import { ComponentBinding, Sandbox } from "@components/sandbox"; import { @@ -15,20 +14,22 @@ import { LegacyTestIdProperties, MarginProperty, TestIdProperty } from "@components/component-properties/common-properties.ts"; +import { getIconOptions } from "@utils/iconUtils"; const FIGMA_LINK = "https://www.figma.com/design/3pb2IK8s2QUqWieH79KdN7/%E2%9D%96-Component-library-%7C-DDD?node-id=24019-471310"; export default function IconsPage() { + const iconOptions = getIconOptions(false); const [iconsProps, setIconsProps] = useState({ - type: ICONS[0] as GoabIconType, + type: iconOptions[0] as GoabIconType, }); const [iconsBindings, setIconsBindings] = useState([ { label: "Type", type: "combobox", name: "type", - options: ICONS, - value: ICONS[0], + options: iconOptions, + value: iconOptions[0], }, { label: "Size", @@ -38,14 +39,6 @@ export default function IconsPage() { value: "", defaultValue: "medium", }, - { - label: "Theme", - type: "list", - name: "theme", - options: ["", "outline", "filled"], - value: "", - defaultValue: "outline", - }, { label: "Opacity", type: "number", @@ -91,12 +84,6 @@ export default function IconsPage() { description: "Sets the size of icon.", defaultValue: "medium", }, - { - name: "theme", - type: "outline | filled", - description: "Styles the icon to show outline or filled.", - defaultValue: "outline", - }, { name: "opacity", type: "number", @@ -147,7 +134,7 @@ export default function IconsPage() { { name: "type", type: "GoabIconType", - description: "Sets the icon.", + description: "Sets the icon. You can optionally append a theme suffix to control the icon style (e.g. search:filled or search:outline). Defaults to outline if no theme is specified.", required: true, }, { @@ -156,12 +143,6 @@ export default function IconsPage() { description: "Sets the size of icon.", defaultValue: "medium", }, - { - name: "theme", - type: "GoabIconTheme (outline | filled)", - description: "Styles the icon to show outline or filled.", - defaultValue: "outline", - }, { name: "inverted", type: "boolean", @@ -195,9 +176,9 @@ export default function IconsPage() { ]; - function onSandboxChange(iconsBindings: ComponentBinding[], props: Record) { - setIconsBindings(iconsBindings); - setIconsProps(props as { type: GoabIconType; [key: string]: unknown }); + function onSandboxChange(bindings: ComponentBinding[], props: Record) { + setIconsBindings(bindings); + setIconsProps(props as { type: GoabIconType;[key: string]: unknown }); } return ( @@ -223,7 +204,10 @@ export default function IconsPage() {

Playground

- + @@ -305,9 +289,9 @@ export default function IconsPage() { The extended icon set includes the full {" "} - Ionicons library. - {" "} + target="_blank" rel="noreferrer"> + Ionicons library. + {" "} When you need additional icons outside of the core icon set, use these icons to maintain a consistent visual language. diff --git a/src/routes/components/Link.tsx b/src/routes/components/Link.tsx index 70f5ad8c0..f42f0966f 100644 --- a/src/routes/components/Link.tsx +++ b/src/routes/components/Link.tsx @@ -9,7 +9,7 @@ import { GoabBadge, GoabTab, GoabTabs, GoabLink } from "@abgov/react-components" 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"; +import { getIconOptions } from "@utils/iconUtils"; export default function LinkPage() { @@ -21,14 +21,14 @@ export default function LinkPage() { label: "Leading Icon", type: "combobox", name: "leadingIcon", - options: [""].concat(ICONS), + options: getIconOptions(), value: "", }, { label: "Trailing Icon", type: "combobox", name: "trailingIcon", - options: [""].concat(ICONS), + options: getIconOptions(), value: "", }, { diff --git a/src/routes/components/MenuButton.tsx b/src/routes/components/MenuButton.tsx index 13950a418..c969f76c3 100644 --- a/src/routes/components/MenuButton.tsx +++ b/src/routes/components/MenuButton.tsx @@ -22,6 +22,7 @@ import { AccessibilityEmpty } from "@components/empty-states/accessibility-empty import { DesignEmpty } from "@components/empty-states/design-empty/DesignEmpty.tsx"; import { ComponentBinding, Sandbox } from "@components/sandbox"; import { CodeSnippet } from "@components/code-snippet/CodeSnippet"; +import { getIconOptions } from "@utils/iconUtils"; const FIGMA_LINK = "https://www.figma.com/design/3pb2IK8s2QUqWieH79KdN7/%E2%9D%96-Component-library-%7C-DDD?node-id=69366-164803"; @@ -39,7 +40,7 @@ type ComponentPropsType = GoabMenuButtonProps; export default function MenuButtonPage() { const { version, language } = useContext(LanguageVersionContext); - + const [menuButtonProps, setMenuButtonProps] = useState({ text: "Menu actions", type: "primary", @@ -59,6 +60,20 @@ export default function MenuButtonPage() { options: ["primary", "secondary", "tertiary"], value: "primary", }, + { + label: "Leading icon", + type: "combobox", + name: "leadingIcon", + options: getIconOptions(), + value: "", + }, + { + label: "Max width", + type: "string", + name: "maxWidth", + helpText: "Sets the maximum width of the dropdown menu options.", + value: "", + }, ]); const menuButtonProperties: ComponentProperty[] = [ diff --git a/src/routes/components/TextField.tsx b/src/routes/components/TextField.tsx index 986dee54c..15eb51cb9 100644 --- a/src/routes/components/TextField.tsx +++ b/src/routes/components/TextField.tsx @@ -13,7 +13,7 @@ import { GoabTab, GoabTabs, } from "@abgov/react-components"; -import ICONS from "./icons.json"; +import { getIconOptions } from "@utils/iconUtils"; import { CodeSnippet } from "@components/code-snippet/CodeSnippet.tsx"; import { useSandboxFormItem } from "@hooks/useSandboxFormItem.tsx"; import { ComponentContent } from "@components/component-content/ComponentContent"; @@ -85,14 +85,14 @@ export default function TextFieldPage() { label: "Leading Icon", type: "combobox", name: "leadingIcon", - options: [""].concat(ICONS), + options: getIconOptions(), value: "", }, { label: "Trailing Icon", type: "combobox", name: "trailingIcon", - options: [""].concat(ICONS), + options: getIconOptions(), value: "", }, { diff --git a/src/routes/components/icons.json b/src/utils/iconUtils.ts similarity index 93% rename from src/routes/components/icons.json rename to src/utils/iconUtils.ts index e96b8f45a..aa543a0a3 100644 --- a/src/routes/components/icons.json +++ b/src/utils/iconUtils.ts @@ -1,4 +1,5 @@ -[ +// All available icons from Ionicons library +export const ICONS = [ "accessibility", "add-circle", "add", @@ -167,7 +168,6 @@ "file-tray-full", "file-tray", "file-tray-stacked", - "filenames.ps1", "film", "filter-circle", "filter", @@ -503,5 +503,20 @@ "logo-xing", "logo-yahoo", "logo-yen", - "logo-youtube;" -] + "logo-youtube", +]; + +/** + * @param includeEmpty - Whether to include an empty string as the first option (default: true) + * @returns Array of icon options including :filled variants + */ +export function getIconOptions(includeEmpty: boolean = true): string[] { + const options: string[] = includeEmpty ? [""] : []; + + for (const icon of ICONS) { + options.push(icon); + options.push(`${icon}:filled`); + } + + return options; +} diff --git a/tsconfig.json b/tsconfig.json index c85970eb3..deffbc015 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -41,6 +41,9 @@ ], "@examples/*": [ "./src/examples/*" + ], + "@utils/*": [ + "./src/utils/*" ] } }, diff --git a/vite.config.ts b/vite.config.ts index 78e4ecc37..58322d0bf 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -16,6 +16,7 @@ export default defineConfig({ "@hooks": path.resolve(__dirname, "./src/hooks"), "@contexts": path.resolve(__dirname, "./src/contexts"), "@examples": path.resolve(__dirname, "./src/examples"), + "@utils": path.resolve(__dirname, "./src/utils"), }, }, }); From 476793feaac7783165996ff83f0cc0e38d105b9f Mon Sep 17 00:00:00 2001 From: Vanessa Tran Date: Fri, 23 Jan 2026 12:53:36 -0700 Subject: [PATCH 2/4] chore: doc minHeight and maxHeight for container --- src/routes/components/Container.tsx | 36 +++++++++++++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) diff --git a/src/routes/components/Container.tsx b/src/routes/components/Container.tsx index 820966d8e..6439d761a 100644 --- a/src/routes/components/Container.tsx +++ b/src/routes/components/Container.tsx @@ -1,4 +1,4 @@ -import { useState } from "react"; +import { useContext, useState } from "react"; import { ComponentBinding, Sandbox } from "@components/sandbox"; import { ComponentProperties, @@ -16,6 +16,7 @@ import { ComponentContent } from "@components/component-content/ComponentContent const FIGMA_LINK = "https://www.figma.com/design/3pb2IK8s2QUqWieH79KdN7/%E2%9D%96-Component-library-%7C-DDD?node-id=1789-12623"; import { DesignEmpty } from "@components/empty-states/design-empty/DesignEmpty.tsx"; import { AccessibilityEmpty } from "@components/empty-states/accessibility-empty/AccessibilityEmpty.tsx"; +import { LanguageVersionContext } from "@contexts/LanguageVersionContext.tsx"; // == Page props == const componentName = "Container"; @@ -29,6 +30,7 @@ const relatedComponents = [ type ComponentPropsType = GoabContainerProps; export default function ContainerPage() { + const { version } = useContext(LanguageVersionContext); const [containerProps, setContainerProps] = useState({}); const [containerBindings, setContainerBindings] = useState([ @@ -71,6 +73,20 @@ export default function ContainerPage() { requirement: "optional", value: "", }, + { + label: "Min Height", + type: "string", + name: "minHeight", + requirement: "optional", + value: "", + }, + { + label: "Max Height", + type: "string", + name: "maxHeight", + requirement: "optional", + value: "", + }, ]); const oldComponentProperties: ComponentProperty[] = [ @@ -170,6 +186,16 @@ export default function ContainerPage() { type: "string", description: "Sets the maximum width of the container.", }, + { + name: "minHeight", + type: "string", + description: "Sets the minimum height of the container.", + }, + { + name: "maxHeight", + type: "string", + description: "Sets the maximum height of the container.", + }, { name: "title", lang: "angular", @@ -231,7 +257,13 @@ export default function ContainerPage() {

Playground

- properties={containerBindings} onChange={onSandboxChange} fullWidth> + + properties={version === "new" + ? containerBindings + : containerBindings.filter(b => b.name !== "minHeight" && b.name !== "maxHeight")} + onChange={onSandboxChange} + fullWidth + >

Detach to use

Add things inside me

From b1a39e31d1ece26ea25169afe4aeb7ef6b6d37e9 Mon Sep 17 00:00:00 2001 From: Vanessa Tran Date: Fri, 23 Jan 2026 13:03:32 -0700 Subject: [PATCH 3/4] chore: add leadingIcon and maxWidth to MenuButton --- src/routes/components/MenuButton.tsx | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/routes/components/MenuButton.tsx b/src/routes/components/MenuButton.tsx index c969f76c3..f4bde288c 100644 --- a/src/routes/components/MenuButton.tsx +++ b/src/routes/components/MenuButton.tsx @@ -89,6 +89,16 @@ export default function MenuButtonPage() { description: "Controls the visual style of the trigger button.", defaultValue: "primary", }, + { + name: "leadingIcon", + type: "GoabIconType", + description: "Optional leading icon appearing within the button.", + }, + { + name: "maxWidth", + type: "string", + description: "Sets the maximum width of the dropdown menu.", + }, TestIdProperty, { name: "onAction", From fa2d04d5ba2509885048bbb3f10aff7448c2529a Mon Sep 17 00:00:00 2001 From: Vanessa Tran Date: Fri, 23 Jan 2026 13:24:17 -0700 Subject: [PATCH 4/4] chore: add id to GoabText --- src/routes/components/Text.tsx | 75 ++++++++++++++++++++++++++++++---- 1 file changed, 66 insertions(+), 9 deletions(-) diff --git a/src/routes/components/Text.tsx b/src/routes/components/Text.tsx index aa00b559d..cecb93864 100644 --- a/src/routes/components/Text.tsx +++ b/src/routes/components/Text.tsx @@ -1,4 +1,4 @@ -import { useState } from "react"; +import { useContext, useState } from "react"; import { ComponentBinding, Sandbox } from "@components/sandbox"; import { ComponentProperties, @@ -9,10 +9,12 @@ import { GoabText, GoabTab, GoabTabs, GoabBadge } from "@abgov/react-components" 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 { LanguageVersionContext } from "@contexts/LanguageVersionContext.tsx"; const FIGMA_LINK = "https://www.figma.com/design/3pb2IK8s2QUqWieH79KdN7/%E2%9D%96-Component-library-%7C-DDD?node-id=27301-303449"; export default function TextPage() { + const { version } = useContext(LanguageVersionContext); const [textProps, setTextProps] = useState({}); const [textBindings, setTextBindings] = useState([ @@ -57,8 +59,53 @@ export default function TextPage() { options: ["none", "3xs", "2xs", "xs", "s", "m", "l", "xl", "2xl", "3xl", "4xl"], value: "none", }, + { + label: "Id", + type: "string", + name: "id", + value: "", + }, ]); + const oldComponentProperties: ComponentProperty[] = [ + { + name: "tag", + type: "h1 | h2 | h3 | h4 | h5 | span | div | p", + description: "Sets the tag and text size.", + defaultValue: "div" + }, + { + name: "size", + type: "heading-xl | heading-l | heading-m | heading-s | heading-xs | body-l | body-m | body-s | body-xs", + description: "Overrides the text size from the 'as' property." + }, + { + name: "maxWidth", + type: "string", + description: "Sets the max width.", + defaultValue: "65ch", + lang: "react", + }, + { + name: "maxwidth", + type: "string", + description: "Sets the max width.", + defaultValue: "65ch", + lang: "angular", + }, + { + name: "color", + type: "primary | secondary", + description: "Sets the text colour.", + defaultValue: "primary" + }, + { + name: "mt,mr,mb,ml", + type: "none | 3xs | 2xs | xs | s | m | l | xl | 2xl | 3xl | 4xl", + description: "Apply margin to the top, right, bottom, and/or left of the component.", + }, + ]; + const componentProperties: ComponentProperty[] = [ { name: "tag", @@ -72,17 +119,22 @@ export default function TextPage() { description: "Overrides the text size from the 'as' property." }, { - name: "maxWidth", - type: "string", - description: "Sets the max width.", - defaultValue: "65ch" + name: "maxWidth", + type: "string", + description: "Sets the max width.", + defaultValue: "65ch" }, - { + { name: "color", type: "primary | secondary", description: "Sets the text colour.", defaultValue: "primary" - }, + }, + { + name: "id", + type: "string", + description: "Sets the HTML id attribute on the text element.", + }, { name: "mt,mr,mb,ml", type: "none | 3xs | 2xs | xs | s | m | l | xl | 2xl | 3xl | 4xl", @@ -108,13 +160,18 @@ export default function TextPage() {

Playground

- + b.name !== "id")} + onChange={onSandboxChange} + > Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. - +