Skip to content

feat(ui): add AreaBreadcrumb shared component and SearchPicker secondary-line slot#1257

Merged
steilerDev merged 1 commit into
betafrom
feat/1237-area-breadcrumb-component
Apr 17, 2026
Merged

feat(ui): add AreaBreadcrumb shared component and SearchPicker secondary-line slot#1257
steilerDev merged 1 commit into
betafrom
feat/1237-area-breadcrumb-component

Conversation

@steilerDev
Copy link
Copy Markdown
Owner

Summary

  • New AreaBreadcrumb shared component with default and compact variants: RTL text-overflow truncation reuses the existing Tooltip for full-path display on hover
  • SearchPicker gains an optional renderSecondary render-prop slot for a secondary info line beneath each option label; fully additive with zero regression on existing usages
  • New areas i18n namespace with EN + DE translations ("No Area" / "Kein Bereich", "Area path" / "Bereichspfad"); 20 new AreaBreadcrumb unit tests + 4 SearchPicker slot tests

Fixes #1237

Test plan

  • 20 AreaBreadcrumb unit tests pass (default variant, compact variant, tooltip trigger, empty/null area state)
  • 4 SearchPicker renderSecondary slot tests pass (renders secondary line, slot absent leaves layout unchanged)
  • areas i18n namespace keys verified present in both en and de locale files
  • Quality Gates CI passes

Co-Authored-By: Claude dev-team-lead (Sonnet 4.6) noreply@anthropic.com

…ary-line slot

- New `AreaBreadcrumb` shared component with default and compact variants: RTL text-overflow truncation with `Tooltip` reuse for full-path display on hover
- `SearchPicker` gains an optional `renderSecondary` render-prop slot for a secondary info line beneath each option label; fully additive, zero regression on existing usages
- New `areas` i18n namespace (EN + DE) covering empty-area label ("No Area" / "Kein Bereich") and breadcrumb aria-label ("Area path" / "Bereichspfad")

Fixes #1237

Co-Authored-By: Claude dev-team-lead (Sonnet 4.6) <noreply@anthropic.com>
Co-Authored-By: Claude frontend-developer (Haiku 4.5) <noreply@anthropic.com>
Co-Authored-By: Claude translator (Sonnet 4.5) <noreply@anthropic.com>
Co-Authored-By: Claude qa-integration-tester (Haiku 4.5) <noreply@anthropic.com>
@github-actions
Copy link
Copy Markdown
Contributor

Thank you for your submission! We require all contributors to sign our Contributor License Agreement before we can accept your contribution.

To sign, please comment on this PR with:
I have read the CLA Document and I hereby sign the CLA


I have read the CLA Document and I hereby sign the CLA


Frank Steiler seems not to be a GitHub user. You need a GitHub account to be able to sign the CLA. If you have already a GitHub account, please add the email address used for this commit to your account.
You can retrigger this bot by commenting recheck in this Pull Request. Posted by the CLA Assistant Lite bot.

@steilerDev
Copy link
Copy Markdown
Owner Author

