Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
104 commits
Select commit Hold shift + click to select a range
b560d51
chore: stop deploying to the next branch
chrisolsen Feb 24, 2026
5fe0d6a
chore(deps): bump devalue from 5.6.2 to 5.6.3
dependabot[bot] Feb 24, 2026
c2fe3c3
chore(deps-dev): bump hono from 4.11.7 to 4.12.2
dependabot[bot] Feb 24, 2026
558046e
feat(#3396): add heading-2xs to Text
Copilot Feb 17, 2026
82022fa
feat(#3407): add orientation prop for tabs & skip focus when load
twjeffery Feb 18, 2026
990c6c4
feat(#3152): update app-header to v2
twjeffery Nov 17, 2025
0931144
bug(#2655): calculate popover position when inside a modal
willcodeforcoffee Feb 10, 2026
fbc9120
feat(#3229): allow text option, add size, variant to MenuButton
vanessatran-ddi Feb 25, 2026
fa147ad
chore: add permissions to gh workflow file
chrisolsen Feb 23, 2026
4d2f5cd
chore: update angular/cli
chrisolsen Feb 23, 2026
b52aedd
chore: update semantic-release npm
chrisolsen Feb 23, 2026
6fe574a
chore: npm audit updates
chrisolsen Feb 24, 2026
7283990
chore: update svelte for security fixes
chrisolsen Feb 24, 2026
35a7fe3
chore: nx migrate to 22.5.2
chrisolsen Feb 24, 2026
ad71456
chore: upgrade nx-release lib
chrisolsen Feb 25, 2026
7412ea9
chore: npm audit fix
chrisolsen Feb 25, 2026
ee33cd4
fix(#3399): correct V2 checkbox spacing behavior
twjeffery Jan 15, 2026
b7e7433
chore(deps): bump @angular/core from 20.3.16 to 20.3.17
dependabot[bot] Feb 27, 2026
3372f98
chore(deps-dev): bump rollup and @angular-devkit/build-angular
dependabot[bot] Feb 27, 2026
d6e3969
fix: calendar specs are failing due to a hardcoded date
willcodeforcoffee Mar 3, 2026
8a19631
chore: nx updates
chrisolsen Mar 3, 2026
2b5ba9d
chore: npm audit updates
chrisolsen Mar 3, 2026
9e80077
chore: npm audit updates
chrisolsen Mar 3, 2026
388a118
fix(#3493): show tooltip on hover for Work Side Menu Group
bdfranck Mar 3, 2026
00a015d
feat(#3050): Add search functionality and component thumbnails
twjeffery Feb 6, 2026
2c6a80a
chore(deps): bump svgo
dependabot[bot] Mar 5, 2026
b9f38a2
chore(deps): bump @tootallnate/once, jest-environment-jsdom and jest-…
dependabot[bot] Mar 5, 2026
3be3c17
chore(deps-dev): bump immutable from 5.1.4 to 5.1.5
dependabot[bot] Mar 4, 2026
5af6313
chore(deps-dev): bump @hono/node-server from 1.19.9 to 1.19.10
dependabot[bot] Mar 4, 2026
38be012
fix(#3455,#3450): Updated top and bottom positioning for Popover
ArakTaiRoth Feb 20, 2026
0ad2789
chore(deps): bump dompurify from 3.3.1 to 3.3.2
dependabot[bot] Mar 5, 2026
29aba73
feat(#3211): Upgrade Angular to v21 and TypeScript to v5.9
willcodeforcoffee Feb 17, 2026
374dc31
fix(#3273): keep Side Menu Group open
bdfranck Feb 12, 2026
504e7e3
chore: add lib to help in updating npm libs
chrisolsen Mar 5, 2026
be1da4f
chore: nx migrate
chrisolsen Mar 5, 2026
710559b
chore: update all libs to most recent minor versions
chrisolsen Mar 5, 2026
6be1587
chore: make package versions specific
chrisolsen Mar 5, 2026
183d34a
feat(docs): enhance search with tokens, pages, and improved UX
twjeffery Feb 24, 2026
0de3eab
feat(#2893): add open prop to SideMenuGroup
bdfranck Mar 5, 2026
6a3d871
feat(#3344): add multi-column sorting to Table and TableSortHeader (#…
twjeffery Mar 7, 2026
a134448
feat(#3569): fix the PushDrawer open prop so the docs site works (#3542)
willcodeforcoffee Mar 10, 2026
ee2816e
feat: Rewrote Popover using Popover and Anchor Position API (#3478)
ArakTaiRoth Mar 10, 2026
e0433ad
fix: use Node 22 for Netlify deploys (#3543)
twjeffery Mar 10, 2026
6a2325f
Add Get Support documentation page (#3480)
twjeffery Mar 10, 2026
480661b
fix(#3397): use existing design tokens in Astro docs (#3515)
bdfranck Mar 10, 2026
aae50a8
docs: add push drawer documentation page (#3521)
twjeffery Mar 11, 2026
ca60800
feat(docs): automate component API extraction in build pipeline (#3513)
twjeffery Mar 11, 2026
f3544de
chore: npm updates
chrisolsen Mar 11, 2026
18568b5
chore(deps): bump tar and npm
dependabot[bot] Mar 12, 2026
3796d9d
chore(deps-dev): bump yauzl from 3.2.0 to 3.2.1
dependabot[bot] Mar 14, 2026
e21f768
feat(#3059): add Get Started section with submenu, content pages, and…
twjeffery Mar 13, 2026
62376c6
chore: add v2 docs publish github action
chrisolsen Mar 13, 2026
f32a262
chore: fix formatting in release-ci
chrisolsen Mar 16, 2026
93bd89a
feat(#3402): dispatch _navigate on WorkSideMenuItem click for SPA nav…
vanessatran-ddi Mar 13, 2026
11a6328
feat(#3549): add App Header V2 documentation and experimental wrappers
twjeffery Mar 10, 2026
f418493
chore: revert the docs deploy
chrisolsen Mar 16, 2026
4542123
fix(#3581): use dynamic content collection for nav instead of hardcod…
twjeffery Mar 17, 2026
d86d3fd
chore(deps): bump @angular/core from 21.2.1 to 21.2.4
dependabot[bot] Mar 14, 2026
6c155c6
chore(deps): bump devalue from 5.6.3 to 5.6.4
dependabot[bot] Mar 12, 2026
e59b7b0
chore(deps-dev): bump hono from 4.12.5 to 4.12.7
dependabot[bot] Mar 11, 2026
511b5c6
chore(deps): bump @angular/compiler from 21.2.1 to 21.2.4
dependabot[bot] Mar 17, 2026
b47e23f
chore: npm audit
chrisolsen Mar 17, 2026
99b850f
chore: minor deps update
chrisolsen Mar 17, 2026
10607af
docs(#3537): add roadmap, dev setup, and update pages
bdfranck Mar 13, 2026
4758fef
fix: add onNavigate to Get Started Sub Menu
bdfranck Mar 17, 2026
29416b7
fix: use correct filename in Contribute docs
bdfranck Mar 17, 2026
205f7a9
feat(#2469): add push drawer experimental wrappers
twjeffery Mar 13, 2026
3e694b3
feat(#3596): add preview images to example grid cards
twjeffery Mar 17, 2026
5a3005b
feat(#3300, docs): addition of motion foundations page
mxsoco Mar 19, 2026
e998fdc
fix(#3498): modified padding and border on radio group.
mxsoco Mar 19, 2026
eafe34f
feat(#2885): add work side menu item popover notification
vanessatran-ddi Mar 19, 2026
0431442
feat(#3446): add workspace service type example
twjeffery Mar 18, 2026
9230823
chore: remove need for npm token
chrisolsen Mar 20, 2026
aa5636e
fix(#3497): fixed how the Angular Calendar and DatePicker components …
willcodeforcoffee Mar 3, 2026
afe172f
fix(#3497): remove build dependency on tests using library code
willcodeforcoffee Mar 23, 2026
7f42aa8
feat(#3529): add letter spacing to headings
bdfranck Mar 18, 2026
72cc4d1
feat(#3544): make icon optional in Work Side Menu Group & Item
bdfranck Mar 23, 2026
7024815
feat(#3580): push drawer V2 styling and dynamic edge behavior
twjeffery Mar 17, 2026
88bd777
chore: remove non-required flaky test
chrisolsen Mar 23, 2026
5ef15f9
chore(deps): bump h3 from 1.15.5 to 1.15.10
dependabot[bot] Mar 23, 2026
ccbf23c
fix: just a change to get an npm publish
chrisolsen Mar 23, 2026
e8675f8
feat(#3612): add favicon, web app manifest, and OG metadata to docs site
twjeffery Mar 20, 2026
345974d
feat(#3474): add in motion tokens to tokens page on docs site
mxsoco Mar 23, 2026
341ad63
fix: Updating the design tokens package
ArakTaiRoth Mar 24, 2026
e9e2866
fix(#3607): update the interaction area to just around the checkbox o…
mxsoco Mar 20, 2026
43bd1a3
chore: don't run test before publishing
chrisolsen Mar 23, 2026
691e84f
Revert "chore: don't run test before publishing"
chrisolsen Mar 24, 2026
903fd30
fix(#3505): Fix icon click and focus on Link
bdfranck Mar 24, 2026
8ca4a49
fix(#3673): docs site bug sweep - push drawer filters, side menu, mul…
twjeffery Mar 24, 2026
ea87b91
fix(#3540): add manual positioning to Popover when the browser does n…
willcodeforcoffee Mar 24, 2026
11ce985
feat(#3676): show subcomponent APIs on parent component pages
twjeffery Mar 24, 2026
b0913d9
chore: fix periodically failing tests
chrisolsen Mar 30, 2026
43ba7a8
chore: add v2 docs public github action job
chrisolsen Mar 13, 2026
5cd7fc1
feat(#3690): move experimental wrappers into main wrappers
bdfranck Mar 26, 2026
c1fc786
chore: Updating our astro default site URL
ArakTaiRoth Mar 30, 2026
09934de
chore: skip more currently broken tests
chrisolsen Mar 30, 2026
c8c4680
feat(#3511): add links to old v1 docs
bdfranck Mar 30, 2026
5d79bc9
fix(#3614): add padding for all IconSizes
willcodeforcoffee Mar 25, 2026
d14e272
feat(#3080): New Foundation pages
ArakTaiRoth Mar 19, 2026
de61045
fix(#3411): audit and improve all component configuration examples
twjeffery Mar 24, 2026
661651c
chore: Updating web-components from 1.x to 2.x
ArakTaiRoth Mar 31, 2026
5d88e17
fix(#3685): adjust width of "reveal" slot for checkbox and radio buttons
mxsoco Mar 31, 2026
ece047c
fix(#3685): remove width calculation from Radio Item
mxsoco Mar 31, 2026
52b4ca3
Merge pull request #3721 from GovAlta/next
chrisolsen Mar 31, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
48 changes: 48 additions & 0 deletions .claude/rules/common-utilities.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# Common Utilities — Use These, Don't Reinvent Them

All utilities are in `libs/web-components/src/common/`. Always check here before writing your own.

## utils.ts

| Function | Purpose |
|----------|---------|
| `typeValidator(msg, values, opts)` | Creates runtime validator + TypeScript type from same array |
| `toBoolean(value)` | String to boolean (`"false"` -> false, `""` -> true) |
| `fromBoolean(value)` | Boolean to string (`true` -> `"true"`) |
| `dispatch(el, name, detail, opts)` | External consumer events (underscore-prefixed names) |
| `relay(el, name, data, opts)` | Internal parent-child messaging (form components) |
| `receive(el, handler)` | Listen for internal relay messages |
| `getSlottedChildren(rootEl)` | Get elements assigned to a slot |
| `announceToScreenReader(text)` | Temporary aria-live announcement |
| `performOnce(timeoutId, action, delay)` | Debounce |
| `validateRequired(name, props)` | Check required props have values |
| `findFirstFocusableNode(nodes)` | Find first focusable element (supports shadow DOM) |
| `generateRandomId()` | 7-char random alphanumeric |
| `clamp(value, min, max)` | Numeric clamping |
| `watch(fn, deps)` | Explicit dependency tracking for `$:` blocks |
| `styles(...css)` | Conditional style string builder |

## styling.ts

| Function | Purpose |
|----------|---------|
| `calculateMargin(mt, mr, mb, ml)` | Converts Spacing values to inline margin styles |
| `Spacing` type | `"none" \| "3xs" \| "2xs" \| "xs" \| "s" \| "m" \| "l" \| "xl" \| "2xl" \| "3xl" \| "4xl" \| null` |

## Other files

| File | Purpose |
|------|---------|
| `context-store.ts` | Cross-shadow-DOM context API (replaces Svelte's native context) |
| `calendar-date.ts` | Timezone-safe date class for DatePicker/Calendar |
| `no-scroll.ts` | Body scroll lock action for Modal/Drawer |
| `breakpoints.ts` | `MOBILE_BP` (624px), `TABLET_BP` (1024px) |
| `validators.ts` | `isValidDimension()` for CSS dimension strings |
| `urls.ts` | URL matching for navigation active state |

## relay() vs dispatch() — The Boundary Rule

- `relay()` / `receive()`: Internal, between DS components only. Uses single `"msg"` event with action discriminator. For form parent-child coordination.
- `dispatch()`: External, for consumer applications. Named events with underscore prefix (`_click`, `_change`).

If the message is between two DS components, use relay. If it's for the consuming app, use dispatch.
74 changes: 74 additions & 0 deletions .claude/rules/component-authoring.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
# Component Authoring Standards

## Script Section Order

Every Svelte component script follows this order:

1. Imports
2. Validators (`typeValidator` declarations)
3. Type declarations
4. Exported props (ordered: required > content > state > visual > a11y > version > margins)
5. Private state (underscore prefix: `_rootEl`, `_isOpen`)
6. Reactive declarations (`$:`)
7. Lifecycle (`onMount`, `onDestroy`)
8. Event handlers / functions

## Universal Props

Every component must include:

- `testid: string = ""` with `data-testid={testid}` on root element
- `mt, mr, mb, ml: Spacing = null` with `style={calculateMargin(mt, mr, mb, ml)}`
- `version: "1" | "2" = "1"` with `class:v2={version === "2"}`

## Boolean Props

Web component attributes are always strings. Boolean props: `export let disabled: string = "false"` with `$: isDisabled = toBoolean(disabled)`.

Note: `toBoolean("")` returns `true` (HTML attribute semantics).

## Enum Props

Always use `typeValidator` for enum/union props. Use the object form `{ required: true }` over the boolean shorthand.

```typescript
const [Types, validateType] = typeValidator("Button type", ["primary", "secondary"], { required: true });
type ButtonType = (typeof Types)[number];
export let type: ButtonType = "primary";
onMount(() => { validateType(type); });
```

## Events

- External (for consumers): `dispatch(_rootEl, "_change", { name, value }, { bubbles: true })`
- Internal (between DS components): `relay()` / `receive()` -- never use `dispatch()` for parent-child coordination
- Event details must be objects (for future extensibility), not bare values
- Use separate events for separate operations

## Lifecycle

- Validate all typeValidators in `onMount`
- rootEl event listeners auto-clean on removal. Do NOT add removeEventListener for rootEl in onDestroy.
- document/window listeners DO need cleanup in onDestroy.

## Slots

Slot names are lowercase. Check existence before rendering with `$$slots`. Use **props** for simple text, **slots** for rich content, both when either should work:

```svelte
{#if $$slots.heading}
<slot name="heading" />
{:else if heading}
<span>{heading}</span>
{/if}
```

Use `getSlottedChildren()` from `common/utils.ts` to access child elements in slots.

## Naming

- Prop names: always lowercase (`leadingicon` not `leadingIcon`)
- Private state: underscore prefix (`_isOpen`)
- Functions: must have verbs (`handleClick`, `getMenuLinks`)
- Size values: use `"default"` not `"regular"`
- Locale: `en-CA` always
98 changes: 98 additions & 0 deletions .claude/rules/framework-wrappers.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
# Framework Wrapper Standards

## Cross-Framework Rule

Every Svelte change requires corresponding React and Angular updates. Props must match across all three frameworks (required/optional, naming, types, data formats). This is the #1 source of review rounds.

## React Wrapper Template

Two interfaces: WCProps (private, lowercase, strings) and GoabXxxProps (exported, camelCase, real types).

```typescript
interface WCProps extends Margins {
name: string;
disabled?: string;
testid?: string;
}

export interface GoabXxxProps extends Margins, DataAttributes {
name: string;
disabled?: boolean;
onChange?: (detail: GoabXxxOnChangeDetail) => void;
testId?: string;
children?: ReactNode;
}

export function GoabXxx({ disabled, onChange, children, ...rest }: GoabXxxProps): JSX.Element {
const el = useRef<HTMLElement>(null);
const _props = transformProps<WCProps>(rest, lowercase);

useEffect(() => {
if (!el.current) return;
const current = el.current;
const listener = (e: Event) => {
const detail = (e as CustomEvent<GoabXxxOnChangeDetail>).detail;
onChange?.({ ...detail, event: e });
};
current.addEventListener("_change", listener);
return () => current.removeEventListener("_change", listener);
}, [el, onChange]);

return (
<goa-xxx ref={el} {..._props} disabled={disabled ? "true" : undefined}>
{children}
</goa-xxx>
);
}
```

Key: Boolean props pass `"true"` or `undefined`, never `"true"` or `"false"`. Event callbacks always spread detail and add `event: e`. Types from `@abgov/ui-components-common`.

## Angular Wrapper Template

Non-form components extend `GoabBaseComponent`. Form controls extend `GoabControlValueAccessor`.

```typescript
@Component({
standalone: true,
selector: "goab-xxx",
template: `
@if (isReady) {
<goa-xxx
[attr.type]="type"
[attr.disabled]="disabled ? 'true' : undefined"
[attr.testid]="testId"
[attr.mt]="mt" [attr.mb]="mb" [attr.ml]="ml" [attr.mr]="mr"
(_click)="_onClick($event)"
>
<ng-content />
</goa-xxx>
}
`,
schemas: [CUSTOM_ELEMENTS_SCHEMA],
})
export class GoabXxx extends GoabBaseComponent implements OnInit {
@Input() type?: GoabXxxType;
@Input({ transform: booleanAttribute }) disabled?: boolean;
@Output() onClick = new EventEmitter<GoabXxxOnClickDetail>();

isReady = false;
constructor(private cdr: ChangeDetectorRef) { super(); }

ngOnInit(): void {
setTimeout(() => {
this.isReady = true;
this.cdr.detectChanges();
}, 0);
}

_onClick(e: Event) {
this.onClick.emit({
...(e as CustomEvent<GoabXxxOnClickDetail>).detail,
event: e,
});
}
}
```

Key: `isReady` + `setTimeout(0)` is non-negotiable (every component). Use `[attr.xxx]` for web component attributes. Use `booleanAttribute` transform for boolean inputs. Form controls add `#goaComponentRef`, `NG_VALUE_ACCESSOR`, `markAsTouched()`.
44 changes: 44 additions & 0 deletions .claude/rules/styling.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# Styling Standards

## Design Tokens

All styling uses CSS custom properties. No exceptions. No hardcoded colors, font sizes, border-radius, or spacing.

Token naming: `--goa-[component]-[variant]-[state]-[property]`

Use `rem` over `px` even when there is no token value (`20px` = `1.25rem`).

## :host

Every component starts with:

```css
:host {
box-sizing: border-box;
font-family: var(--goa-font-family-sans);
}
```

## V2 Token Fallbacks (Mandatory)

Every V2 CSS variable must fall back to V1. This is the most repeated review feedback on V2 PRs.

```css
color: var(--goa-component-v2-token, var(--goa-v1-fallback));
```

## Class Binding

Variant classes use string interpolation. State classes use `class:` directive.

```svelte
<div class="goa-badge badge-{type}" class:v2={version === "2"} class:disabled={isDisabled}>
```

## Responsive

Use PostCSS aliases: `@media (--mobile) { ... }`. Breakpoints: mobile = 624px, tablet = 1024px.

## CSS Simplification

Prefer `gap` over margins between items. Remove redundant CSS properties. No consumer CSS customization by design (no `::part()`, no exposed custom properties).
58 changes: 58 additions & 0 deletions .claude/rules/testing.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# Testing Standards

## Testing Tiers

| Tier | Framework | When to Use |
|------|-----------|-------------|
| WC Unit | Vitest + @testing-library/svelte | Prop rendering, basic state, margins |
| React Unit | Vitest + @testing-library/react | Wrapper prop transformation |
| React Browser | Vitest + Playwright (Chromium + Firefox) | Event behavior, interactions, shadow DOM |
| Angular | Jest + TestBed | Wrapper attribute binding, form integration |

**Browser tests for events, unit tests for props.**

## Enforced Patterns

**Locators are always truthy. Don't assert on them.**
`getBy*` always returns an object. `expect(el).toBeTruthy()` is meaningless. Assert on actual state instead.

**Declare locators outside `waitFor`.**
Putting locators inside `waitFor` defeats its purpose.

```typescript
// Bad
await vi.waitFor(() => {
const el = result.getByTestId("button");
expect(el).toHaveTextContent("Submit");
});

// Good
const el = result.getByTestId("button");
await vi.waitFor(() => {
expect(el).toHaveTextContent("Submit");
});
```

**No timeout hacks.** Browser tests already retry. Default `waitFor` timeout is 1000ms.

**Use `click()`, not `dispatchEvent`** in browser tests.

**Use `data-testid` for selectors**, but prefer `getByText` when it makes the test more accessible.

**Tests must test what they claim.** If named "should show error state", assert on error state, not just element existence.

**Use `it()` not `test()`.**

## What to Test

Every component: basic rendering, all prop variants, event dispatch, margins, disabled state, `data-*` passthrough, ARIA where applicable.

V2 components need their own browser tests.

## Angular Testing

Use a test host component (test as a consumer would). `fakeAsync` + `tick()` for the `setTimeout(0)` pattern. Double `detectChanges()` (before and after `tick()`). Query via `By.css("goa-xxx")`.

## PR Playground Files

`feat{N}` not `feat-{N}` (no hyphen). Bug pages in `apps/prs/react/src/routes/bugs/`, features in `features/`.
11 changes: 8 additions & 3 deletions .github/workflows/pull-request.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
name: Pull Request Check
permissions:
contents: read
pull-requests: write

on:
pull_request:
Expand All @@ -12,17 +15,19 @@ jobs:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v5
with:
fetch-depth: 0
- uses: actions/setup-node@v4

- uses: actions/setup-node@v6
with:
node-version: "24"

- name: Install npm 11
run: npm install -g npm@11

- run: npm ci

# Run with the target branch as the base.
- name: Lint
run: npm run lint

Expand Down
Loading
Loading