feat(ui): add AreaBreadcrumb shared component and SearchPicker secondary-line slot#1257
Conversation
…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>
|
Thank you for your submission! We require all contributors to sign our Contributor License Agreement before we can accept your contribution. 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. |
|
[product-owner] Verdict: APPROVE. All 4 acceptance criteria met.
Test coverage: 13 AreaBreadcrumb + 4 SearchPicker slot tests. No blockers, no non-functional gaps. Clean foundation for downstream issues 3/4/5. |
steilerDev
left a comment
There was a problem hiding this comment.
[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:
AreaBreadcrumbis properly structured as a shared component inclient/src/components/AreaBreadcrumb/(folder with.tsx,.module.css,index.ts,.test.tsx). The compact variant correctly reuses the existingTooltipshared component rather than introducing a parallel hover implementation. Matches the pattern of other shared components (Badge, SearchPicker, Modal, Skeleton, EmptyState, FormError). - SearchPicker extensibility:
renderSecondaryis 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')). Newareasnamespace registered inclient/src/i18n/index.ts(resources +nsarray). Bothen/areas.jsonandde/areas.jsonpresent with identical key sets. Translator memory updated. - TypeScript strict:
import type { ReactNode },import type { AreaSummary } from '@cornerstone/shared',.jsextensions on relative imports. Noany.AreaBreadcrumbPropsinterface exported viaindex.tsbarrel. - Token-only CSS: zero hardcoded colors, pixels, or rgb() in
AreaBreadcrumb.module.cssand the newSearchPickerrules. Uses--font-size-xs,--font-weight-normal,--color-text-muted,--spacing-0-5,--shadow-focus. Unitlessline-height: 1.4andopacity: 0.6are acceptable ratios. - Accessibility:
<nav aria-label="...">+<ol>witharia-hiddenseparators for default variant; null area renders a plain<span>(no empty nav); compact usestabIndex={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.tsxtest "does not render an ol element" (lines 77-80) callsrender()twice within the same test — harmless but the first render is unused. Trivial cleanup..compactusescursor: defaultwhile 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.
steilerDev
left a comment
There was a problem hiding this comment.
[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-mutedon all breadcrumb surfaces (.muted,.segment,.separator,.compact)--shadow-focuson.compact:focus-visible(notoutline: 2px solid var(--color-primary)— the recurring mistake is correctly avoided here)--spacing-0-5for.resultSecondarymargin-top,--font-size-xsand--color-text-mutedfor secondary lineopacity: 0.6andline-height: 1.4are 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+.resultSecondarywhenrenderSecondaryprop is provided; falls back to bare.resultTitlespan otherwise — matches spec - Secondary omitted from selectedDisplay — confirmed by test #12
.resultOptionis alreadydisplay: flex; align-items: centerso 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.
Summary
AreaBreadcrumbshared component with default and compact variants: RTL text-overflow truncation reuses the existingTooltipfor full-path display on hoverSearchPickergains an optionalrenderSecondaryrender-prop slot for a secondary info line beneath each option label; fully additive with zero regression on existing usagesareasi18n namespace with EN + DE translations ("No Area" / "Kein Bereich", "Area path" / "Bereichspfad"); 20 new AreaBreadcrumb unit tests + 4 SearchPicker slot testsFixes #1237
Test plan
renderSecondaryslot tests pass (renders secondary line, slot absent leaves layout unchanged)areasi18n namespace keys verified present in bothenanddelocale filesCo-Authored-By: Claude dev-team-lead (Sonnet 4.6) noreply@anthropic.com