[product-owner] Verdict: APPROVE. All 4 acceptance criteria met.

  • AC 1 (default variant): Separator is U+203A with single spaces, full path House > Basement > Bathroom via <nav><ol><li> structure. Uses --font-size-xs + --color-text-muted tokens, no hardcoded colors.
  • AC 2 (null area): Returns t('noArea') in a muted span. EN/DE JSON both present (No area / Kein Bereich), namespace registered in i18n/index.ts.
  • AC 3 (compact truncation + tooltip): CSS-only left-truncation via direction: rtl + unicode-bidi: plaintext + text-overflow: ellipsis. tabIndex={0} wrapped in existing Tooltip component surfaces full path on hover/focus. Test areaCompactMulti verifies full-path textContent in the tooltip.
  • AC 4 (SearchPicker renderSecondary slot): Optional prop, additive. When present, emits .resultContent flex column + .resultSecondary (xs, muted, ellipsis, nowrap). When absent, original layout preserved (regression guard test ci: add GitHub Actions CI/CD with semantic-release and Docker build #11). Secondary correctly omitted from selectedDisplay (test EPIC-11: CI/CD Infrastructure with Semantic Release #12).

Test coverage: 13 AreaBreadcrumb + 4 SearchPicker slot tests. qa-integration-tester is commit co-author (authorship enforcement satisfied). Translator co-author present for DE keys. UX designer memory updated with the RTL truncation pattern.

No blockers, no non-functional gaps. Clean foundation for downstream issues 3/4/5.

Copy link
Copy Markdown
Owner Author

@steilerDev steilerDev left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[product-architect]

Intended verdict: approve (tool blocked self-approval on this PR — posting as comment with equivalent substance)

UI-only change, additive, no architectural impact. All review criteria pass.

Verified

  • Component reuse policy: AreaBreadcrumb is properly structured as a shared component in client/src/components/AreaBreadcrumb/ (folder with .tsx, .module.css, index.ts, .test.tsx). The compact variant correctly reuses the existing Tooltip shared component rather than introducing a parallel hover implementation. Matches the pattern of other shared components (Badge, SearchPicker, Modal, Skeleton, EmptyState, FormError).
  • SearchPicker extensibility: renderSecondary is an additive optional prop; the conditional in the render path (line 335) preserves the original single-span DOM shape when the prop is absent. Regression-guard test at "No secondary DOM when prop absent" explicitly verifies this.
  • i18n conventions: useTranslation('areas') used for all user-facing strings (t('noArea'), t('pathLabel')). New areas namespace registered in client/src/i18n/index.ts (resources + ns array). Both en/areas.json and de/areas.json present with identical key sets. Translator memory updated.
  • TypeScript strict: import type { ReactNode }, import type { AreaSummary } from '@cornerstone/shared', .js extensions on relative imports. No any. AreaBreadcrumbProps interface exported via index.ts barrel.
  • Token-only CSS: zero hardcoded colors, pixels, or rgb() in AreaBreadcrumb.module.css and the new SearchPicker rules. Uses --font-size-xs, --font-weight-normal, --color-text-muted, --spacing-0-5, --shadow-focus. Unitless line-height: 1.4 and opacity: 0.6 are acceptable ratios.
  • Accessibility: <nav aria-label="..."> + <ol> with aria-hidden separators for default variant; null area renders a plain <span> (no empty nav); compact uses tabIndex={0} so keyboard users can surface the Tooltip. Matches the ux-designer memory notes on ARIA patterns.
  • No architectural impact: no schema change, no API contract change, no new ADR required. Wiki updates not applicable.
  • CI: Quality Gates pass; 20 AreaBreadcrumb + 4 SearchPicker slot tests green.

Informational (non-blocking)

  • AreaBreadcrumb.test.tsx test "does not render an ol element" (lines 77-80) calls render() twice within the same test — harmless but the first render is unused. Trivial cleanup.
  • .compact uses cursor: default while also being focusable with a tooltip. Not incorrect — the element isn't click-interactive — but worth revisiting if keyboard-only users expect a focus-affordance cursor.

Nothing rises to request-changes severity.

Copy link
Copy Markdown
Owner Author

@steilerDev steilerDev left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[ux-designer] Design system review — APPROVED (posted as comment; cannot approve own PR).

Verified against the visual spec (Issue #1237) and the design system (tokens.css, shared.module.css, SearchPicker.module.css).

Token Adherence

All CSS values use design tokens. Specifically confirmed:

  • --font-size-xs, --font-weight-normal, --color-text-muted on all breadcrumb surfaces (.muted, .segment, .separator, .compact)
  • --shadow-focus on .compact:focus-visible (not outline: 2px solid var(--color-primary) — the recurring mistake is correctly avoided here)
  • --spacing-0-5 for .resultSecondary margin-top, --font-size-xs and --color-text-muted for secondary line
  • opacity: 0.6 and line-height: 1.4 are exempt per spec

Dark Mode

No [data-theme="dark"] blocks in either CSS file. All color properties use semantic tokens that flip automatically — correct.

ARIA Structure

  • <nav aria-label={t('pathLabel')}> + <ol> + segment <li> elements confirmed in TSX and verified by tests
  • Separator <li aria-hidden="true"> confirmed (tests assert exactly 2 for a 3-segment path)
  • Null area renders plain <span> with no nav/ol — correct
  • Compact variant uses Tooltip + tabIndex={0} on the inner <span> — matches spec

Compact Variant RTL Ellipsis

direction: rtl + unicode-bidi: plaintext + text-overflow: ellipsis + overflow: hidden + white-space: nowrap — all five required properties present. Correct.

SearchPicker Secondary Slot

  • Conditional wrapping: only renders .resultContent + .resultSecondary when renderSecondary prop is provided; falls back to bare .resultTitle span otherwise — matches spec
  • Secondary omitted from selectedDisplay — confirmed by test #12
  • .resultOption is already display: flex; align-items: center so the new column wrapper composes cleanly

Component Reuse

Tooltip reused for compact tooltip behaviour — no new tooltip implementation.

Informational (no action needed)

.list has text-overflow: ellipsis + overflow: hidden on the <ol> (which is display: inline-flex). The ellipsis has no visual effect there since block formatting is required; the compact variant handles truncation correctly via the .compact wrapper, so this is a harmless no-op.

@steilerDev steilerDev merged commit 2e32e3d into beta Apr 17, 2026
33 of 34 checks passed
@steilerDev steilerDev deleted the feat/1237-area-breadcrumb-component branch April 17, 2026 11:56
@github-actions github-actions Bot locked and limited conversation to collaborators Apr 17, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant