Skip to content

✨ feat: Float Input Label#326

Draft
Gabrieldsantos96 wants to merge 5 commits intozard-ui:masterfrom
Gabrieldsantos96:feat/float-input-label
Draft

✨ feat: Float Input Label#326
Gabrieldsantos96 wants to merge 5 commits intozard-ui:masterfrom
Gabrieldsantos96:feat/float-input-label

Conversation

@Gabrieldsantos96
Copy link

@Gabrieldsantos96 Gabrieldsantos96 commented Nov 14, 2025

What was done? 📝

Implemented ZardFloatLabelComponent with floating label support using only CSS :has() and minimal TS logic. The label automatically floats when the input is focused or has a value, with smooth transitions and support for validation states (destructive, warning, success). Added safe SSR handling with isPlatformBrowser when accessing document.activeElement. Compatible with input, textarea, and button via ng-content (may work with select too).

Screenshots or GIFs 📸

|-----Figma-----|
|-----Implementation-----|

Link to Issue 🔗

Type of change 🏗

  • New feature (non-breaking change that adds functionality)
  • Bug fix (non-breaking change that fixes an issue)
  • Refactor (non-breaking change that improves the code or technical debt)
  • Chore (none of the above, such as upgrading libraries)

Breaking change 🚨

Checklist 🧐

  • Tested on Chrome
  • Tested on Safari
  • Tested on Firefox
  • No errors in the console

Summary by CodeRabbit

  • New Features

    • Added Float Label component—a new form wrapper providing floating label animation for inputs, textareas, and select elements
    • Added comprehensive documentation and demo examples (default, textarea, select, status variants)
    • Float Label component now accessible in component documentation
  • Improvements

    • Enhanced form input components with improved state tracking and visual feedback capabilities

@coderabbitai
Copy link

coderabbitai bot commented Nov 14, 2025

Note

.coderabbit.yaml has unrecognized properties

CodeRabbit is using all valid settings from your configuration. Unrecognized properties (listed below) have been ignored and may indicate typos or deprecated fields that can be removed.

⚠️ Parsing warnings (1)
Validation error: Unrecognized key(s) in object: 'tools', 'path_instructions'
⚙️ Configuration instructions
  • Please see the configuration documentation for more information.
  • You can also validate your configuration using the online YAML validator.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Walkthrough

This PR introduces a new Float Label component with four demo variants and comprehensive test coverage, enhances the Input Directive with lifecycle hooks and form state awareness, upgrades the Select component with DOM state tracking, and registers the new component with routing and documentation.

Changes

Cohort / File(s) Summary
Float Label Component Core
libs/zard/src/lib/components/float-label/float.label.component.ts, libs/zard/src/lib/components/float-label/float.label.variants.ts
Introduces ZardFloatLabelComponent with signal-based class input, computed styling via CVA, browser-platform guards, and dynamic input-has-value toggling on focus/blur/input events; adds floatLabelStyles constant for comprehensive Tailwind-based state variants (focus, value, error/warning/success).
Float Label Demos
libs/zard/src/lib/components/float-label/demo/default.ts, default.ts, input.ts, select.ts, status.ts, text-area.ts
Adds four demo components (default, textarea, select, status) showcasing float-label integration with reactive forms and form state validation; introduces FLOAT_LABEL metadata constant for demo registration.
Float Label Documentation
libs/zard/src/lib/components/float-label/doc/overview.md, api.md
Adds markdown documentation describing float-label as a wrapper component providing floating label animation for form inputs.
Float Label Testing
libs/zard/src/lib/components/float-label/float.label.spec.ts
Comprehensive unit test suite validating component creation, focus/blur behavior, dynamic class application, status styling, custom class propagation, server-side guards, and event-driven state updates.
Input Directive Enhancement
libs/zard/src/lib/components/input/input.directive.ts
Extends ZardInputDirective with AfterViewInit/OnDestroy lifecycle hooks, injects Renderer2/NgControl/NgModel/FormControlName/FormControlDirective for form integration, adds subscription management for valueChanges tracking, implements updateInputState method to toggle input-has-value class and data-status attribute.
Input Demo Refactoring
libs/zard/src/lib/components/input/demo/input.ts
Reorders imports (swaps ZardDemoInputTextAreaComponent and ZardDemoInputStatusComponent positions).
Select Component Enhancement
libs/zard/src/lib/components/select/select.component.ts
Adds Overlay/Portal/platform-check imports, extends form integration with Renderer2 and Subscription for event handling, introduces updateSelectState method to toggle input-has-value class on trigger button based on value presence, subscribes to form value changes and focus/blur events, adds placeholder id for DOM targeting.
Routing & Configuration
apps/web/prerender-routes.txt, apps/web/src/app/shared/constants/routes.constant.ts
Registers new float-label component route at /docs/components/float-label in prerender routes and component navigation constant.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant FloatLabel as FloatLabel<br/>Component
    participant Input as Input/Textarea<br/>Element
    participant Renderer as Renderer2

    User->>Input: Focus
    Input->>FloatLabel: onInteraction() (focus event)
    FloatLabel->>FloatLabel: updateLabelState()
    FloatLabel->>Renderer: toggleClass(input-has-value)
    Renderer->>Input: Apply class

    User->>Input: Type value
    Input->>FloatLabel: onInteraction() (input event)
    FloatLabel->>FloatLabel: updateLabelState()
    FloatLabel->>Renderer: Check element.value
    alt Has value
        Renderer->>Input: Add input-has-value
    else Empty
        Renderer->>Input: Remove input-has-value
    end

    User->>Input: Blur
    Input->>FloatLabel: onInteraction() (blur event)
    FloatLabel->>FloatLabel: updateLabelState()
    note over FloatLabel: Maintains input-has-value if value exists
Loading
sequenceDiagram
    participant FormControl as Form Control<br/>(Reactive/Template)
    participant InputDirective as Input Directive
    participant Renderer as Renderer2

    FormControl->>InputDirective: ngAfterViewInit()
    InputDirective->>FormControl: Subscribe to valueChanges
    InputDirective->>InputDirective: Subscribe to input/change events

    FormControl->>InputDirective: valueChanges emits
    InputDirective->>InputDirective: updateInputState()
    InputDirective->>Renderer: Toggle input-has-value class
    InputDirective->>Renderer: Set data-status attribute

    note over InputDirective: On component destroy
    InputDirective->>InputDirective: ngOnDestroy()
    InputDirective->>InputDirective: Unsubscribe from all subscriptions
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

  • Input Directive public API expansion: Five new public injected dependencies (renderer, ngControl, ngModel, formControlName, formControlDirective) plus lifecycle hooks and subscription management—verify injection strategy follows Angular 17+ best practices with inject() pattern and ensures no circular dependencies
  • Float Label DOM manipulation logic: Browser platform guards, ElementRef queries for nested inputs/textareas/buttons, and dynamic class toggling via Renderer2—ensure platform-agnostic execution and verify query selectors are resilient
  • Form integration patterns: Subscription management across Input Directive, Select component, and potential Float Label interactions—verify proper cleanup in ngOnDestroy and no memory leaks
  • Select component state tracking: New Overlay/Portal and Renderer2 usage alongside existing logic—ensure updateSelectState integrates smoothly with existing overlay/positioning without interference
  • CVA styling integration: floatLabelStyles defines comprehensive Tailwind selectors for focus/value/status states—validate selector specificity and Tailwind v4 compatibility

Possibly related PRs

  • Feat/doc ssr support #269: Modifies the same demo file (libs/zard/src/lib/components/input/demo/input.ts) to add description metadata to the INPUT constant, which could conflict with or complement the import reordering in this PR.

Suggested reviewers

  • Luizgomess
  • ribeiromatheuss
  • srizzon

Poem

✨ A label floats with graceful ease,
While inputs dance and states find peace,
Forms track changes, Directives guide,
Selects respond with every stride,
Angular signals now reside! 🎯

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title 'feat: Float Input Label' accurately summarizes the main change—implementing a new floating label component. It is concise, clear, and directly reflects the primary objective of the pull request.
Description check ✅ Passed The description covers the main implementation details, specifies the type of change (new feature), includes testing checklist validation across browsers, but lacks Figma/implementation screenshots and a related issue link.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 42b35d6 and 6ad04c3.

⛔ Files ignored due to path filters (4)
  • apps/web/public/components/input/demo/float.input.md is excluded by !apps/web/public/** and included by apps/**
  • apps/web/public/installation/manual/empty.md is excluded by !apps/web/public/** and included by apps/**
  • apps/web/public/installation/manual/input.md is excluded by !apps/web/public/** and included by apps/**
  • package-lock.json is excluded by !**/package-lock.json and included by none
📒 Files selected for processing (4)
  • libs/zard/src/lib/components/input/demo/float.input.ts (1 hunks)
  • libs/zard/src/lib/components/input/demo/input.ts (2 hunks)
  • libs/zard/src/lib/components/input/float.label.component.ts (1 hunks)
  • libs/zard/src/lib/components/input/input.directive.ts (2 hunks)
🧰 Additional context used
📓 Path-based instructions (4)
libs/zard/src/lib/components/**/*.component.ts

📄 CodeRabbit inference engine (CLAUDE.md)

libs/zard/src/lib/components/**/*.component.ts: Angular components must be standalone (standalone: true)
Use ChangeDetectionStrategy.OnPush for all Angular components
Bind host class to computed classes via host: { '[class]': 'classes()' }
Use signal-based inputs via input() for component inputs (e.g., variant, size, class)
Provide a selector in the form 'z-[name], [z-[name]]' for each component

Files:

  • libs/zard/src/lib/components/input/float.label.component.ts
libs/zard/src/lib/components/**/*.{component,variants}.ts

📄 CodeRabbit inference engine (CLAUDE.md)

Use tailwind-merge for class merging and clsx for conditional classes when composing CSS classes

Files:

  • libs/zard/src/lib/components/input/float.label.component.ts
libs/zard/src/lib/components/*/*.component.ts

📄 CodeRabbit inference engine (CONTRIBUTING.md)

libs/zard/src/lib/components/*/*.component.ts: Place each Angular component in its own folder and name the main file [name].component.ts under libs/zard/src/lib/components/[name]/
Components must be standalone (standalone: true) and use ChangeDetectionStrategy.OnPush
Component selector should follow: 'z-[name], [z-[name]]' (element and attribute selectors)
Use signal-based inputs via input() for public inputs (e.g., variant, size, class)
Host-bind the class attribute and compute classes via computed() + mergeClasses(CVA(...), class)
Use Tailwind utility classes and resolve class conflicts via tailwind-merge (through mergeClasses) in components

Files:

  • libs/zard/src/lib/components/input/float.label.component.ts
libs/zard/src/lib/components/**/demo/**/*.ts

📄 CodeRabbit inference engine (CLAUDE.md)

Place demo files under a demo/ directory (including a main demo export file, default.ts, and variant example files)

Files:

  • libs/zard/src/lib/components/input/demo/float.input.ts
  • libs/zard/src/lib/components/input/demo/input.ts
🧠 Learnings (21)
📓 Common learnings
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: libs/blocks/README.md:0-0
Timestamp: 2025-10-17T17:12:22.571Z
Learning: Applies to libs/blocks/src/lib/*/*.component.{ts,html} : Use ZardUI form components for validation (FormField, FormLabel, FormControl) in blocks with forms
Learnt from: mikij
Repo: zard-ui/zardui PR: 318
File: libs/zard/src/lib/components/select/demo/default.ts:21-21
Timestamp: 2025-11-10T21:46:33.213Z
Learning: In demo files under libs/zard/src/lib/components/**/demo/*.ts, intentionally showing different patterns (e.g., primitive values vs signals) across different demos is valuable for demonstrating the flexibility of Angular features like two-way binding.
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-10-15T00:51:30.882Z
Learning: Applies to libs/zard/src/lib/components/**/*.component.ts : Use signal-based inputs via input() for component inputs (e.g., variant, size, class)
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-10-17T19:24:10.610Z
Learning: Applies to libs/zard/src/lib/components/*/*.component.ts : Use signal-based inputs via input() for public inputs (e.g., variant, size, class)
📚 Learning: 2025-10-15T00:51:30.882Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-10-15T00:51:30.882Z
Learning: Applies to libs/zard/src/lib/components/components.ts : Export new components from libs/zard/src/lib/components/components.ts

Applied to files:

  • libs/zard/src/lib/components/input/float.label.component.ts
  • libs/zard/src/lib/components/input/demo/float.input.ts
  • libs/zard/src/lib/components/input/demo/input.ts
  • libs/zard/src/lib/components/input/input.directive.ts
📚 Learning: 2025-10-17T17:12:22.571Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: libs/blocks/README.md:0-0
Timestamp: 2025-10-17T17:12:22.571Z
Learning: Applies to libs/blocks/src/lib/*/*.component.{ts,html} : Use ZardUI form components for validation (FormField, FormLabel, FormControl) in blocks with forms

Applied to files:

  • libs/zard/src/lib/components/input/float.label.component.ts
  • libs/zard/src/lib/components/input/demo/float.input.ts
  • libs/zard/src/lib/components/input/demo/input.ts
  • libs/zard/src/lib/components/input/input.directive.ts
📚 Learning: 2025-10-17T19:24:10.610Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-10-17T19:24:10.610Z
Learning: Applies to libs/zard/src/lib/components/*/*.component.ts : Component selector should follow: 'z-[name], [z-[name]]' (element and attribute selectors)

Applied to files:

  • libs/zard/src/lib/components/input/float.label.component.ts
  • libs/zard/src/lib/components/input/demo/float.input.ts
  • libs/zard/src/lib/components/input/demo/input.ts
  • libs/zard/src/lib/components/input/input.directive.ts
📚 Learning: 2025-10-17T19:24:10.610Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-10-17T19:24:10.610Z
Learning: Applies to libs/zard/src/lib/components/*/*.component.ts : Place each Angular component in its own folder and name the main file [name].component.ts under libs/zard/src/lib/components/[name]/

Applied to files:

  • libs/zard/src/lib/components/input/float.label.component.ts
  • libs/zard/src/lib/components/input/demo/float.input.ts
📚 Learning: 2025-10-15T00:51:30.882Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-10-15T00:51:30.882Z
Learning: Applies to libs/zard/src/lib/components/**/*.component.ts : Use signal-based inputs via input() for component inputs (e.g., variant, size, class)

Applied to files:

  • libs/zard/src/lib/components/input/float.label.component.ts
  • libs/zard/src/lib/components/input/demo/float.input.ts
  • libs/zard/src/lib/components/input/demo/input.ts
  • libs/zard/src/lib/components/input/input.directive.ts
📚 Learning: 2025-10-15T00:51:30.882Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-10-15T00:51:30.882Z
Learning: Applies to libs/zard/src/lib/components/**/*.component.ts : Provide a selector in the form 'z-[name], [z-[name]]' for each component

Applied to files:

  • libs/zard/src/lib/components/input/float.label.component.ts
  • libs/zard/src/lib/components/input/demo/float.input.ts
  • libs/zard/src/lib/components/input/demo/input.ts
  • libs/zard/src/lib/components/input/input.directive.ts
📚 Learning: 2025-10-17T19:24:10.610Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-10-17T19:24:10.610Z
Learning: Applies to libs/zard/src/lib/components/*/*.component.ts : Use signal-based inputs via input() for public inputs (e.g., variant, size, class)

Applied to files:

  • libs/zard/src/lib/components/input/float.label.component.ts
  • libs/zard/src/lib/components/input/demo/input.ts
  • libs/zard/src/lib/components/input/input.directive.ts
📚 Learning: 2025-10-17T19:24:10.610Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-10-17T19:24:10.610Z
Learning: Applies to libs/zard/src/lib/components/*/*.component.ts : Use Tailwind utility classes and resolve class conflicts via tailwind-merge (through mergeClasses) in components

Applied to files:

  • libs/zard/src/lib/components/input/float.label.component.ts
📚 Learning: 2025-10-17T19:24:10.610Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-10-17T19:24:10.610Z
Learning: Applies to libs/zard/src/lib/components/components.ts : Export new components from the barrel file libs/zard/src/lib/components/components.ts

Applied to files:

  • libs/zard/src/lib/components/input/float.label.component.ts
  • libs/zard/src/lib/components/input/demo/float.input.ts
  • libs/zard/src/lib/components/input/demo/input.ts
📚 Learning: 2025-10-15T00:51:30.882Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-10-15T00:51:30.882Z
Learning: Applies to libs/zard/src/lib/components/**/*.component.ts : Bind host class to computed classes via host: { '[class]': 'classes()' }

Applied to files:

  • libs/zard/src/lib/components/input/float.label.component.ts
  • libs/zard/src/lib/components/input/input.directive.ts
📚 Learning: 2025-10-17T19:24:10.610Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-10-17T19:24:10.610Z
Learning: Applies to libs/zard/src/lib/components/*/*.component.ts : Host-bind the class attribute and compute classes via computed() + mergeClasses(CVA(...), class)

Applied to files:

  • libs/zard/src/lib/components/input/float.label.component.ts
  • libs/zard/src/lib/components/input/input.directive.ts
📚 Learning: 2025-10-31T10:03:18.563Z
Learnt from: mikij
Repo: zard-ui/zardui PR: 299
File: libs/zard/src/lib/components/select/select.component.ts:34-38
Timestamp: 2025-10-31T10:03:18.563Z
Learning: In Angular 19+ (including Angular 20 used in this project), components are standalone by default. The `standalone: true` flag is redundant and should be omitted unless explicitly setting `standalone: false` to opt out.

Applied to files:

  • libs/zard/src/lib/components/input/float.label.component.ts
📚 Learning: 2025-10-15T00:51:30.882Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-10-15T00:51:30.882Z
Learning: Applies to libs/zard/src/lib/components/**/demo/**/*.ts : Place demo files under a demo/ directory (including a main demo export file, default.ts, and variant example files)

Applied to files:

  • libs/zard/src/lib/components/input/demo/float.input.ts
  • libs/zard/src/lib/components/input/demo/input.ts
📚 Learning: 2025-11-10T21:46:33.213Z
Learnt from: mikij
Repo: zard-ui/zardui PR: 318
File: libs/zard/src/lib/components/select/demo/default.ts:21-21
Timestamp: 2025-11-10T21:46:33.213Z
Learning: In demo files under libs/zard/src/lib/components/**/demo/*.ts, intentionally showing different patterns (e.g., primitive values vs signals) across different demos is valuable for demonstrating the flexibility of Angular features like two-way binding.

Applied to files:

  • libs/zard/src/lib/components/input/demo/float.input.ts
  • libs/zard/src/lib/components/input/demo/input.ts
📚 Learning: 2025-11-04T20:46:01.373Z
Learnt from: mikij
Repo: zard-ui/zardui PR: 309
File: libs/zard/src/lib/components/select/demo/multi-select.ts:23-27
Timestamp: 2025-11-04T20:46:01.373Z
Learning: In demo files under libs/zard/src/lib/components/**/demo/*.ts, console.log statements are acceptable and often intentional to demonstrate reactivity and help users understand how the component works.

Applied to files:

  • libs/zard/src/lib/components/input/demo/float.input.ts
  • libs/zard/src/lib/components/input/demo/input.ts
📚 Learning: 2025-10-17T19:24:10.610Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-10-17T19:24:10.610Z
Learning: Applies to libs/zard/src/lib/components/*/demo/default.ts : Each component must provide a demo/default.ts exporting a DefaultExample with name, code, and lazy-loaded component

Applied to files:

  • libs/zard/src/lib/components/input/demo/float.input.ts
  • libs/zard/src/lib/components/input/demo/input.ts
📚 Learning: 2025-10-15T00:51:30.882Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-10-15T00:51:30.882Z
Learning: Applies to libs/zard/src/index.ts : Maintain the library public entry point in libs/zard/src/index.ts

Applied to files:

  • libs/zard/src/lib/components/input/demo/input.ts
📚 Learning: 2025-10-15T00:51:30.882Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-10-15T00:51:30.882Z
Learning: Applies to libs/zard/src/lib/components/**/*.component.ts : Use ChangeDetectionStrategy.OnPush for all Angular components

Applied to files:

  • libs/zard/src/lib/components/input/input.directive.ts
📚 Learning: 2025-10-15T00:51:30.882Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-10-15T00:51:30.882Z
Learning: Applies to libs/zard/src/lib/components/**/*.{component,variants}.ts : Use tailwind-merge for class merging and clsx for conditional classes when composing CSS classes

Applied to files:

  • libs/zard/src/lib/components/input/input.directive.ts
📚 Learning: 2025-10-15T00:51:30.882Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-10-15T00:51:30.882Z
Learning: Applies to libs/zard/src/lib/components/**/*.variants.ts : Define styling variants with Class Variance Authority (CVA) in a companion <name>.variants.ts file

Applied to files:

  • libs/zard/src/lib/components/input/input.directive.ts
🧬 Code graph analysis (2)
libs/zard/src/lib/components/input/float.label.component.ts (1)
libs/zard/src/lib/components/input/demo/float.input.ts (1)
  • Component (6-17)
libs/zard/src/lib/components/input/demo/float.input.ts (1)
libs/zard/src/lib/components/input/float.label.component.ts (1)
  • Component (4-94)
🔇 Additional comments (2)
libs/zard/src/lib/components/input/demo/input.ts (1)

3-6: Float-label demo wiring looks correct and consistent

The new ZardFloatLabelDemoComponent import and the 'float-label' entry in INPUT.examples are correctly hooked up and consistent with the existing demo structure (column layout etc.). No issues here.

Also applies to: 18-22

libs/zard/src/lib/components/input/input.directive.ts (1)

39-74: Guard DOM event subscriptions for SSR and add OnPush detection strategy

Lines 39–74 need two critical fixes:

  1. Wrap fromEvent() subscriptions with SSR guard (lines 55–56): fromEvent(nativeElement, 'input'/'change') will throw on server where nativeElement lacks addEventListener. Inject PLATFORM_ID, compute const isBrowser = isPlatformBrowser(this.platformId), and guard both fromEvent calls plus the initial updateInputState() inside an if (isBrowser) block. Mirror the pattern used in sheet-ref.ts, dialog-ref.ts, and menu.directive.ts in the same codebase.

  2. Mark updateInputState as private readonly (line 61): Arrow function should not be part of the public API surface.

  3. Add brief comment on setTimeout (line 39): Document that this ensures form directives/controls are fully wired before subscriptions attach (control initialization timing).

  4. Add ChangeDetectionStrategy.OnPush to the @Directive decorator per coding guidelines.

⛔ Skipped due to learnings
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-10-15T00:51:30.882Z
Learning: Applies to libs/zard/src/lib/components/**/*.component.ts : Use ChangeDetectionStrategy.OnPush for all Angular components

Comment on lines +1 to +17
import { Component } from '@angular/core';

import { ZardFloatLabelComponent } from '../float.label.component';
import { ZardInputDirective } from '../input.directive';

@Component({
selector: 'z-demo-input-float-input',
standalone: true,
imports: [ZardInputDirective, ZardFloatLabelComponent],
template: `
<zard-float-label>
<input z-input />
<label>Float Label</label>
</zard-float-label>
`,
})
export class ZardFloatLabelDemoComponent {}
Copy link

@coderabbitai coderabbitai bot Nov 14, 2025

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Optional: add OnPush change detection to align demo with library components

The demo is simple and works as-is. To stay in line with the rest of the library’s Angular best practices, you could also set changeDetection: ChangeDetectionStrategy.OnPush here (and import ChangeDetectionStrategy), even though it won’t change behaviour today.

Example:

