002 shared UI primitives#7
Conversation
|
Warning Rate limit exceeded
To keep reviews running without waiting, you can enable usage-based add-on for your organization. This allows additional reviews beyond the hourly cap. Account admins can enable it under billing. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (4)
📝 WalkthroughWalkthroughThis PR introduces three reusable Angular UI primitives—Button, TextInput, and Spinner—with comprehensive specifications and implementations. It includes component definitions with accessibility features, design token styling, reactive forms integration, and a barrel export. Configuration updated with tsconfig path alias and feature directory references. Changes
Estimated Code Review Effort🎯 3 (Moderate) | ⏱️ ~20 minutes Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 inconclusive)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Review rate limit: 0/1 reviews remaining, refill in 47 minutes and 28 seconds.Comment |
There was a problem hiding this comment.
Actionable comments posted: 7
🧹 Nitpick comments (1)
specs/002-shared-ui-primitives/data-model.md (1)
54-62: ⚡ Quick winKeep the Button contract in sync with the implementation.
The contract currently documents only the base and variant classes, but the component also applies
btn--disabledandbtn--loading. If this spec is meant to be authoritative, include those state classes here so downstream consumers and tests do not rely on a partial contract.📘 Suggested doc update
-Template binding: `[class]="'btn btn--' + variant()"` +Template binding: `[class]="'btn btn--' + variant() + (isDisabled() ? ' btn--disabled' : '') + (loading() ? ' btn--loading' : '')"`🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@specs/002-shared-ui-primitives/data-model.md` around lines 54 - 62, The spec for the Button CSS class strategy is out of sync with the implementation: update the documented CSS Class Strategy to include the state classes `btn--disabled` and `btn--loading` alongside the base `btn` and variant classes; explicitly describe when those classes are applied (e.g., when the component's `disabled` or `loading` signals/props are truthy) and reflect the template binding pattern that composes them from `variant()` and state flags (the existing `[class]="'btn btn--' + variant()"` entry should be expanded to show how `btn--disabled` and `btn--loading` are added based on `disabled`/`loading` signals).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@specs/002-shared-ui-primitives/contracts/button.md`:
- Line 62: The table row for the `disabled` contract is breaking Markdown
because the code span contains a pipe character; update the cell to avoid '||' —
e.g. replace the cell content "When `loading() || disabled()`" with a
Markdown-safe phrase such as "When loading() or disabled()" or "When `loading()`
or `disabled()`" so the `disabled` row (the `disabled` contract) no longer
contains an unescaped pipe and the table remains valid.
In `@specs/002-shared-ui-primitives/contracts/spinner.md`:
- Around line 78-95: The two fenced code blocks showing the spinner directory
listing and the ButtonComponent snippet are missing a language tag; update the
markdown examples to use a language identifier (use "text") for the directory
block that references spinner.component.ts and spinner.component.scss and for
the HTML snippet that demonstrates the ButtonComponent usage (the block showing
the `@if` (loading()) { <app-spinner ... /> } inside button.component.html) so
markdownlint stops flagging them.
In `@specs/002-shared-ui-primitives/contracts/text-input.md`:
- Around line 107-123: The markdown examples in the documentation use fenced
code blocks without a language tag which triggers markdownlint; update the two
fenced blocks showing the errorMessage behavior and the File Structure to
include a language identifier (e.g., ```text) so the linter stops flagging
them—edit the examples in text-input.md where the blocks contain "errorMessage()
=== '' ..." and the tree listing "src/app/shared/ui/text-input/ ..." and change
the opening backticks to ```text for each block.
In `@src/app/shared/ui/button/button.component.scss`:
- Around line 20-23: The current &:focus-visible rule uses a thin accent outline
that may fail contrast; update the focus style to a higher-contrast, more
prominent ring by increasing thickness and using a high-contrast token (or
fallback) and optional halo: replace outline: 2px solid tokens.$color-accent
with something like outline: 3px solid tokens.$color-focus (or
tokens.$color-on-surface if a dedicated focus token isn't available), increase
outline-offset to 3px, and add a subtle halo using box-shadow: 0 0 0 3px
tokens.$color-accent to preserve accent while ensuring the visible ring meets
contrast requirements.
In `@src/app/shared/ui/spinner/spinner.component.scss`:
- Line 13: Add a prefers-reduced-motion fallback in spinner.component.scss to
stop the infinite rotation for users who request reduced motion: target the
spinner selector that currently uses "animation: lexico-spin 0.75s linear
infinite" and inside an `@media` (prefers-reduced-motion: reduce) rule disable the
animation (set animation: none or animation-duration: 0s) and optionally remove
transforms so the spinner is static; update the rule alongside the existing
"animation: lexico-spin..." declaration so it only applies for reduced-motion
users.
In `@src/app/shared/ui/text-input/text-input.component.scss`:
- Around line 21-40: The input currently removes the browser outline in &__input
and only changes border-color on &:focus which is insufficient; add a
:focus-visible rule for &__input that restores an accessible visible ring (e.g.,
using box-shadow or outline with tokens.$color-accent and appropriate spread)
and ensure it is only applied on :focus-visible to avoid mouse-click outlines;
update the rules adjacent to &__input { ... &:focus { ... } } so the new
&:focus-visible selector uses tokens.$color-accent and a subtle spread (and
respects tokens.$focus-ring-width if available) to meet the visible-ring
requirement.
- Around line 41-68: Replace the duplicated hard-coded error hex (`#e53e3e`) with
the shared token tokens.$color-error: update the border rule in the
[aria-invalid='true'] selector to use tokens.$color-error and update the color
in the &__error block to use tokens.$color-error as well; ensure you reference
the same token name (tokens.$color-error) in both places so the error color is
driven by the design tokens rather than a literal hex value.
---
Nitpick comments:
In `@specs/002-shared-ui-primitives/data-model.md`:
- Around line 54-62: The spec for the Button CSS class strategy is out of sync
with the implementation: update the documented CSS Class Strategy to include the
state classes `btn--disabled` and `btn--loading` alongside the base `btn` and
variant classes; explicitly describe when those classes are applied (e.g., when
the component's `disabled` or `loading` signals/props are truthy) and reflect
the template binding pattern that composes them from `variant()` and state flags
(the existing `[class]="'btn btn--' + variant()"` entry should be expanded to
show how `btn--disabled` and `btn--loading` are added based on
`disabled`/`loading` signals).
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: d25c8837-5254-4c07-93db-d43f32576b3a
📒 Files selected for processing (21)
.specify/feature.jsonCLAUDE.mdspecs/002-shared-ui-primitives/checklists/requirements.mdspecs/002-shared-ui-primitives/contracts/button.mdspecs/002-shared-ui-primitives/contracts/spinner.mdspecs/002-shared-ui-primitives/contracts/text-input.mdspecs/002-shared-ui-primitives/data-model.mdspecs/002-shared-ui-primitives/plan.mdspecs/002-shared-ui-primitives/quickstart.mdspecs/002-shared-ui-primitives/research.mdspecs/002-shared-ui-primitives/spec.mdspecs/002-shared-ui-primitives/tasks.mdsrc/app/shared/ui/button/button.component.scsssrc/app/shared/ui/button/button.component.tssrc/app/shared/ui/index.tssrc/app/shared/ui/spinner/spinner.component.scsssrc/app/shared/ui/spinner/spinner.component.tssrc/app/shared/ui/text-input/text-input.component.htmlsrc/app/shared/ui/text-input/text-input.component.scsssrc/app/shared/ui/text-input/text-input.component.tstsconfig.json
| | Attribute | Value | Condition | | ||
| |-----------|-------|-----------| | ||
| | `type` | `"button"` or `"submit"` | Always (from `type` input) | | ||
| | `disabled` | present | When `loading() || disabled()` | |
There was a problem hiding this comment.
Rewrite the disabled contract row so the Markdown table stays valid.
The || inside the code span is being parsed as extra table separators, which is why markdownlint reports the row as having too many columns. Rephrase it to avoid pipe characters in the cell.
📝 Proposed wording fix
-| `disabled` | present | When `loading() || disabled()` |
+| `disabled` | present | When `loading` or `disabled` is true |📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| | `disabled` | present | When `loading() || disabled()` | | |
| | `disabled` | present | When `loading` or `disabled` is true | |
🧰 Tools
🪛 markdownlint-cli2 (0.22.1)
[warning] 62-62: Table column count
Expected: 3; Actual: 5; Too many cells, extra data will be missing
(MD056, table-column-count)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@specs/002-shared-ui-primitives/contracts/button.md` at line 62, The table row
for the `disabled` contract is breaking Markdown because the code span contains
a pipe character; update the cell to avoid '||' — e.g. replace the cell content
"When `loading() || disabled()`" with a Markdown-safe phrase such as "When
loading() or disabled()" or "When `loading()` or `disabled()`" so the `disabled`
row (the `disabled` contract) no longer contains an unescaped pipe and the table
remains valid.
| ``` | ||
| src/app/shared/ui/spinner/ | ||
| ├── spinner.component.ts # Component class (inline template) | ||
| └── spinner.component.scss # Component styles | ||
| ``` | ||
|
|
||
| Spinner uses an inline template because the template is minimal (2 elements). | ||
|
|
||
| ## Composition Note | ||
|
|
||
| `ButtonComponent` imports `SpinnerComponent` and renders it internally: | ||
|
|
||
| ```html | ||
| <!-- Inside button.component.html --> | ||
| @if (loading()) { | ||
| <app-spinner size="sm" label="Loading…" aria-hidden="true" /> | ||
| } | ||
| ``` |
There was a problem hiding this comment.
Tag the fenced examples with a language.
Both fenced blocks are missing a language identifier, which will keep markdownlint failing here. Use text for these examples so the contract stays lint-clean.
Suggested fix
-```
+```text
src/app/shared/ui/spinner/
├── spinner.component.ts # Component class (inline template)
└── spinner.component.scss # Component styles
-```
+```
-```
+```text
<!-- Inside button.component.html -->
`@if` (loading()) {
<app-spinner size="sm" label="Loading…" aria-hidden="true" />
}
-```
+```📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| ``` | |
| src/app/shared/ui/spinner/ | |
| ├── spinner.component.ts # Component class (inline template) | |
| └── spinner.component.scss # Component styles | |
| ``` | |
| Spinner uses an inline template because the template is minimal (2 elements). | |
| ## Composition Note | |
| `ButtonComponent` imports `SpinnerComponent` and renders it internally: | |
| ```html | |
| <!-- Inside button.component.html --> | |
| @if (loading()) { | |
| <app-spinner size="sm" label="Loading…" aria-hidden="true" /> | |
| } | |
| ``` |
🧰 Tools
🪛 markdownlint-cli2 (0.22.1)
[warning] 78-78: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@specs/002-shared-ui-primitives/contracts/spinner.md` around lines 78 - 95,
The two fenced code blocks showing the spinner directory listing and the
ButtonComponent snippet are missing a language tag; update the markdown examples
to use a language identifier (use "text") for the directory block that
references spinner.component.ts and spinner.component.scss and for the HTML
snippet that demonstrates the ButtonComponent usage (the block showing the `@if`
(loading()) { <app-spinner ... /> } inside button.component.html) so
markdownlint stops flagging them.
| ``` | ||
| errorMessage() === '' or undefined → @if block not rendered (zero height, zero CLS) | ||
| errorMessage() !== '' → <span role="alert"> renders with error text | ||
| ``` | ||
|
|
||
| The error span has `role="alert"` so that when it is inserted into the DOM (which happens | ||
| when `errorMessage` changes from empty to non-empty), screen readers announce it immediately | ||
| (`aria-live="assertive"` implied by `role="alert"`). | ||
|
|
||
| ## File Structure | ||
|
|
||
| ``` | ||
| src/app/shared/ui/text-input/ | ||
| ├── text-input.component.ts # Component class + template (external) | ||
| ├── text-input.component.html # External template | ||
| └── text-input.component.scss # Component styles | ||
| ``` |
There was a problem hiding this comment.
Tag the fenced examples with a language.
These blocks will keep tripping the markdownlint fenced-code-language rule. Add a language identifier such as text so the docs stay lint-clean.
Suggested fix
-```
+```text
errorMessage() === '' or undefined → `@if` block not rendered (zero height, zero CLS)
errorMessage() !== '' → <span role="alert"> renders with error text
-```
+```
-```
+```text
src/app/shared/ui/text-input/
├── text-input.component.ts # Component class + template (external)
├── text-input.component.html # External template
└── text-input.component.scss # Component styles
-```
+```🧰 Tools
🪛 markdownlint-cli2 (0.22.1)
[warning] 107-107: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
[warning] 118-118: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@specs/002-shared-ui-primitives/contracts/text-input.md` around lines 107 -
123, The markdown examples in the documentation use fenced code blocks without a
language tag which triggers markdownlint; update the two fenced blocks showing
the errorMessage behavior and the File Structure to include a language
identifier (e.g., ```text) so the linter stops flagging them—edit the examples
in text-input.md where the blocks contain "errorMessage() === '' ..." and the
tree listing "src/app/shared/ui/text-input/ ..." and change the opening
backticks to ```text for each block.
…ments - Add \$color-error token to tokens.scss; replace hard-coded #e53e3e in text-input.component.scss (FR-015 / SC-003 compliance) - Change text-input &:focus to &:focus-visible and add outline ring for WCAG 2.4.7 keyboard focus visibility - Add prefers-reduced-motion media query to spinner.component.scss (WCAG 2.3.3) - Increase button focus-visible ring to 3px + box-shadow halo for contrast Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Closes #3
Summary by CodeRabbit
New Features
Chores