-import { Component } from '@angular/core';
+import { Component, ChangeDetectionStrategy } from '@angular/core';

 @Component({
   selector: 'z-demo-input-float-input',
   standalone: true,
   imports: [ZardInputDirective, ZardFloatLabelComponent],
+  changeDetection: ChangeDetectionStrategy.OnPush,
   template: `

Purely a consistency/refinement tweak; not a blocker.
As per coding guidelines

📝 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.

Suggested change
import { Component } from '@angular/core';
import { ZardFloatLabelComponent } from '../float.label.component';
import { ZardInputDirective } from '../input.directive';
@Component({
selector: 'z-demo-input-float-input',
standalone: true,
imports: [ZardInputDirective, ZardFloatLabelComponent],
template: `
<zard-float-label>
<input z-input />
<label>Float Label</label>
</zard-float-label>
`,
})
export class ZardFloatLabelDemoComponent {}
import { Component, ChangeDetectionStrategy } from '@angular/core';
import { ZardFloatLabelComponent } from '../float.label.component';
import { ZardInputDirective } from '../input.directive';
@Component({
selector: 'z-demo-input-float-input',
standalone: true,
imports: [ZardInputDirective, ZardFloatLabelComponent],
changeDetection: ChangeDetectionStrategy.OnPush,
template: `
<zard-float-label>
<input z-input />
<label>Float Label</label>
</zard-float-label>
`,
})
export class ZardFloatLabelDemoComponent {}
🤖 Prompt for AI Agents
In libs/zard/src/lib/components/input/demo/float.input.ts lines 1-17, the demo
component lacks explicit changeDetection; add ChangeDetectionStrategy.OnPush to
the @Component decorator and import ChangeDetectionStrategy from '@angular/core'
so the demo aligns with the library's OnPush convention: update the import list
to include ChangeDetectionStrategy and add changeDetection:
ChangeDetectionStrategy.OnPush to the component metadata.

Copy link
Contributor

Choose a reason for hiding this comment

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

do this

Copy link

Choose a reason for hiding this comment

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

@mikij, perfect! Here's the updated code with OnPush change detection:

import { Component, ChangeDetectionStrategy } from '@angular/core';

import { ZardFloatLabelComponent } from '../float.label.component';
import { ZardInputDirective } from '../input.directive';

@Component({
  selector: 'z-demo-input-float-input',
  standalone: true,
  imports: [ZardInputDirective, ZardFloatLabelComponent],
  changeDetection: ChangeDetectionStrategy.OnPush,
  template: `
    <zard-float-label>
      <input z-input />
      <label>Float Label</label>
    </zard-float-label>
  `,
})
export class ZardFloatLabelDemoComponent {}

This aligns the demo with the library's Angular best practices! 🚀


🧠 Learnings used
Learnt from: mikij
Repo: zard-ui/zardui PR: 318
File: libs/zard/src/lib/components/select/demo/default.ts:21-21
Timestamp: 2025-11-10T21:46:33.213Z
Learning: In demo files under libs/zard/src/lib/components/**/demo/*.ts, intentionally showing different patterns (e.g., primitive values vs signals) across different demos is valuable for demonstrating the flexibility of Angular features like two-way binding.

Learnt from: mikij
Repo: zard-ui/zardui PR: 309
File: libs/zard/src/lib/components/select/demo/multi-select.ts:23-27
Timestamp: 2025-11-04T20:46:01.373Z
Learning: In demo files under libs/zard/src/lib/components/**/demo/*.ts, console.log statements are acceptable and often intentional to demonstrate reactivity and help users understand how the component works.

Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-10-15T00:51:30.882Z
Learning: Applies to libs/zard/src/lib/components/**/demo/**/*.ts : Place demo files under a demo/ directory (including a main demo export file, default.ts, and variant example files)

Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-10-15T00:51:30.882Z
Learning: Applies to libs/zard/src/lib/components/**/*.component.ts : Use signal-based inputs via input() for component inputs (e.g., variant, size, class)

Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-10-17T19:24:10.610Z
Learning: Applies to libs/zard/src/lib/components/*/demo/default.ts : Each component must provide a demo/default.ts exporting a DefaultExample with name, code, and lazy-loaded component

Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: libs/blocks/README.md:0-0
Timestamp: 2025-10-17T17:12:22.571Z
Learning: Applies to libs/blocks/src/lib/*/*.component.{ts,html} : Use ZardUI form components for validation (FormField, FormLabel, FormControl) in blocks with forms

Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-10-15T00:51:30.882Z
Learning: Applies to libs/zard/src/lib/components/components.ts : Export new components from libs/zard/src/lib/components/components.ts

Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-10-17T19:24:10.610Z
Learning: Applies to libs/zard/src/lib/components/*/*.component.ts : Use signal-based inputs via input() for public inputs (e.g., variant, size, class)

Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-10-15T00:51:30.882Z
Learning: Applies to libs/zard/src/lib/components/**/*.component.ts : Provide a selector in the form 'z-[name], [z-[name]]' for each component

Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-10-17T19:24:10.610Z
Learning: Applies to libs/zard/src/lib/components/*/*.component.ts : Component selector should follow: 'z-[name], [z-[name]]' (element and attribute selectors)

Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-10-15T00:51:30.882Z
Learning: Applies to libs/zard/src/lib/components/**/*.component.ts : Use ChangeDetectionStrategy.OnPush for all Angular components

Learnt from: mikij
Repo: zard-ui/zardui PR: 299
File: libs/zard/src/lib/components/select/select.component.ts:34-38
Timestamp: 2025-10-31T10:03:18.563Z
Learning: In Angular 19+ (including Angular 20 used in this project), components are standalone by default. The `standalone: true` flag is redundant and should be omitted unless explicitly setting `standalone: false` to opt out.

Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-10-15T00:51:30.882Z
Learning: Use the provided Angular best practices in docs/angular-llm.txt when making changes

Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-10-17T19:24:10.610Z
Learning: Applies to libs/zard/src/lib/components/*/*.component.ts : Place each Angular component in its own folder and name the main file [name].component.ts under libs/zard/src/lib/components/[name]/

Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-10-17T19:24:10.610Z
Learning: Applies to libs/zard/src/lib/components/components.ts : Export new components from the barrel file libs/zard/src/lib/components/components.ts

If you found this review helpful, would you consider giving us a shout-out on X?

Thank you for using CodeRabbit!

Comment on lines +2 to +9
import { Component, ElementRef, AfterViewInit, ViewEncapsulation, Renderer2, HostListener, Inject, PLATFORM_ID } from '@angular/core';

@Component({
selector: 'zard-float-label',
standalone: true,
template: `<ng-content />`,
encapsulation: ViewEncapsulation.None,
styles: `
Copy link

@coderabbitai coderabbitai bot Nov 14, 2025

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

Align component metadata with ZardUI conventions (selector, OnPush, standalone)

  • The selector 'zard-float-label' doesn’t follow the documented 'z-[name], [z-[name]]' pattern and only exposes an element selector. To stay consistent and avoid later churn, I’d strongly suggest switching to something like selector: 'z-float-label, [z-float-label]' and updating usages in float.input.ts accordingly.
  • Add changeDetection: ChangeDetectionStrategy.OnPush to match the rest of the component library and the stated best practice.
  • In Angular 19+/20 the standalone: true flag is redundant; you can safely drop it unless you explicitly opt out with standalone: false.

A possible tweak (you’ll also need to adjust the demo template to the new selector):

-import { Component, ElementRef, AfterViewInit, ViewEncapsulation, Renderer2, HostListener, Inject, PLATFORM_ID } from '@angular/core';
+import { Component, ElementRef, AfterViewInit, ViewEncapsulation, Renderer2, HostListener, Inject, PLATFORM_ID, ChangeDetectionStrategy } from '@angular/core';

 @Component({
-  selector: 'zard-float-label',
-  standalone: true,
+  selector: 'z-float-label, [z-float-label]',
+  changeDetection: ChangeDetectionStrategy.OnPush,
   template: `<ng-content />`,
   encapsulation: ViewEncapsulation.None,

You may also want to revisit the dedicated CSS block later and see whether pieces of it can be expressed via the existing Tailwind/CVA stack to reduce bespoke styling.
As per coding guidelines


I'll verify the concerns in the review comment by inspecting the actual codebase.


🏁 Script executed:

#!/bin/bash
# Check the current state of float.label.component.ts
echo "=== float.label.component.ts ===" 
cat libs/zard/src/lib/components/input/float.label.component.ts

echo -e "\n=== float.input.ts (to see how float-label is used) ==="
cat libs/zard/src/lib/components/input/float.input.ts | head -50

echo -e "\n=== Check Angular version ==="
cat package.json | grep -A2 '"@angular/core"'

echo -e "\n=== Sample selector patterns from other components ==="
rg -A1 "selector:\s*'" libs/zard/src/lib/components --type ts | head -20

Length of output: 4312


🏁 Script executed:

#!/bin/bash
# Find package.json in monorepo
echo "=== Finding package.json ==="
find . -maxdepth 2 -name "package.json" -type f

echo -e "\n=== Main component selectors (exclude demos) ==="
rg "selector:\s*'" libs/zard/src/lib/components --type ts -A1 | grep -v "/demo/" | head -30

echo -e "\n=== Check ChangeDetectionStrategy usage ==="
rg "ChangeDetectionStrategy.OnPush" libs/zard/src/lib/components --type ts | head -10

echo -e "\n=== Files containing 'float' in input folder ==="
fd . libs/zard/src/lib/components/input --type f

Length of output: 2789


🏁 Script executed:

#!/bin/bash
# Check for Angular version
echo "=== Angular version from dependencies ==="
find . -name "*.json" -type f | xargs grep -l '"@angular/core"' 2>/dev/null | head -3

echo -e "\n=== Searching all component selectors for dual [z-*] patterns ==="
rg "selector:\s*['\"]z-.*,\s*\[z-" libs/zard/src/lib/components --type ts

echo -e "\n=== Check if any non-demo component uses dual selector ==="
rg "selector:" libs/zard/src/lib/components --type ts -A1 | grep -E "\[z-" | head -5

echo -e "\n=== Verify ChangeDetectionStrategy import in float.label.component.ts ==="
head -1 libs/zard/src/lib/components/input/float.label.component.ts

echo -e "\n=== Check actual import for ChangeDetectionStrategy across components ==="
rg "ChangeDetectionStrategy" libs/zard/src/lib/components/toggle/toggle.component.ts -B5 | head -10

Length of output: 3404


Fix selector, add ChangeDetectionStrategy.OnPush, and remove @HostListener

The component violates established ZardUI patterns and should be aligned:

  • Selector: Currently 'zard-float-label' breaks convention. Must follow 'z-float-label, [z-float-label]' (dual element/attribute pattern used consistently across switch, radio, checkbox, avatar, alert, form, and many other components).
  • Missing ChangeDetectionStrategy.OnPush: All comparable components (toggle, switch, tabs, toast, skeleton, slider, etc.) use OnPush. Add this import and include changeDetection: ChangeDetectionStrategy.OnPush in metadata.
  • @HostListener ineffective here: The decorators on 'input', 'focus', 'blur' won't reliably fire on the wrapper element when child inputs receive focus/blur. Since updateLabelState() is called in ngAfterViewInit() and tracks value changes, this pattern is redundant. Simplify to only the input event if cross-browser value-tracking is critical, or rely on CSS :has() which already handles focus/blur states.
-import { Component, ElementRef, AfterViewInit, ViewEncapsulation, Renderer2, HostListener, Inject, PLATFORM_ID } from '@angular/core';
+import { Component, ElementRef, AfterViewInit, ViewEncapsulation, Renderer2, HostListener, Inject, PLATFORM_ID, ChangeDetectionStrategy } from '@angular/core';

 @Component({
-  selector: 'zard-float-label',
+  selector: 'z-float-label, [z-float-label]',
+  changeDetection: ChangeDetectionStrategy.OnPush,
   standalone: 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.

Suggested change
import { Component, ElementRef, AfterViewInit, ViewEncapsulation, Renderer2, HostListener, Inject, PLATFORM_ID } from '@angular/core';
@Component({
selector: 'zard-float-label',
standalone: true,
template: `<ng-content />`,
encapsulation: ViewEncapsulation.None,
styles: `
import { Component, ElementRef, AfterViewInit, ViewEncapsulation, Renderer2, HostListener, Inject, PLATFORM_ID, ChangeDetectionStrategy } from '@angular/core';
@Component({
selector: 'z-float-label, [z-float-label]',
changeDetection: ChangeDetectionStrategy.OnPush,
standalone: true,
template: `<ng-content />`,
encapsulation: ViewEncapsulation.None,
styles: `
🤖 Prompt for AI Agents
In libs/zard/src/lib/components/input/float.label.component.ts around lines 2 to
9, update the component metadata and decorators to follow ZardUI conventions:
change the selector from 'zard-float-label' to the dual-element/attribute
pattern 'z-float-label, [z-float-label]'; import ChangeDetectionStrategy from
@angular/core and add changeDetection: ChangeDetectionStrategy.OnPush to the
@Component metadata; remove the @HostListener decorators (and any associated
focus/blur handler methods) since they are ineffective on the wrapper element
and redundant with ngAfterViewInit/value tracking or CSS :has() behavior; if
input event handling is still required keep a single input listener bound
directly to the inner input element rather than HostListener on the wrapper.

Copy link
Contributor

Choose a reason for hiding this comment

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

do not follow this comment about selector if this is not acting as directive

Copy link

Choose a reason for hiding this comment

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

Seems like the humans are having a chat. I'll hop back into my burrow for now. If you need me again, just tag @coderabbitai in a new comment, and I'll come hopping out!

Comment on lines +71 to +76
@HostListener('input', ['$event'])
@HostListener('focus', ['$event'])
@HostListener('blur', ['$event'])
onInteraction(event: Event) {
this.updateLabelState();
}
Copy link

@coderabbitai coderabbitai bot Nov 14, 2025

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

Tighten HostListener usage; focus/blur listeners are effectively dead code

  • @HostListener('focus') / @HostListener('blur') on the wrapper element won’t fire when the projected <input>/<textarea>/<button> gains or loses focus, because focus/blur don’t bubble from the child control. Right now, only the input listener is doing any work.
  • We’re also not using the $event parameter.

To simplify and avoid misleading HostListeners while still updating the value state, you can reduce this to just the input event and drop $event entirely:

-  @HostListener('input', ['$event'])
-  @HostListener('focus', ['$event'])
-  @HostListener('blur', ['$event'])
-  onInteraction(event: Event) {
-    this.updateLabelState();
-  }
+  @HostListener('input')
+  onInput() {
+    this.updateLabelState();
+  }

This also keeps HostListener usage minimal, as recommended, while leaving focus handling entirely to the :has(...:focus) CSS.
As per coding guidelines


I'll verify the component structure and validate the review comment claims.


🏁 Script executed:

#!/bin/bash
# View the float.label.component.ts file to inspect the HostListener usage and component structure
fd -e "float.label.component.ts" --path "*input*" | head -1 | xargs cat

Length of output: 233


🏁 Script executed:

#!/bin/bash
# Search for any other @HostListener or @HostBinding usage in the same file
fd -e "float.label.component.ts" --path "*input*" | head -1 | xargs grep -n "HostListener\|HostBinding"

Length of output: 233


🏁 Script executed:

#!/bin/bash
# Check if updateLabelState is called elsewhere in the file
fd -e "float.label.component.ts" --path "*input*" | head -1 | xargs grep -n "updateLabelState"

Length of output: 233


🏁 Script executed:

#!/bin/bash
# Verify component configuration (standalone, changeDetection, inputs, etc.)
fd -e "float.label.component.ts" --path "*input*" | head -1 | xargs grep -n -A 5 "^@Component"

Length of output: 233


🏁 Script executed:

#!/bin/bash
# Check the overall structure: class definition, imports, and ChangeDetectionStrategy usage
fd -e "float.label.component.ts" --path "*input*" | head -1 | xargs head -30

Length of output: 233


🏁 Script executed:

#!/bin/bash
# Look for signal-based inputs (input() function) usage
fd -e "float.label.component.ts" --path "*input*" | head -1 | xargs grep -n "= input"

Length of output: 233


🏁 Script executed:

#!/bin/bash
# Check if there's a computed classes or host binding for classes
fd -e "float.label.component.ts" --path "*input*" | head -1 | xargs grep -n "classes\|host.*class"

Length of output: 233


🏁 Script executed:

#!/bin/bash
# Inspect lines 65-85 for broader context around the HostListener methods
fd -e "float.label.component.ts" --path "*input*" | head -1 | xargs sed -n '65,85p'

Length of output: 233


🏁 Script executed:

#!/bin/bash
# Check if any other input/focus/blur listeners exist elsewhere in the codebase
rg -n "HostListener.*blur|HostListener.*focus" libs/zard/src/lib/components/input/

Length of output: 198


🏁 Script executed:

#!/bin/bash
# Verify if there are any other event handlers or listeners for focus/blur
fd -e "float.label.component.ts" --path "*input*" | head -1 | xargs grep -n -i "focus\|blur" | grep -v "^Binary"

Length of output: 233


🏁 Script executed:

#!/bin/bash
# Look at the updateLabelState method to understand what it does
fd -e "float.label.component.ts" --path "*input*" | head -1 | xargs grep -n -A 10 "updateLabelState()"

Length of output: 233


🏁 Script executed:

#!/bin/bash
# Check for ChangeDetectionStrategy usage
fd -e "float.label.component.ts" --path "*input*" | head -1 | xargs grep -n "ChangeDetectionStrategy"

Length of output: 233


🏁 Script executed:

#!/bin/bash
# Look for any CSS that might use :has(:focus) selector
fd -e "float.label.*.css\|float.label.*.scss\|float.label.*.style" --path "*input*" | xargs cat 2>/dev/null || echo "No separate style file found"

Length of output: 233


🏁 Script executed:

#!/bin/bash
# Check for inline styles in the component
fd -e "float.label.component.ts" --path "*input*" | head -1 | xargs grep -n -A 50 "styles:\|styleUrls:" | head -60

Length of output: 233


🏁 Script executed:

#!/bin/bash
# Verify if the component is using proper Angular signal-based patterns
fd -e "float.label.component.ts" --path "*input*" | head -1 | xargs grep -n "input\(\)\|computed\(\)\|signal\(\)"

Length of output: 233


🏁 Script executed:

#!/bin/bash
# Check host configuration and class binding strategy
fd -e "float.label.component.ts" --path "*input*" | head -1 | xargs grep -n "host:" -A 3

Length of output: 233


🏁 Script executed:

#!/bin/bash
# Full file inspection for context
fd -e "float.label.component.ts" --path "*input*" | head -1 | xargs wc -l

Length of output: 235


🏁 Script executed:

#!/bin/bash
# Get complete file content with line numbers
fd -e "float.label.component.ts" --path "*input*" | head -1 | xargs cat -n

Length of output: 233


🏁 Script executed:

#!/bin/bash
# Look for any CSS :has selector patterns that might rely on focus state
fd -e "float.label.component.ts" --path "*input*" | head -1 | xargs grep -n ":has"

Length of output: 233


🏁 Script executed:

#!/bin/bash
# Check if the onInteraction method's $event is ever used
fd -e "float.label.component.ts" --path "*input*" | head -1 | xargs grep -n "event\." | grep -A 5 -B 5 "onInteraction"

Length of output: 233


🏁 Script executed:

#!/bin/bash
# Verify component selector format
fd -e "float.label.component.ts" --path "*input*" | head -1 | xargs grep -n "selector:"

Length of output: 233


🏁 Script executed:

#!/bin/bash
# Check if standalone is set to true
fd -e "float.label.component.ts" --path "*input*" | head -1 | xargs grep -n "standalone"

Length of output: 233


🏁 Script executed:

#!/bin/bash
# Look for any @HostBinding usage on the class attribute or other bindings
fd -e "float.label.component.ts" --path "*input*" | head -1 | xargs grep -n "@HostBinding"

Length of output: 233


🏁 Script executed:

#!/bin/bash
# Verify whether the component has a form-related context that might rely on focus handling
fd -e "float.label.component.ts" --path "*input*" | head -1 | xargs grep -n "FormControl\|ngModel\|formControl"

Length of output: 233


🏁 Script executed:

#!/bin/bash
# Check template to see if there are event bindings for focus/blur
fd -e "float.label.component.html" --path "*input*" | head -1 | xargs cat 2>/dev/null || echo "No template file; check inline template in component"

Length of output: 233


🏁 Script executed:

#!/bin/bash
# Check for inline template
fd -e "float.label.component.ts" --path "*input*" | head -1 | xargs grep -n "template:" -A 50

Length of output: 233


🏁 Script executed:

#!/bin/bash
# Search for any comments explaining the focus/blur listener logic
fd -e "float.label.component.ts" --path "*input*" | head -1 | xargs grep -n -B 3 "HostListener.*focus\|HostListener.*blur\|HostListener.*input"

Length of output: 233


🏁 Script executed:

#!/bin/bash
# Check if event.target is used anywhere in the component
fd -e "float.label.component.ts" --path "*input*" | head -1 | xargs grep -n "event\.target\|event\." 

Length of output: 233


🏁 Script executed:

#!/bin/bash
# Look at surrounding context for the onInteraction method signature
fd -e "float.label.component.ts" --path "*input*" | head -1 | xargs grep -n -B 5 "onInteraction"

Length of output: 233


🏁 Script executed:

#!/bin/bash
# Verify the complete structure of the component and list all methods
fd -e "float.label.component.ts" --path "*input*" | head -1 | xargs grep -n "^\s*[a-zA-Z_][a-zA-Z0-9_]*\s*("

Length of output: 233


🏁 Script executed:

#!/bin/bash
# Check if there's a specific implementation reason for listening to focus/blur (e.g., to sync child state)
fd -e "float.label.component.ts" --path "*input*" | head -1 | xargs grep -n -C 15 "@HostListener"

Length of output: 233


🏁 Script executed:

#!/bin/bash
# Final verification: grep all event listener related to input, focus, blur in the component
fd -e "float.label.component.ts" --path "*input*" | head -1 | xargs egrep -n "input|focus|blur" | head -30

Length of output: 233


🏁 Script executed:

#!/bin/bash
# Look for any child component or projected content handling
fd -e "float.label.component.ts" --path "*input*" | head -1 | xargs grep -n "ng-content\|@ContentChild\|@ViewChild"

Length of output: 233


🏁 Script executed:

#!/bin/bash
# Check if the component uses ::ng-deep or any CSS targeting that might justify focus/blur listeners
fd -e "float.label.component.ts" --path "*input*" | head -1 | xargs grep -n "ng-deep\|::ng-deep"

Length of output: 233


🏁 Script executed:

#!/bin/bash
# Verify by examining implementation directly - get the method body
fd -e "float.label.component.ts" --path "*input*" | head -1 | xargs sed -n '71,76p'

Length of output: 233


🏁 Script executed:

#!/bin/bash
# Complete view of the entire file to understand context
fd -e "float.label.component.ts" --path "*input*" | head -1

Length of output: 233


🏁 Script executed:

#!/bin/bash
# Get the path and show the full file
find . -name "float.label.component.ts" -type f 2>/dev/null | head -1

Length of output: 61


🏁 Script executed:

#!/bin/bash
# Direct file path lookup and display
find . -path "*input*float.label.component.ts" -type f 2>/dev/null | xargs cat

Length of output: 2872


🏁 Script executed:

#!/bin/bash
# Try alternative search pattern
find libs -name "*float*label*.ts" -type f 2>/dev/null | head -5

Length of output: 59


🏁 Script executed:

#!/bin/bash
# List all TypeScript files in the input component directory
find libs/zard/src/lib/components/input -name "*.ts" -type f 2>/dev/null

Length of output: 585


🏁 Script executed:

#!/bin/bash
# View all files in the input directory
ls -la libs/zard/src/lib/components/input/ 2>/dev/null || echo "Directory not found"

Length of output: 508


🏁 Script executed:

#!/bin/bash
# Check if the directory structure matches the expected path
find libs/zard/src/lib/components -type d -name "input" 2>/dev/null

Length of output: 34


🏁 Script executed:

#!/bin/bash
# Search for float.label pattern anywhere in the libs directory
find libs -name "*float*" -type f 2>/dev/null | head -10

Length of output: 114


🏁 Script executed:

#!/bin/bash
# Broad search for label component files
find libs -name "*label*.component.ts" -type f 2>/dev/null | head -10

Length of output: 125


🏁 Script executed:

#!/bin/bash
# Look in zard components for any file containing "float"
find libs/zard -name "*.ts" -type f 2>/dev/null | xargs grep -l "float" | head -5

Length of output: 163


🏁 Script executed:

#!/bin/bash
# Try rg to search for the HostListener pattern with focus/blur
rg -l "HostListener.*focus.*blur|HostListener.*blur.*focus" libs/zard/ 2>/dev/null | head -5

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Search for HostListener specifically with blur
rg "HostListener.*blur" libs/zard/src/lib/components/ 2>/dev/null | head -5

Length of output: 95


🏁 Script executed:

#!/bin/bash
# Search for @HostListener in input components
rg "@HostListener" libs/zard/src/lib/components/input 2>/dev/null | head -20

Length of output: 289


🏁 Script executed:

#!/bin/bash
# List all components in the input directory
find libs/zard/src/lib/components/input -type f 2>/dev/null

Length of output: 682


🏁 Script executed:

#!/bin/bash
# Check if libs/zard directory exists
ls -la libs/zard/src/lib/components/ 2>/dev/null | head -20

Length of output: 1084


🏁 Script executed:

#!/bin/bash
# Find all component files
find . -name "*.component.ts" -path "*input*" 2>/dev/null | head -10

Length of output: 195


🏁 Script executed:

#!/bin/bash
# Search for files that contain both HostListener and updateLabelState
rg -l "HostListener.*updateLabelState|updateLabelState.*HostListener" . 2>/dev/null | head -5

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Search for updateLabelState method
rg -n "updateLabelState" . 2>/dev/null | head -10

Length of output: 525


🏁 Script executed:

#!/bin/bash
# Look for files with input, focus, blur HostListeners together
rg "HostListener.*input.*HostListener.*focus.*HostListener.*blur" . 2>/dev/null | head -5

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Search with multiline pattern for the exact code snippet
rg -U "@HostListener\('input'.*@HostListener\('focus'.*@HostListener\('blur'" . 2>/dev/null | head -5

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Try to find by exact method name onInteraction
rg -n "onInteraction" . 2>/dev/null | head -10

Length of output: 179


🏁 Script executed:

#!/bin/bash
# Check repository structure
find . -type d -name "zard" | head -5

Length of output: 11


🏁 Script executed:

#!/bin/bash
# List current directory to understand structure
ls -la | head -20

Length of output: 389


🏁 Script executed:

#!/bin/bash
# Get git info about the PR
git log --oneline -5 2>/dev/null || echo "Not a git repo or git not available"

Length of output: 266


🏁 Script executed:

#!/bin/bash
# Show changed files in PR
git diff --name-only HEAD~1..HEAD 2>/dev/null | grep -i "label\|input" | head -10

Length of output: 315


🏁 Script executed:

#!/bin/bash
# Find modified files with HostListener
git diff --name-only HEAD~1..HEAD 2>/dev/null | xargs -I {} grep -l "HostListener" {} 2>/dev/null | head -5

Length of output: 104


🏁 Script executed:

#!/bin/bash
# Search all TypeScript files for the code pattern from the review
rg -A 5 "@HostListener\('input'" . --type ts 2>/dev/null | head -30

Length of output: 546


🏁 Script executed:

#!/bin/bash
# Search for the exact error pattern
rg -n "onInteraction" --type ts 2>/dev/null | head -10

Length of output: 94


🏁 Script executed:

#!/bin/bash
# Alternative: search by exact line content
rg "updateLabelState" --type ts 2>/dev/null | head -20

Length of output: 268


🏁 Script executed:

#!/bin/bash
# Check if file exists at exact path
test -f "libs/zard/src/lib/components/input/float.label.component.ts" && echo "File exists" || echo "File not found"

Length of output: 11


🏁 Script executed:

#!/bin/bash
# If it exists, display it
if [ -f "libs/zard/src/lib/components/input/float.label.component.ts" ]; then
  cat "libs/zard/src/lib/components/input/float.label.component.ts"
else
  echo "File does not exist at expected path"
  # Try to find it
  find . -name "float.label.component.ts" 2>/dev/null
fi

Length of output: 2872


🏁 Script executed:

#!/bin/bash
# List component directory if it exists
if [ -d "libs/zard/src/lib/components/input" ]; then
  ls -la "libs/zard/src/lib/components/input/"
else
  find . -type d -name "input" | grep components | head -5
fi

Length of output: 508


🏁 Script executed:

#!/bin/bash
# Comprehensive search using multiple strategies
echo "=== Searching for float.label component ===" && \
(find . -name "float.label.component.ts" 2>/dev/null || echo "Not found via find") && \
echo "=== Searching via rg ===" && \
(rg -l "float.label" . 2>/dev/null || echo "Not found via rg") && \
echo "=== Searching for onInteraction method ===" && \
(rg -l "onInteraction" . 2>/dev/null | head -3 || echo "Not found")

Length of output: 554


🏁 Script executed:

#!/bin/bash
# Show repository structure
tree -L 3 libs/zard/src/lib/components 2>/dev/null || find libs/zard/src/lib/components -maxdepth 3 -type f 2>/dev/null | head -20

Length of output: 12757


🏁 Script executed:

#!/bin/bash
# PWD and repo info
pwd && echo "---" && find . -maxdepth 2 -name ".git" -o -name "package.json" | head -5

Length of output: 29


Remove dead focus/blur listeners and unused $event parameter; input tracking via CSS :has(:focus) is already in place

The review is accurate. @HostListener('focus') and @HostListener('blur') on the host component never fire because these events don't bubble from the projected child inputs. The CSS already uses :has(input:focus), :has(textarea:focus), etc., making the focus listeners redundant. Additionally, the event: Event parameter is never used in onInteraction().

Apply the suggested refactor to keep only the functional input listener:

-  @HostListener('input', ['$event'])
-  @HostListener('focus', ['$event'])
-  @HostListener('blur', ['$event'])
-  onInteraction(event: Event) {
-    this.updateLabelState();
-  }
+  @HostListener('input')
+  onInput() {
+    this.updateLabelState();
+  }
🤖 Prompt for AI Agents
In libs/zard/src/lib/components/input/float.label.component.ts around lines 71
to 76, remove the dead @HostListener('focus') and @HostListener('blur')
decorators and the unused event parameter from onInteraction; keep only
@HostListener('input') so the method becomes parameterless (onInteraction()) and
rely on the existing CSS :has(...) focus handling; update the method signature
and delete the unused parameter reference accordingly.

Copy link
Contributor

Choose a reason for hiding this comment

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

and move to component decorator any host related stuff

Copy link

Choose a reason for hiding this comment

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

@mikij, absolutely! Per the coding guidelines that flag @HostListener, let's move the event binding to the @Component decorator's host property. Combined with the earlier suggestion to drop the dead focus/blur listeners, here's the complete refactor:

In the @Component decorator, add:

@Component({
  selector: 'zard-float-label',
  standalone: true,
  template: `<ng-content />`,
  encapsulation: ViewEncapsulation.None,
  host: {
    '(input)': 'onInput()'
  },
  styles: `...`
})

Then remove the @HostListener decorators and simplify the method:

-  @HostListener('input', ['$event'])
-  @HostListener('focus', ['$event'])
-  @HostListener('blur', ['$event'])
-  onInteraction(event: Event) {
-    this.updateLabelState();
-  }
+  onInput() {
+    this.updateLabelState();
+  }

This keeps focus handling entirely in CSS (:has(...:focus)) while moving the input listener to the declarative host binding—cleaner and aligned with the project's Angular patterns.


✏️ Learnings added
Learnt from: mikij
Repo: zard-ui/zardui PR: 326
File: libs/zard/src/lib/components/input/float.label.component.ts:71-0
Timestamp: 2025-11-14T22:52:09.094Z
Learning: In libs/zard/src/lib/components/*/*.component.ts files, move HostListener and HostBinding to the Component decorator's host property instead of using decorators on class members (e.g., host: { '(input)': 'onInput()' }).

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.


🧠 Learnings used
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-10-17T19:24:10.610Z
Learning: Applies to libs/zard/src/lib/components/*/*.component.ts : Component selector should follow: 'z-[name], [z-[name]]' (element and attribute selectors)

Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-10-17T19:24:10.610Z
Learning: Applies to libs/zard/src/lib/components/*/*.component.ts : Use signal-based inputs via input() for public inputs (e.g., variant, size, class)

Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-10-15T00:51:30.882Z
Learning: Applies to libs/zard/src/lib/components/**/*.component.ts : Use signal-based inputs via input() for component inputs (e.g., variant, size, class)

Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-10-15T00:51:30.882Z
Learning: Applies to libs/zard/src/lib/components/**/*.component.ts : Bind host class to computed classes via host: { '[class]': 'classes()' }

Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-10-17T19:24:10.610Z
Learning: Applies to libs/zard/src/lib/components/*/*.component.ts : Host-bind the class attribute and compute classes via computed() + mergeClasses(CVA(...), class)

Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: libs/blocks/README.md:0-0
Timestamp: 2025-10-17T17:12:22.571Z
Learning: Applies to libs/blocks/src/lib/*/*.component.{ts,html} : Use ZardUI form components for validation (FormField, FormLabel, FormControl) in blocks with forms

Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-10-15T00:51:30.882Z
Learning: Applies to libs/zard/src/lib/components/**/*.component.ts : Provide a selector in the form 'z-[name], [z-[name]]' for each component

Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-10-15T00:51:30.882Z
Learning: Applies to apps/web/src/app/shared/constants/components.constant.ts : Update the component registry when adding components to ensure docs/demo rendering

Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-10-17T19:24:10.610Z
Learning: Applies to libs/zard/src/lib/components/*/*.component.ts : Place each Angular component in its own folder and name the main file [name].component.ts under libs/zard/src/lib/components/[name]/

Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-10-15T00:51:30.882Z
Learning: Applies to libs/zard/src/lib/components/components.ts : Export new components from libs/zard/src/lib/components/components.ts

Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-10-17T19:24:10.610Z
Learning: Applies to libs/zard/src/lib/components/*/*.component.ts : Use Tailwind utility classes and resolve class conflicts via tailwind-merge (through mergeClasses) in components

Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-10-15T00:51:30.882Z
Learning: Applies to libs/zard/src/lib/components/**/*.component.ts : Use ChangeDetectionStrategy.OnPush for all Angular components

Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-10-17T19:24:10.610Z
Learning: Applies to libs/zard/src/lib/components/components.ts : Export new components from the barrel file libs/zard/src/lib/components/components.ts


@Component({
selector: 'z-demo-input-float-input',
standalone: true,
Copy link
Contributor

Choose a reason for hiding this comment

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

remove standalone as it is true by default

Copy link
Contributor

@mikij mikij left a comment

Choose a reason for hiding this comment

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

what are the changes in the lock file?

Copy link
Contributor

@ribeiromatheuss ribeiromatheuss left a comment

Choose a reason for hiding this comment

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

need include tests

Copy link
Contributor

@ribeiromatheuss ribeiromatheuss left a comment

Choose a reason for hiding this comment

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

I believe this component should be part of the forms component in a separate file

Copy link
Contributor

Choose a reason for hiding this comment

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

Change the filename to float-label

Copy link
Contributor

Choose a reason for hiding this comment

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

Change the filename to float-label.component.ts

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 5

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
libs/zard/src/lib/components/select/select.component.ts (2)

200-205: Prefer explicit fromEvent/renderer.listen over @HostListener('document:click')

Given the project’s move away from @HostListener, it would be more in line with current patterns to replace the document:click HostListener with an RxJS/Renderer2 subscription that you attach conditionally in ngOnInit/ngAfterViewInit (behind isPlatformBrowser(this.platformId)) and tear down via the existing Subscription in ngOnDestroy. This also centralizes cleanup in one place.

Not blocking, but worth aligning with the newer event-handling approach used elsewhere in the library.


161-167: Keep input-has-value in sync when zValue or writeValue changes

The new updateSelectState wiring (form valueChanges, focus/blur, and initial call in ngAfterContentInit) correctly tracks form-driven changes, but pure @Input() zValue changes after initialization and calls to writeValue won't automatically toggle input-has-value. selectedValue will update due to its computed dependency, yet updateSelectState is never invoked for those changes.

To keep float-label behavior consistent:

  • Call this.updateSelectState() from writeValue (line 347) and add an effect on zValue() to sync the class whenever either changes.
  • Or create a single side-effect that reacts to selectedValue() changes and calls updateSelectState (guarding against SSR if needed).

Also, refactor updateSelectState from a private arrow property (line 318) to a private method—arrow properties create per-instance allocations and don't follow Angular conventions. Replace private updateSelectState = () => { ... } with private updateSelectState(): void { ... }.

Additionally, move the @HostListener('document:click') decorator (line 201) to use a subscription-based approach with fromEvent + Renderer2.listen() + platform guard, consistent with your existing pattern for button focus/blur events and aligned with framework guidelines.

libs/zard/src/lib/components/input/input.directive.ts (1)

17-73: Input state wiring looks solid; tighten updateInputState visibility

The new form/DOM subscriptions and Renderer2 usage correctly keep input-has-value and data-status in sync, and teardown via Subscription in ngOnDestroy is good.

Since updateInputState is only called internally, consider:

  • Making it private, and
  • Defining it as a regular method (private updateInputState(): void { ... }) instead of a public arrow property, to avoid unintentionally exposing it on the directive’s public surface and to reduce per-instance allocations.

Behavior doesn’t change, but the API surface stays slimmer.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ce4becc and a66451f.

⛔ Files ignored due to path filters (16)
  • apps/web/public/components/float-label/demo/borderless.md is excluded by !apps/web/public/** and included by apps/**
  • apps/web/public/components/float-label/demo/default.md is excluded by !apps/web/public/** and included by apps/**
  • apps/web/public/components/float-label/demo/float.input.md is excluded by !apps/web/public/** and included by apps/**
  • apps/web/public/components/float-label/demo/input.md is excluded by !apps/web/public/** and included by apps/**
  • apps/web/public/components/float-label/demo/select.md is excluded by !apps/web/public/** and included by apps/**
  • apps/web/public/components/float-label/demo/size.md is excluded by !apps/web/public/** and included by apps/**
  • apps/web/public/components/float-label/demo/status.md is excluded by !apps/web/public/** and included by apps/**
  • apps/web/public/components/float-label/demo/text-area.md is excluded by !apps/web/public/** and included by apps/**
  • apps/web/public/components/float-label/demo/textarea.md is excluded by !apps/web/public/** and included by apps/**
  • apps/web/public/components/float-label/doc/api.md is excluded by !apps/web/public/** and included by apps/**
  • apps/web/public/components/float-label/doc/overview.md is excluded by !apps/web/public/** and included by apps/**
  • apps/web/public/components/input/demo/float.input.md is excluded by !apps/web/public/** and included by apps/**
  • apps/web/public/installation/cli/add-float-label.md is excluded by !apps/web/public/** and included by apps/**
  • apps/web/public/installation/manual/float-label.md is excluded by !apps/web/public/** and included by apps/**
  • apps/web/public/installation/manual/input.md is excluded by !apps/web/public/** and included by apps/**
  • apps/web/public/installation/manual/select.md is excluded by !apps/web/public/** and included by apps/**
📒 Files selected for processing (15)
  • apps/web/prerender-routes.txt (1 hunks)
  • apps/web/src/app/shared/constants/routes.constant.ts (1 hunks)
  • libs/zard/src/lib/components/float-label/demo/default.ts (1 hunks)
  • libs/zard/src/lib/components/float-label/demo/input.ts (1 hunks)
  • libs/zard/src/lib/components/float-label/demo/select.ts (1 hunks)
  • libs/zard/src/lib/components/float-label/demo/status.ts (1 hunks)
  • libs/zard/src/lib/components/float-label/demo/text-area.ts (1 hunks)
  • libs/zard/src/lib/components/float-label/doc/api.md (1 hunks)
  • libs/zard/src/lib/components/float-label/doc/overview.md (1 hunks)
  • libs/zard/src/lib/components/float-label/float.label.component.ts (1 hunks)
  • libs/zard/src/lib/components/float-label/float.label.spec.ts (1 hunks)
  • libs/zard/src/lib/components/float-label/float.label.variants.ts (1 hunks)
  • libs/zard/src/lib/components/input/demo/input.ts (1 hunks)
  • libs/zard/src/lib/components/input/input.directive.ts (2 hunks)
  • libs/zard/src/lib/components/select/select.component.ts (7 hunks)
🧰 Additional context used
📓 Path-based instructions (12)
libs/zard/src/lib/components/**/demo/**/*.ts

📄 CodeRabbit inference engine (CLAUDE.md)

Place demo files under a demo/ directory (including a main demo export file, default.ts, and variant example files)

Files:

  • libs/zard/src/lib/components/float-label/demo/input.ts
  • libs/zard/src/lib/components/float-label/demo/select.ts
  • libs/zard/src/lib/components/float-label/demo/status.ts
  • libs/zard/src/lib/components/input/demo/input.ts
  • libs/zard/src/lib/components/float-label/demo/text-area.ts
  • libs/zard/src/lib/components/float-label/demo/default.ts
libs/zard/src/lib/components/**/doc/{overview,api}.md

📄 CodeRabbit inference engine (CLAUDE.md)

Provide documentation files overview.md and api.md under each component's doc/ directory

Files:

  • libs/zard/src/lib/components/float-label/doc/api.md
  • libs/zard/src/lib/components/float-label/doc/overview.md
libs/zard/src/lib/components/*/doc/api.md

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Provide documentation: doc/api.md for complete API reference (props, events, methods)

Files:

  • libs/zard/src/lib/components/float-label/doc/api.md
libs/zard/src/lib/components/**/*.variants.ts

📄 CodeRabbit inference engine (CLAUDE.md)

Define styling variants with Class Variance Authority (CVA) in a companion .variants.ts file

Files:

  • libs/zard/src/lib/components/float-label/float.label.variants.ts
libs/zard/src/lib/components/**/*.{component,variants}.ts

📄 CodeRabbit inference engine (CLAUDE.md)

Use tailwind-merge for class merging and clsx for conditional classes when composing CSS classes

Files:

  • libs/zard/src/lib/components/float-label/float.label.variants.ts
  • libs/zard/src/lib/components/float-label/float.label.component.ts
  • libs/zard/src/lib/components/select/select.component.ts
libs/zard/src/lib/components/*/*.variants.ts

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Define component variants with CVA in a dedicated [name].variants.ts file and export typed variants

Files:

  • libs/zard/src/lib/components/float-label/float.label.variants.ts
libs/zard/src/lib/components/**/*.spec.ts

📄 CodeRabbit inference engine (CLAUDE.md)

Co-locate unit tests next to components using .spec.ts filenames

Files:

  • libs/zard/src/lib/components/float-label/float.label.spec.ts
libs/zard/src/lib/components/*/*.spec.ts

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Co-locate Jest tests next to components in [name].spec.ts using Angular Testing Utilities and @happy-dom/jest-environment

Files:

  • libs/zard/src/lib/components/float-label/float.label.spec.ts
libs/zard/src/lib/components/**/*.component.ts

📄 CodeRabbit inference engine (CLAUDE.md)

libs/zard/src/lib/components/**/*.component.ts: Angular components must be standalone (standalone: true)
Use ChangeDetectionStrategy.OnPush for all Angular components
Bind host class to computed classes via host: { '[class]': 'classes()' }
Use signal-based inputs via input() for component inputs (e.g., variant, size, class)
Provide a selector in the form 'z-[name], [z-[name]]' for each component

Files:

  • libs/zard/src/lib/components/float-label/float.label.component.ts
  • libs/zard/src/lib/components/select/select.component.ts
libs/zard/src/lib/components/*/*.component.ts

📄 CodeRabbit inference engine (CONTRIBUTING.md)

libs/zard/src/lib/components/*/*.component.ts: Place each Angular component in its own folder and name the main file [name].component.ts under libs/zard/src/lib/components/[name]/
Components must be standalone (standalone: true) and use ChangeDetectionStrategy.OnPush
Component selector should follow: 'z-[name], [z-[name]]' (element and attribute selectors)
Use signal-based inputs via input() for public inputs (e.g., variant, size, class)
Host-bind the class attribute and compute classes via computed() + mergeClasses(CVA(...), class)
Use Tailwind utility classes and resolve class conflicts via tailwind-merge (through mergeClasses) in components

Files:

  • libs/zard/src/lib/components/float-label/float.label.component.ts
  • libs/zard/src/lib/components/select/select.component.ts
libs/zard/src/lib/components/*/doc/overview.md

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Provide documentation: doc/overview.md for overview, use cases, and basic examples

Files:

  • libs/zard/src/lib/components/float-label/doc/overview.md
libs/zard/src/lib/components/*/demo/default.ts

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Each component must provide a demo/default.ts exporting a DefaultExample with name, code, and lazy-loaded component

Files:

  • libs/zard/src/lib/components/float-label/demo/default.ts
🧠 Learnings (34)
📓 Common learnings
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: libs/blocks/README.md:0-0
Timestamp: 2025-10-17T17:12:22.571Z
Learning: Applies to libs/blocks/src/lib/*/*.component.{ts,html} : Use ZardUI form components for validation (FormField, FormLabel, FormControl) in blocks with forms
📚 Learning: 2025-10-15T00:51:30.882Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-10-15T00:51:30.882Z
Learning: Applies to libs/zard/src/lib/components/**/demo/**/*.ts : Place demo files under a demo/ directory (including a main demo export file, default.ts, and variant example files)

Applied to files:

  • libs/zard/src/lib/components/float-label/demo/input.ts
  • libs/zard/src/lib/components/float-label/demo/select.ts
  • libs/zard/src/lib/components/float-label/demo/status.ts
  • libs/zard/src/lib/components/float-label/float.label.spec.ts
  • libs/zard/src/lib/components/input/demo/input.ts
  • libs/zard/src/lib/components/float-label/demo/text-area.ts
  • libs/zard/src/lib/components/float-label/demo/default.ts
📚 Learning: 2025-10-17T19:24:10.610Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-10-17T19:24:10.610Z
Learning: Applies to libs/zard/src/lib/components/*/demo/default.ts : Each component must provide a demo/default.ts exporting a DefaultExample with name, code, and lazy-loaded component

Applied to files:

  • libs/zard/src/lib/components/float-label/demo/input.ts
  • libs/zard/src/lib/components/float-label/demo/select.ts
  • libs/zard/src/lib/components/float-label/demo/status.ts
  • libs/zard/src/lib/components/input/demo/input.ts
  • libs/zard/src/lib/components/float-label/demo/text-area.ts
  • libs/zard/src/lib/components/float-label/demo/default.ts
📚 Learning: 2025-10-17T19:24:10.610Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-10-17T19:24:10.610Z
Learning: Applies to libs/zard/src/lib/components/*/*.component.ts : Use signal-based inputs via input() for public inputs (e.g., variant, size, class)

Applied to files:

  • libs/zard/src/lib/components/float-label/demo/input.ts
  • libs/zard/src/lib/components/input/input.directive.ts
  • libs/zard/src/lib/components/input/demo/input.ts
  • libs/zard/src/lib/components/select/select.component.ts
📚 Learning: 2025-10-15T00:51:30.882Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-10-15T00:51:30.882Z
Learning: Applies to libs/zard/src/lib/components/**/*.component.ts : Use signal-based inputs via input() for component inputs (e.g., variant, size, class)

Applied to files:

  • libs/zard/src/lib/components/float-label/demo/input.ts
  • libs/zard/src/lib/components/float-label/demo/status.ts
  • libs/zard/src/lib/components/float-label/float.label.component.ts
  • libs/zard/src/lib/components/input/input.directive.ts
  • libs/zard/src/lib/components/input/demo/input.ts
  • libs/zard/src/lib/components/select/select.component.ts
📚 Learning: 2025-10-15T00:51:30.882Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-10-15T00:51:30.882Z
Learning: Applies to libs/zard/src/lib/components/components.ts : Export new components from libs/zard/src/lib/components/components.ts

Applied to files:

  • libs/zard/src/lib/components/float-label/demo/input.ts
  • libs/zard/src/lib/components/float-label/demo/select.ts
  • libs/zard/src/lib/components/float-label/demo/status.ts
  • libs/zard/src/lib/components/float-label/float.label.spec.ts
  • libs/zard/src/lib/components/float-label/float.label.component.ts
  • libs/zard/src/lib/components/input/input.directive.ts
  • libs/zard/src/lib/components/input/demo/input.ts
  • libs/zard/src/lib/components/float-label/demo/text-area.ts
  • libs/zard/src/lib/components/float-label/demo/default.ts
  • libs/zard/src/lib/components/select/select.component.ts
📚 Learning: 2025-11-10T21:46:33.213Z
Learnt from: mikij
Repo: zard-ui/zardui PR: 318
File: libs/zard/src/lib/components/select/demo/default.ts:21-21
Timestamp: 2025-11-10T21:46:33.213Z
Learning: In demo files under libs/zard/src/lib/components/**/demo/*.ts, intentionally showing different patterns (e.g., primitive values vs signals) across different demos is valuable for demonstrating the flexibility of Angular features like two-way binding.

Applied to files:

  • libs/zard/src/lib/components/float-label/demo/input.ts
  • libs/zard/src/lib/components/float-label/demo/select.ts
  • libs/zard/src/lib/components/float-label/demo/status.ts
  • libs/zard/src/lib/components/float-label/float.label.spec.ts
  • libs/zard/src/lib/components/input/demo/input.ts
  • libs/zard/src/lib/components/float-label/demo/text-area.ts
  • libs/zard/src/lib/components/float-label/demo/default.ts
  • libs/zard/src/lib/components/select/select.component.ts
📚 Learning: 2025-11-04T20:46:01.373Z
Learnt from: mikij
Repo: zard-ui/zardui PR: 309
File: libs/zard/src/lib/components/select/demo/multi-select.ts:23-27
Timestamp: 2025-11-04T20:46:01.373Z
Learning: In demo files under libs/zard/src/lib/components/**/demo/*.ts, console.log statements are acceptable and often intentional to demonstrate reactivity and help users understand how the component works.

Applied to files:

  • libs/zard/src/lib/components/float-label/demo/input.ts
  • libs/zard/src/lib/components/float-label/demo/select.ts
  • libs/zard/src/lib/components/float-label/demo/status.ts
  • libs/zard/src/lib/components/float-label/float.label.spec.ts
  • libs/zard/src/lib/components/input/demo/input.ts
  • libs/zard/src/lib/components/float-label/demo/text-area.ts
  • libs/zard/src/lib/components/float-label/demo/default.ts
📚 Learning: 2025-10-17T19:24:10.610Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-10-17T19:24:10.610Z
Learning: Applies to libs/zard/src/lib/components/components.ts : Export new components from the barrel file libs/zard/src/lib/components/components.ts

Applied to files:

  • libs/zard/src/lib/components/float-label/demo/input.ts
  • libs/zard/src/lib/components/float-label/demo/select.ts
  • libs/zard/src/lib/components/float-label/demo/status.ts
  • libs/zard/src/lib/components/float-label/float.label.component.ts
  • libs/zard/src/lib/components/input/input.directive.ts
  • libs/zard/src/lib/components/input/demo/input.ts
  • libs/zard/src/lib/components/float-label/demo/text-area.ts
  • libs/zard/src/lib/components/float-label/demo/default.ts
  • libs/zard/src/lib/components/select/select.component.ts
📚 Learning: 2025-10-17T17:12:22.571Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: libs/blocks/README.md:0-0
Timestamp: 2025-10-17T17:12:22.571Z
Learning: Applies to libs/blocks/src/lib/*/*.component.{ts,html} : Use ZardUI form components for validation (FormField, FormLabel, FormControl) in blocks with forms

Applied to files:

  • libs/zard/src/lib/components/float-label/demo/input.ts
  • libs/zard/src/lib/components/float-label/demo/select.ts
  • libs/zard/src/lib/components/float-label/demo/status.ts
  • apps/web/prerender-routes.txt
  • libs/zard/src/lib/components/float-label/float.label.spec.ts
  • libs/zard/src/lib/components/float-label/float.label.component.ts
  • libs/zard/src/lib/components/input/input.directive.ts
  • libs/zard/src/lib/components/input/demo/input.ts
  • libs/zard/src/lib/components/float-label/demo/text-area.ts
  • libs/zard/src/lib/components/float-label/demo/default.ts
  • libs/zard/src/lib/components/select/select.component.ts
📚 Learning: 2025-10-15T00:51:30.882Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-10-15T00:51:30.882Z
Learning: Applies to apps/web/src/app/shared/constants/components.constant.ts : Update the component registry when adding components to ensure docs/demo rendering

Applied to files:

  • libs/zard/src/lib/components/float-label/demo/input.ts
  • apps/web/src/app/shared/constants/routes.constant.ts
📚 Learning: 2025-10-15T00:51:30.882Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-10-15T00:51:30.882Z
Learning: Applies to libs/zard/src/lib/components/**/*.component.ts : Provide a selector in the form 'z-[name], [z-[name]]' for each component

Applied to files:

  • libs/zard/src/lib/components/float-label/demo/input.ts
  • libs/zard/src/lib/components/float-label/demo/select.ts
  • libs/zard/src/lib/components/float-label/doc/api.md
  • libs/zard/src/lib/components/float-label/demo/status.ts
  • libs/zard/src/lib/components/float-label/float.label.spec.ts
  • libs/zard/src/lib/components/float-label/float.label.component.ts
  • libs/zard/src/lib/components/input/input.directive.ts
  • libs/zard/src/lib/components/input/demo/input.ts
  • libs/zard/src/lib/components/float-label/demo/text-area.ts
  • libs/zard/src/lib/components/float-label/demo/default.ts
  • libs/zard/src/lib/components/select/select.component.ts
📚 Learning: 2025-10-17T19:24:10.610Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-10-17T19:24:10.610Z
Learning: Applies to libs/zard/src/lib/components/*/*.component.ts : Component selector should follow: 'z-[name], [z-[name]]' (element and attribute selectors)

Applied to files:

  • libs/zard/src/lib/components/float-label/demo/select.ts
  • libs/zard/src/lib/components/float-label/doc/api.md
  • libs/zard/src/lib/components/float-label/demo/status.ts
  • libs/zard/src/lib/components/float-label/float.label.spec.ts
  • libs/zard/src/lib/components/float-label/float.label.component.ts
  • libs/zard/src/lib/components/input/input.directive.ts
  • libs/zard/src/lib/components/float-label/demo/text-area.ts
  • libs/zard/src/lib/components/float-label/demo/default.ts
  • libs/zard/src/lib/components/select/select.component.ts
📚 Learning: 2025-10-17T19:24:10.610Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-10-17T19:24:10.610Z
Learning: Applies to libs/zard/src/lib/components/*/*.component.ts : Place each Angular component in its own folder and name the main file [name].component.ts under libs/zard/src/lib/components/[name]/

Applied to files:

  • libs/zard/src/lib/components/float-label/demo/select.ts
  • libs/zard/src/lib/components/float-label/demo/status.ts
  • libs/zard/src/lib/components/float-label/float.label.spec.ts
  • libs/zard/src/lib/components/float-label/float.label.component.ts
  • libs/zard/src/lib/components/input/input.directive.ts
  • libs/zard/src/lib/components/input/demo/input.ts
  • libs/zard/src/lib/components/float-label/demo/text-area.ts
  • libs/zard/src/lib/components/float-label/demo/default.ts
📚 Learning: 2025-10-17T19:24:10.610Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-10-17T19:24:10.610Z
Learning: Applies to libs/zard/src/lib/components/*/*.spec.ts : Co-locate Jest tests next to components in [name].spec.ts using Angular Testing Utilities and happy-dom/jest-environment

Applied to files:

  • libs/zard/src/lib/components/float-label/demo/select.ts
  • libs/zard/src/lib/components/float-label/float.label.spec.ts
📚 Learning: 2025-10-17T19:24:10.610Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-10-17T19:24:10.610Z
Learning: Applies to libs/zard/src/lib/components/*/doc/api.md : Provide documentation: doc/api.md for complete API reference (props, events, methods)

Applied to files:

  • libs/zard/src/lib/components/float-label/doc/api.md
  • libs/zard/src/lib/components/float-label/doc/overview.md
📚 Learning: 2025-10-15T00:51:30.882Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-10-15T00:51:30.882Z
Learning: Applies to libs/zard/src/lib/components/**/doc/{overview,api}.md : Provide documentation files overview.md and api.md under each component's doc/ directory

Applied to files:

  • libs/zard/src/lib/components/float-label/doc/api.md
  • libs/zard/src/lib/components/float-label/doc/overview.md
📚 Learning: 2025-10-17T19:24:10.610Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-10-17T19:24:10.610Z
Learning: Applies to libs/zard/src/lib/components/*/doc/overview.md : Provide documentation: doc/overview.md for overview, use cases, and basic examples

Applied to files:

  • libs/zard/src/lib/components/float-label/doc/api.md
  • libs/zard/src/lib/components/float-label/doc/overview.md
📚 Learning: 2025-11-04T10:18:55.477Z
Learnt from: mihajm
Repo: zard-ui/zardui PR: 308
File: libs/zard/src/lib/components/button-group/doc/overview.md:1-3
Timestamp: 2025-11-04T10:18:55.477Z
Learning: In zardui repo, doc/overview.md files for components should contain only a brief overview description. Examples are provided through separate demo files and the api.md documentation, not in overview.md.

Applied to files:

  • libs/zard/src/lib/components/float-label/doc/api.md
  • libs/zard/src/lib/components/float-label/doc/overview.md
📚 Learning: 2025-10-15T00:51:30.882Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-10-15T00:51:30.882Z
Learning: Applies to libs/zard/src/lib/components/**/*.variants.ts : Define styling variants with Class Variance Authority (CVA) in a companion <name>.variants.ts file

Applied to files:

  • libs/zard/src/lib/components/float-label/float.label.variants.ts
  • libs/zard/src/lib/components/input/input.directive.ts
📚 Learning: 2025-10-17T19:24:10.610Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-10-17T19:24:10.610Z
Learning: Applies to libs/zard/src/lib/components/*/*.variants.ts : Define component variants with CVA in a dedicated [name].variants.ts file and export typed variants

Applied to files:

  • libs/zard/src/lib/components/float-label/float.label.variants.ts
📚 Learning: 2025-10-17T19:24:10.610Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-10-17T19:24:10.610Z
Learning: Applies to libs/zard/src/lib/components/*/*.component.ts : Use Tailwind utility classes and resolve class conflicts via tailwind-merge (through mergeClasses) in components

Applied to files:

  • libs/zard/src/lib/components/float-label/float.label.variants.ts
  • libs/zard/src/lib/components/float-label/float.label.spec.ts
  • libs/zard/src/lib/components/float-label/float.label.component.ts
  • libs/zard/src/lib/components/input/input.directive.ts
  • libs/zard/src/lib/components/select/select.component.ts
📚 Learning: 2025-10-15T00:51:30.882Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-10-15T00:51:30.882Z
Learning: Applies to libs/zard/src/lib/components/**/*.{component,variants}.ts : Use tailwind-merge for class merging and clsx for conditional classes when composing CSS classes

Applied to files:

  • libs/zard/src/lib/components/float-label/float.label.variants.ts
  • libs/zard/src/lib/components/float-label/float.label.component.ts
  • libs/zard/src/lib/components/input/input.directive.ts
📚 Learning: 2025-10-15T00:53:17.826Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: packages/cli/README.md:0-0
Timestamp: 2025-10-15T00:53:17.826Z
Learning: Applies to packages/cli/**/components.json : Keep ZardUI CLI configuration in components.json (style, tailwind.css path, baseColor, cssVariables, aliases)

Applied to files:

  • libs/zard/src/lib/components/float-label/float.label.variants.ts
📚 Learning: 2025-11-14T22:52:09.094Z
Learnt from: mikij
Repo: zard-ui/zardui PR: 326
File: libs/zard/src/lib/components/input/float.label.component.ts:71-0
Timestamp: 2025-11-14T22:52:09.094Z
Learning: In libs/zard/src/lib/components/*/*.component.ts files, move HostListener and HostBinding to the Component decorator's host property instead of using decorators on class members (e.g., host: { '(input)': 'onInput()' }).

Applied to files:

  • libs/zard/src/lib/components/float-label/demo/status.ts
  • libs/zard/src/lib/components/float-label/float.label.spec.ts
  • libs/zard/src/lib/components/float-label/float.label.component.ts
  • libs/zard/src/lib/components/input/input.directive.ts
  • libs/zard/src/lib/components/input/demo/input.ts
  • libs/zard/src/lib/components/float-label/demo/text-area.ts
  • libs/zard/src/lib/components/select/select.component.ts
📚 Learning: 2025-10-17T17:12:22.571Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: libs/blocks/README.md:0-0
Timestamp: 2025-10-17T17:12:22.571Z
Learning: Applies to libs/blocks/src/lib/*/*.component.ts : Use ReactiveFormsModule for form handling in block components that include forms

Applied to files:

  • libs/zard/src/lib/components/float-label/demo/status.ts
  • libs/zard/src/lib/components/float-label/demo/text-area.ts
  • libs/zard/src/lib/components/float-label/demo/default.ts
📚 Learning: 2025-10-17T19:24:10.610Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-10-17T19:24:10.610Z
Learning: Applies to apps/web/public/components/*/{demo,doc}/** : Demo and doc files in apps/web/public/components/*/{demo,doc} are synchronized outputs; source of truth lives under libs/zard/src/lib/components/*/{demo,doc}

Applied to files:

  • apps/web/prerender-routes.txt
📚 Learning: 2025-10-15T00:51:30.882Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-10-15T00:51:30.882Z
Learning: Applies to libs/zard/src/lib/components/**/*.spec.ts : Co-locate unit tests next to components using .spec.ts filenames

Applied to files:

  • libs/zard/src/lib/components/float-label/float.label.spec.ts
📚 Learning: 2025-10-15T00:51:30.882Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-10-15T00:51:30.882Z
Learning: Applies to libs/zard/src/lib/components/**/*.component.ts : Bind host class to computed classes via host: { '[class]': 'classes()' }

Applied to files:

  • libs/zard/src/lib/components/float-label/float.label.spec.ts
  • libs/zard/src/lib/components/float-label/float.label.component.ts
  • libs/zard/src/lib/components/input/input.directive.ts
📚 Learning: 2025-10-17T19:24:10.610Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-10-17T19:24:10.610Z
Learning: Applies to libs/zard/src/lib/components/*/*.component.ts : Host-bind the class attribute and compute classes via computed() + mergeClasses(CVA(...), class)

Applied to files:

  • libs/zard/src/lib/components/float-label/float.label.component.ts
  • libs/zard/src/lib/components/input/input.directive.ts
📚 Learning: 2025-10-15T00:51:30.882Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-10-15T00:51:30.882Z
Learning: Applies to libs/zard/src/lib/components/**/*.component.ts : Use ChangeDetectionStrategy.OnPush for all Angular components

Applied to files:

  • libs/zard/src/lib/components/input/input.directive.ts
  • libs/zard/src/lib/components/select/select.component.ts
📚 Learning: 2025-10-15T00:51:30.882Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-10-15T00:51:30.882Z
Learning: Applies to libs/zard/src/index.ts : Maintain the library public entry point in libs/zard/src/index.ts

Applied to files:

  • libs/zard/src/lib/components/input/input.directive.ts
  • libs/zard/src/lib/components/input/demo/input.ts
📚 Learning: 2025-10-31T10:03:18.563Z
Learnt from: mikij
Repo: zard-ui/zardui PR: 299
File: libs/zard/src/lib/components/select/select.component.ts:34-38
Timestamp: 2025-10-31T10:03:18.563Z
Learning: In Angular 19+ (including Angular 20 used in this project), components are standalone by default. The `standalone: true` flag is redundant and should be omitted unless explicitly setting `standalone: false` to opt out.

Applied to files:

  • libs/zard/src/lib/components/select/select.component.ts
📚 Learning: 2025-10-15T00:53:17.826Z
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: packages/cli/README.md:0-0
Timestamp: 2025-10-15T00:53:17.826Z
Learning: Applies to packages/cli/src/app/shared/components/**/*.{ts,html,css} : Place shared Angular UI components under src/app/shared/components

Applied to files:

  • apps/web/src/app/shared/constants/routes.constant.ts
🧬 Code graph analysis (6)
libs/zard/src/lib/components/float-label/demo/select.ts (2)
libs/zard/src/lib/components/float-label/float.label.component.ts (1)
  • Component (7-44)
libs/zard/src/lib/components/select/select.component.ts (1)
  • Component (38-496)
libs/zard/src/lib/components/float-label/demo/status.ts (1)
libs/zard/src/lib/components/float-label/float.label.component.ts (1)
  • Component (7-44)
libs/zard/src/lib/components/float-label/float.label.component.ts (7)
libs/zard/src/lib/components/float-label/demo/default.ts (1)
  • Component (8-26)
libs/zard/src/lib/components/float-label/demo/select.ts (1)
  • Component (8-22)
libs/zard/src/lib/components/float-label/demo/status.ts (1)
  • Component (9-31)
libs/zard/src/lib/components/float-label/demo/text-area.ts (1)
  • Component (8-26)
libs/zard/src/lib/components/select/select.component.ts (1)
  • Component (38-496)
libs/zard/src/lib/shared/utils/utils.ts (1)
  • mergeClasses (4-6)
libs/zard/src/lib/components/float-label/float.label.variants.ts (1)
  • floatLabelStyles (3-66)
libs/zard/src/lib/components/input/input.directive.ts (2)
libs/zard/src/lib/components/menu/menu-item.directive.ts (1)
  • Directive (10-85)
libs/zard/src/lib/components/menu/menu-content.directive.ts (1)
  • Directive (9-21)
libs/zard/src/lib/components/float-label/demo/text-area.ts (2)
libs/zard/src/lib/components/float-label/demo/default.ts (1)
  • Component (8-26)
libs/zard/src/lib/components/float-label/float.label.component.ts (1)
  • Component (7-44)
libs/zard/src/lib/components/float-label/demo/default.ts (2)
libs/zard/src/lib/components/float-label/demo/text-area.ts (1)
  • Component (8-26)
libs/zard/src/lib/components/float-label/float.label.component.ts (1)
  • Component (7-44)
🪛 markdownlint-cli2 (0.18.1)
libs/zard/src/lib/components/float-label/doc/api.md

3-3: Files should end with a single newline character

(MD047, single-trailing-newline)

libs/zard/src/lib/components/float-label/doc/overview.md

3-3: Files should end with a single newline character

(MD047, single-trailing-newline)

🔇 Additional comments (9)
libs/zard/src/lib/components/input/demo/input.ts (1)

4-5: Import reorder is fine

Swapping the status and text-area imports does not affect behavior; the INPUT examples remain unchanged.

apps/web/prerender-routes.txt (1)

30-30: Float Label prerender route wired correctly

/docs/components/float-label matches the components route path and is placed consistently alongside other component docs routes.

apps/web/src/app/shared/constants/routes.constant.ts (1)

49-49: Component sidebar entry for Float Label is consistent

The new { name: 'Float Label', path: '/docs/components/float-label', available: true } entry aligns with the docs path and will sort correctly among other components.

libs/zard/src/lib/components/float-label/demo/input.ts (1)

1-32: FLOAT_LABEL demo metadata is coherent and wired to all variants

The FLOAT_LABEL config correctly wires the default, textarea, select, and status demo components with a consistent slug (componentName: 'float-label') and column layout, matching the new docs route.

libs/zard/src/lib/components/float-label/demo/status.ts (1)

1-31: Mark the status demo as standalone and use OnPush change detection

This demo also uses the imports array, so it must be a standalone component, and it should follow the library’s Angular best practices.

  • Blocking: Add standalone: true so Angular treats this as a standalone component; otherwise the imports config is invalid.
  • Best practice: Use ChangeDetectionStrategy.OnPush for consistency with other Zard UI components and demos.

Suggested change:

-import { Component } from '@angular/core';
+import { ChangeDetectionStrategy, Component } from '@angular/core';
@@
-@Component({
-  selector: 'z-demo-float-label-status',
-  imports: [ReactiveFormsModule, ZardInputDirective, ZardFloatLabelComponent, ZardFormLabelComponent],
+@Component({
+  standalone: true,
+  selector: 'z-demo-float-label-status',
+  changeDetection: ChangeDetectionStrategy.OnPush,
+  imports: [ReactiveFormsModule, ZardInputDirective, ZardFloatLabelComponent, ZardFormLabelComponent],
@@
 })
 export class ZardDemoFloatLabelStatusComponent {}
⛔ Skipped due to learnings
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-10-15T00:51:30.882Z
Learning: Applies to libs/zard/src/lib/components/**/*.component.ts : Use ChangeDetectionStrategy.OnPush for all Angular components
Learnt from: mikij
Repo: zard-ui/zardui PR: 299
File: libs/zard/src/lib/components/select/select.component.ts:34-38
Timestamp: 2025-10-31T10:03:18.563Z
Learning: In Angular 19+ (including Angular 20 used in this project), components are standalone by default. The `standalone: true` flag is redundant and should be omitted unless explicitly setting `standalone: false` to opt out.
Learnt from: mikij
Repo: zard-ui/zardui PR: 326
File: libs/zard/src/lib/components/input/float.label.component.ts:71-0
Timestamp: 2025-11-14T22:52:09.094Z
Learning: In libs/zard/src/lib/components/*/*.component.ts files, move HostListener and HostBinding to the Component decorator's host property instead of using decorators on class members (e.g., host: { '(input)': 'onInput()' }).
Learnt from: mikij
Repo: zard-ui/zardui PR: 318
File: libs/zard/src/lib/components/select/demo/default.ts:21-21
Timestamp: 2025-11-10T21:46:33.213Z
Learning: In demo files under libs/zard/src/lib/components/**/demo/*.ts, intentionally showing different patterns (e.g., primitive values vs signals) across different demos is valuable for demonstrating the flexibility of Angular features like two-way binding.
Learnt from: mikij
Repo: zard-ui/zardui PR: 309
File: libs/zard/src/lib/components/select/demo/multi-select.ts:23-27
Timestamp: 2025-11-04T20:46:01.373Z
Learning: In demo files under libs/zard/src/lib/components/**/demo/*.ts, console.log statements are acceptable and often intentional to demonstrate reactivity and help users understand how the component works.
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: libs/blocks/README.md:0-0
Timestamp: 2025-10-17T17:12:22.571Z
Learning: Applies to libs/blocks/src/lib/*/*.component.{ts,html} : Use ZardUI form components for validation (FormField, FormLabel, FormControl) in blocks with forms
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-10-17T19:24:10.610Z
Learning: Applies to libs/zard/src/lib/components/*/*.component.ts : Component selector should follow: 'z-[name], [z-[name]]' (element and attribute selectors)
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-10-15T00:51:30.882Z
Learning: Applies to libs/zard/src/lib/components/**/demo/**/*.ts : Place demo files under a demo/ directory (including a main demo export file, default.ts, and variant example files)
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-10-15T00:51:30.882Z
Learning: Applies to libs/zard/src/lib/components/**/*.component.ts : Provide a selector in the form 'z-[name], [z-[name]]' for each component
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-10-17T19:24:10.610Z
Learning: Applies to libs/zard/src/lib/components/*/demo/default.ts : Each component must provide a demo/default.ts exporting a DefaultExample with name, code, and lazy-loaded component
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-10-15T00:51:30.882Z
Learning: Applies to libs/zard/src/lib/components/components.ts : Export new components from libs/zard/src/lib/components/components.ts
Learnt from: CR
Repo: zard-ui/zardui PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-10-15T00:51:30.882Z
Learning: Applies to libs/zard/src/lib/components/**/*.component.ts : Use signal-based inputs via input() for component inputs (e.g., variant, size, class)
libs/zard/src/lib/components/float-label/demo/text-area.ts (1)

1-26: LGTM! Clean demo implementation.

The textarea demo follows established patterns, properly integrates reactive forms, and demonstrates error state handling with the float label component.

libs/zard/src/lib/components/float-label/float.label.variants.ts (1)

1-66: LGTM! Comprehensive CVA styling configuration.

The variants properly leverage CVA and Tailwind utilities with CSS :has() selectors to handle all float label states (focus, value, status) declaratively. This aligns perfectly with the PR objectives.

libs/zard/src/lib/components/float-label/demo/default.ts (1)

1-26: LGTM! Standard default demo pattern.

The default demo correctly demonstrates the float label component with reactive forms and validation state handling.

libs/zard/src/lib/components/float-label/float.label.spec.ts (1)

1-207: LGTM! Excellent test coverage.

The test suite comprehensively covers all component behaviors including focus/value states, SSR guards, dynamic class toggling, status styling, and event-driven updates. Well-structured and thorough.

Comment on lines +1 to +22
import { Component } from '@angular/core';

import { ZardFormLabelComponent } from '../../form/form.component';
import { ZardSelectItemComponent } from '../../select/select-item.component';
import { ZardSelectComponent } from '../../select/select.component';
import { ZardFloatLabelComponent } from '../float.label.component';

@Component({
selector: 'z-demo-float-label-select',
imports: [ZardFloatLabelComponent, ZardFormLabelComponent, ZardSelectComponent, ZardSelectItemComponent],
template: `
<z-float-label>
<z-select value="react" class="w-[200px]" zSize="lg">
<z-select-item zValue="angular">Angular</z-select-item>
<z-select-item zValue="react">React</z-select-item>
<z-select-item zValue="vue">Vue</z-select-item>
</z-select>
<label z-form-label>Framework</label>
</z-float-label>
`,
})
export class ZardDemoFloatLabelSelectComponent {}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Make the select demo a proper standalone, OnPush component and fix the initial value

Two things here:

  1. Missing standalone: true (blocking)
    You’re using the imports array on the component, which only works for standalone components. Without standalone: true, this will not compile correctly under Angular’s standalone model.

  2. Angular best practices for demos
    To keep demos aligned with the rest of the library, this component should also opt into ChangeDetectionStrategy.OnPush.

  3. Select API: use zValue instead of value
    ZardSelectComponent exposes a zValue input / CVA rather than a value input. Using value="react" won’t initialize the selected option as intended, so the demo won’t show "React" pre‑selected.

Suggested change:

-import { Component } from '@angular/core';
+import { ChangeDetectionStrategy, Component } from '@angular/core';

 @Component({
-  selector: 'z-demo-float-label-select',
-  imports: [ZardFloatLabelComponent, ZardFormLabelComponent, ZardSelectComponent, ZardSelectItemComponent],
+  standalone: true,
+  selector: 'z-demo-float-label-select',
+  changeDetection: ChangeDetectionStrategy.OnPush,
+  imports: [ZardFloatLabelComponent, ZardFormLabelComponent, ZardSelectComponent, ZardSelectItemComponent],
   template: `
     <z-float-label>
-      <z-select value="react" class="w-[200px]" zSize="lg">
+      <z-select zValue="react" class="w-[200px]" zSize="lg">
         <z-select-item zValue="angular">Angular</z-select-item>
         <z-select-item zValue="react">React</z-select-item>
         <z-select-item zValue="vue">Vue</z-select-item>
       </z-select>
       <label z-form-label>Framework</label>
     </z-float-label>
   `,
 })
 export class ZardDemoFloatLabelSelectComponent {}
🤖 Prompt for AI Agents
In libs/zard/src/lib/components/float-label/demo/select.ts around lines 1 to 22,
the component is missing standalone: true, isn’t using
ChangeDetectionStrategy.OnPush, and uses the wrong input for the select; update
the @Component decorator to include standalone: true and changeDetection:
ChangeDetectionStrategy.OnPush (importing ChangeDetectionStrategy from
@angular/core), and in the template replace value="react" on <z-select> with
zValue="react" so the select initializes correctly; keep the existing imports
array as-is for the standalone component.

Comment on lines +1 to +4
## [z-float-label] <span class="api-type-label component">Component</span>

> Wraps `input`, `textarea`, or `z-select` with a floating label.
> The label floats when the input has focus or contains a value. No newline at end of file
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

API doc looks correct; add trailing newline for markdownlint

The description of z-float-label is clear and consistent with the implementation. markdownlint reports MD047 though, so please add a single newline at the end of the file.

🧰 Tools
🪛 markdownlint-cli2 (0.18.1)

3-3: Files should end with a single newline character

(MD047, single-trailing-newline)

🤖 Prompt for AI Agents
In libs/zard/src/lib/components/float-label/doc/api.md around lines 1 to 4, the
markdown file is missing a trailing newline which triggers markdownlint MD047;
fix it by adding a single newline character at the end of the file (ensure the
file ends with exactly one newline) and save the file.

Comment on lines +1 to +3
# Float Label

A wrapper component that provides a floating label animation for form inputs. No newline at end of file
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Overview content is good; add trailing newline for markdownlint

The brief description matches the component’s purpose and the repo’s pattern for overview docs, but markdownlint flags the missing final newline (MD047). Please end the file with a single trailing newline.

🧰 Tools
🪛 markdownlint-cli2 (0.18.1)

3-3: Files should end with a single newline character

(MD047, single-trailing-newline)

🤖 Prompt for AI Agents
libs/zard/src/lib/components/float-label/doc/overview.md around lines 1 to 3:
the markdown file is missing a final newline which triggers markdownlint MD047;
simply add a single trailing newline character at the end of the file (ensure
the file ends with one blank line) and save.

Comment on lines +7 to +14
@Component({
selector: 'z-float-label',
template: `<ng-content />`,
encapsulation: ViewEncapsulation.None,
host: {
'[class]': 'classes()',
},
})
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Add ChangeDetectionStrategy.OnPush.

The component is missing ChangeDetectionStrategy.OnPush, which is required by coding guidelines for all Angular components to optimize change detection.

Apply this diff:

-import { Component, ElementRef, AfterViewInit, HostListener, PLATFORM_ID, ViewEncapsulation, computed, input, inject } from '@angular/core';
+import { Component, ElementRef, AfterViewInit, HostListener, PLATFORM_ID, ViewEncapsulation, ChangeDetectionStrategy, computed, input, inject } from '@angular/core';
 @Component({
   selector: 'z-float-label',
   template: `<ng-content />`,
   encapsulation: ViewEncapsulation.None,
+  changeDetection: ChangeDetectionStrategy.OnPush,
   host: {
     '[class]': 'classes()',
   },
 })
📝 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.

Suggested change
@Component({
selector: 'z-float-label',
template: `<ng-content />`,
encapsulation: ViewEncapsulation.None,
host: {
'[class]': 'classes()',
},
})
@Component({
selector: 'z-float-label',
template: `<ng-content />`,
encapsulation: ViewEncapsulation.None,
changeDetection: ChangeDetectionStrategy.OnPush,
host: {
'[class]': 'classes()',
},
})
🤖 Prompt for AI Agents
In libs/zard/src/lib/components/float-label/float.label.component.ts around
lines 7 to 14, the @Component decorator lacks ChangeDetectionStrategy.OnPush;
update the decorator to add changeDetection: ChangeDetectionStrategy.OnPush and
add the corresponding import from @angular/core at the top of the file (ensure
ChangeDetectionStrategy is imported alongside Component and ViewEncapsulation).
This will set the component to use OnPush change detection without changing
template or host configuration.

Comment on lines +27 to +32
@HostListener('input')
@HostListener('focus')
@HostListener('blur')
onInteraction() {
this.updateLabelState();
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Migrate @HostListener decorators to host property.

The @HostListener decorators violate project conventions. Event listeners should be declared in the component decorator's host property instead of using decorators on class members.

Based on learnings

Apply this diff:

-import { Component, ElementRef, AfterViewInit, HostListener, PLATFORM_ID, ViewEncapsulation, computed, input, inject } from '@angular/core';
+import { Component, ElementRef, AfterViewInit, PLATFORM_ID, ViewEncapsulation, computed, input, inject } from '@angular/core';
 @Component({
   selector: 'z-float-label',
   template: `<ng-content />`,
   encapsulation: ViewEncapsulation.None,
   host: {
     '[class]': 'classes()',
+    '(input)': 'onInteraction()',
+    '(focus)': 'onInteraction()',
+    '(blur)': 'onInteraction()',
   },
 })
 export class ZardFloatLabelComponent implements AfterViewInit {
   readonly class = input<string>('');

   private readonly el = inject(ElementRef);
   private readonly platformId = inject(PLATFORM_ID);

   protected readonly classes = computed(() => mergeClasses(floatLabelStyles(), this.class()));

   ngAfterViewInit() {
     this.updateLabelState();
   }

-  @HostListener('input')
-  @HostListener('focus')
-  @HostListener('blur')
   onInteraction() {
     this.updateLabelState();
   }
📝 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.

Suggested change
@HostListener('input')
@HostListener('focus')
@HostListener('blur')
onInteraction() {
this.updateLabelState();
}
onInteraction() {
this.updateLabelState();
}
🤖 Prompt for AI Agents
In libs/zard/src/lib/components/float-label/float.label.component.ts around
lines 27-32, replace the three @HostListener decorators on onInteraction() with
host bindings in the @Component decorator: add or extend the host property to
map '(input)', '(focus)', and '(blur)' to 'onInteraction()' (e.g. '(input)':
'onInteraction()', '(focus)': 'onInteraction()', '(blur)': 'onInteraction()')
and remove the @HostListener decorators from the class method so the component
uses the host metadata for event listeners.

this.updateLabelState();
}

@HostListener('input')
Copy link
Contributor

Choose a reason for hiding this comment

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

move to the component host

import { floatLabelStyles } from './float.label.variants';
import { mergeClasses } from '../../shared/utils/utils';

@Component({
Copy link
Contributor

Choose a reason for hiding this comment

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

OnPush still missing

@mikij
Copy link
Contributor

mikij commented Nov 22, 2025

Visually does not appeal quite right
image
image
image
image

@mikij mikij marked this pull request as draft February 26, 2026 19:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants