Skip to content

feat(ui): separate focus states for SearchForm input and button - #461

Merged
BleedingDev merged 6 commits into
masterfrom
claude/search-input-focus-states-9uwxy6
Jun 21, 2026
Merged

feat(ui): separate focus states for SearchForm input and button#461
BleedingDev merged 6 commits into
masterfrom
claude/search-input-focus-states-9uwxy6

Conversation

@Luko248

@Luko248 Luko248 commented Jun 17, 2026

Copy link
Copy Markdown
Collaborator

Summary

Reworks SearchForm so the input and button are composed as two independent controls side by side, instead of being wrapped in one bordered control with a single shared focus-within ring.

  • Separate focus states — Removed the wrapper's focus-within outline, border, background, and overflow-hidden. The input uses the Input atom's own outline-input-ring; the button uses the Button atom's own outline-button-ring. Focusing the input highlights only the input; focusing the button highlights only the button.
  • Side-by-side composition + stripped corners — They sit flush in a flex row. Using logical Tailwind radius utilities, the input gets rounded-e-none (strips right corners) and the button gets rounded-s-none (strips left corners), so the joined state reads as one unit while each keeps its own border.
  • New gapped boolean prop — When true, inserts an 8px gap between the two controls (new --spacing-search-form-gapped token aliasing --dimension-8 = 0.5rem) and restores the full rounded corners on both. Threaded through context and exposed via VariantProps, the Storybook control, a new Gapped story, and Figma Code Connect.
  • Consistent sizing — Pins the button to the shared h-form-control-{size} height for sm/md/lg so it always matches the input height (the Button atom otherwise sizes lg by padding alone, causing a height mismatch).

Files

  • libs/ui/src/molecules/search-form.tsx — component rework + gapped prop/context
  • libs/ui/src/tokens/components/molecules/_search-form.css--spacing-search-form-gapped token (8px)
  • libs/ui/stories/molecules/search-form.stories.tsxgapped control + Gapped story
  • libs/ui/src/molecules/search-form.figma.tsx — Code Connect mirrors gapped

Testing

  • biome check — clean on all changed files
  • tsc --noEmit (libs/ui) — no type errors
  • nx run ui-kit:build — succeeds, Publint passed
  • Verified the built Storybook CSS emits every relied-on utility and that values resolve correctly: gap-search-form-gapped0.5rem (8px), rounded-e-none, rounded-s-none, h-form-control-lg, and the independent outline-input-ring / outline-button-ring focus rings.
  • ⚠️ Live Chrome/visual validation was not possible in this environment — the Chrome MCP isn't available and the network policy blocks downloading a headless browser (no system Chrome present). Validation was done structurally via the generated CSS. The Gapped and Sizes Storybook stories allow visual confirmation locally.

🤖 Generated with Claude Code


Generated by Claude Code

Summary by CodeRabbit

Release Notes

  • New Features

    • Added a gapped option to SearchForm to create an 8px separation between the input and search button, with restored rounded corners when enabled.
  • Documentation

    • Updated Storybook controls and added a dedicated “Gapped” story.
    • Enhanced the component comparison view with separate cards for default vs gapped SearchForm layouts.
  • Design Tokens

    • Added a dedicated spacing token to support the SearchForm gapped variant.

Rework SearchForm so the input and button are composed side by side as two
independent controls instead of being wrapped in a single bordered control
with one shared focus-within ring.

- Drop the unified control border/background/overflow and shared
  focus-within outline. Each control now uses its own default focus ring
  (input ring on the input, button ring on the button), so focusing one
  no longer highlights the whole group.
- Strip the touching corners with logical radius utilities (input
  rounded-e-none, button rounded-s-none) so the joined state reads as one
  unit while keeping each control's own border.
- Add a `gapped` boolean prop: when true, inserts an 8px gap between the
  input and button (new --spacing-search-form-gapped token) and restores
  the full rounded corners on both controls.
- Pin the button to the shared form-control height per size so it always
  matches the input height across sm/md/lg (the Button atom sizes lg by
  padding alone).
- Update stories (gapped control + Gapped story) and Figma Code Connect.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JvsHgQRBmsL5otpYzsL2Q8
@semanticdiff-com

semanticdiff-com Bot commented Jun 17, 2026

Copy link
Copy Markdown

Review changes with  SemanticDiff

Changed Files
File Status
  libs/ui/src/molecules/search-form.figma.tsx  67% smaller
  libs/ui/src/molecules/search-form.tsx  42% smaller
  libs/ui/src/tokens/components/molecules/_search-form.css  0% smaller
  libs/ui/stories/molecules/search-form.stories.tsx  0% smaller
  libs/ui/stories/overview/component-comparison.stories.tsx Unsupported file format

@vercel

vercel Bot commented Jun 17, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
new-engine-ui-storybook Ready Ready Preview, Comment Jun 19, 2026 5:12am

@coderabbitai

coderabbitai Bot commented Jun 17, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: a3d90af4-8dc7-48d1-b57e-5f4ecb032828

📥 Commits

Reviewing files that changed from the base of the PR and between 6f9cece and dbfa8dc.

📒 Files selected for processing (2)
  • libs/ui/src/molecules/search-form.tsx
  • libs/ui/stories/overview/component-comparison.stories.tsx
📜 Recent review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: storybook-a11y / storybook-a11y
  • GitHub Check: Greptile Review
  • GitHub Check: main
  • GitHub Check: Analyze (javascript-typescript)
🧰 Additional context used
📓 Path-based instructions (5)
libs/ui/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Implement UI library components using Zag.js for React and Tailwind CSS for styling

libs/ui/**/*.{ts,tsx}: UI library must use Zag.js for React components with Tailwind CSS styling
Organize UI library components into Atoms, Molecules, and Tokens directories following atomic design pattern

Files:

  • libs/ui/stories/overview/component-comparison.stories.tsx
  • libs/ui/src/molecules/search-form.tsx
libs/ui/stories/**/*.stories.{tsx,ts}

📄 CodeRabbit inference engine (libs/ui/AGENTS.md)

libs/ui/stories/**/*.stories.{tsx,ts}: Define Storybook stories using CSF3 format with autodocs support
Use components from src/ instead of native HTML elements in Storybook stories
Use semantic and layout tokens in story className attributes instead of hardcoded Tailwind values
Define Storybook controls only for props that change appearance or behavior; exclude id, ref, internal callbacks
Order Storybook stories as: Playground, Variants (if exist), Sizes (if exist), States (if exist), Component-specific stories
Use VariantContainer and VariantGroup for visual matrices in Storybook stories
Use fn() from storybook/test for event handlers in Storybook stories

Files:

  • libs/ui/stories/overview/component-comparison.stories.tsx
libs/**

📄 CodeRabbit inference engine (AGENTS.md)

Use RSLib for building libraries in the monorepo

Files:

  • libs/ui/stories/overview/component-comparison.stories.tsx
  • libs/ui/src/molecules/search-form.tsx
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

Run Biome linting and formatting only on changed files using 'bunx biome check --write path/to/file'

Files:

  • libs/ui/stories/overview/component-comparison.stories.tsx
  • libs/ui/src/molecules/search-form.tsx
libs/ui/src/**/*.{tsx,ts}

📄 CodeRabbit inference engine (libs/ui/AGENTS.md)

libs/ui/src/**/*.{tsx,ts}: Use tv() for styling components instead of manual class concatenation
Never use forwardRef or useCallback for handlers in components (React 19 doesn't need them)
Use type for type definitions instead of interface
Never use arbitrary Tailwind values (e.g., bg-[#ff0000], p-[1rem]); use tokens instead
Never use default exports or barrel files (index.ts) unless the framework requires them
Use data attributes for state styling in Tailwind (e.g., data-disabled:..., data-[state=open]:...)
Use component-specific token classes in component implementations, not direct semantic tokens like bg-primary or text-fg
Implement compound components using Component.Subcomponent = function ... syntax instead of object exports

Files:

  • libs/ui/src/molecules/search-form.tsx
🧠 Learnings (6)
📚 Learning: 2025-12-16T19:45:17.746Z
Learnt from: BleedingDev
Repo: NMIT-WR/new-engine PR: 207
File: libs/ui/src/molecules/select.tsx:50-50
Timestamp: 2025-12-16T19:45:17.746Z
Learning: When reviewing Tailwind classes in TSX/TS files, prefer using square brackets for arbitrary CSS values and complex expressions. Specifically: - Do not use the parentheses syntax (z-(--z-index)) for anything beyond simple CSS variable references; this syntax auto-wraps in var() and cannot handle calc or complex functions. - Use the square brackets syntax (e.g., h-[calc(var(--available-height)-var(--spacing-content))]) for calc expressions, var with calc, and any complex CSS expressions. This rule applies broadly to Tailwind v4 usage in TSX code across the project.

Applied to files:

  • libs/ui/stories/overview/component-comparison.stories.tsx
  • libs/ui/src/molecules/search-form.tsx
📚 Learning: 2025-12-29T13:25:52.634Z
Learnt from: KaiUweCZE
Repo: NMIT-WR/new-engine PR: 250
File: libs/ui/src/molecules/slider.tsx:277-285
Timestamp: 2025-12-29T13:25:52.634Z
Learning: In the libs/ui project, when a child component defines a default value for a prop (for example StatusText has status = 'default'), do not override this value from the parent with a nullish coalescing operator (??) or other fallbacks. Centralize defaults in the child component (via default parameter or defaultProps) to ensure a single source of truth. Apply this pattern to TSX components under libs/ui (e.g., any files in libs/ui/src/**/*.tsx).

Applied to files:

  • libs/ui/stories/overview/component-comparison.stories.tsx
  • libs/ui/src/molecules/search-form.tsx
📚 Learning: 2026-06-12T05:11:34.288Z
Learnt from: Luko248
Repo: TechsioCZ/new-engine PR: 439
File: libs/ui/src/molecules/combobox.tsx:96-98
Timestamp: 2026-06-12T05:11:34.288Z
Learning: When reviewing Tailwind `text-*` class usage in `libs/ui` components (including `libs/ui/src/molecules/combobox.tsx`), note that `text-*` may map to Figma tokens that are intentionally namespace-ambiguous: e.g. `text-combobox-trigger` may resolve to a **font-size** token (CSS `font-size`), while `text-combobox-trigger-fg-base` may resolve to a **color** token (CSS `color`). Because they set different CSS properties, both classes may coexist on the same element without overriding each other. Do not flag these as duplicate/dead classes; instead, verify whether the referenced token is a size vs. color (and thus whether they affect `font-size` vs `color`) before raising any concern.

Applied to files:

  • libs/ui/stories/overview/component-comparison.stories.tsx
  • libs/ui/src/molecules/search-form.tsx
📚 Learning: 2026-03-26T09:04:02.783Z
Learnt from: KaiUweCZE
Repo: TechsioCZ/new-engine PR: 358
File: libs/ui/src/molecules/radio-card.tsx:337-401
Timestamp: 2026-03-26T09:04:02.783Z
Learning: In libs/ui compound components (e.g., Select/TreeView/RadioCard under libs/ui/src/molecules/), the established pattern is to implement the main component as a plain exported function and attach sub-components and metadata directly as static properties (e.g., `Select.Label = ...`, `Select.displayName = "Select"`). Do not require `Object.assign` or a typed compound-component interface for these components; if this static-property pattern is used, do not flag it as a TypeScript/type-declaration issue as long as declaration emit/type checking passes.

Applied to files:

  • libs/ui/src/molecules/search-form.tsx
📚 Learning: 2026-05-11T12:36:23.341Z
Learnt from: BleedingDev
Repo: TechsioCZ/new-engine PR: 404
File: libs/ui/src/molecules/figma/tree-view.figma.tsx:2-2
Timestamp: 2026-05-11T12:36:23.341Z
Learning: Inside the `libs/ui` library source (e.g., under `libs/ui/src/`), require component imports to use relative paths (such as `../tree-view`) instead of the `libs/ui` alias. Treat `libs/ui/...` imports as reserved for external consumers of the published library; do not flag them or suggest replacing them with relative imports when they appear in consumer code or in contexts outside the library source.

Applied to files:

  • libs/ui/src/molecules/search-form.tsx
📚 Learning: 2026-06-15T07:26:29.844Z
Learnt from: Luko248
Repo: TechsioCZ/new-engine PR: 448
File: libs/ui/src/organisms/footer.tsx:0-0
Timestamp: 2026-06-15T07:26:29.844Z
Learning: In `libs/ui` components, when using Tailwind v4 border-width utilities with a CSS variable (e.g., `--border-footer-width`, `--border-table-width`), always use the explicit `length:` hint syntax so the variable is treated as a border *width* (e.g., `border-t-(length:--border-footer-width)`, `border-b-(length:--border-table-width)`). If you use bare `(--var)` without `length:`, Tailwind v4 interprets it as a border *color* and the width will not be applied. Apply this rule to all border-width utilities: `border-t`, `border-b`, `border-l`, `border-r`, and `border`.

Applied to files:

  • libs/ui/src/molecules/search-form.tsx
🔇 Additional comments (2)
libs/ui/src/molecules/search-form.tsx (1)

37-40: LGTM!

Also applies to: 226-229

libs/ui/stories/overview/component-comparison.stories.tsx (1)

450-450: LGTM!

Also applies to: 464-464


Walkthrough

Adds a gapped boolean variant to SearchForm that visually separates the input and button with an 8px gap and restores individual rounded corners. A new --spacing-search-form-gapped CSS token is introduced, searchFormVariants gains explicit named slots, the prop is propagated via SearchFormContext to all subcomponents, clear-button portal infrastructure is implemented, and the change is reflected in Storybook and Figma Code Connect.

Changes

SearchForm gapped variant

Layer / File(s) Summary
CSS token and variant slot refactor
libs/ui/src/tokens/components/molecules/_search-form.css, libs/ui/src/molecules/search-form.tsx
Defines --spacing-search-form-gapped as var(--dimension-8), updates React imports for portal and ID generation, and refactors searchFormVariants to use explicit root, control, inputWrapper, input, button, and clearButton slots with a gapped variant toggling joined corner styling versus detached gap styling.
SearchForm component and context wiring
libs/ui/src/molecules/search-form.tsx
Adds gapped prop (default false) to SearchForm, introduces clearSlot and hasClearButton state for portal anchoring, and extends SearchFormContextValue to include gapped plus portal/layout coordination fields.
Subcomponent implementation
libs/ui/src/molecules/search-form.tsx
Control consumes gapped and passes it to searchFormVariants; Input wraps the native input in a container (portal anchor) and sets withButtonInside based on hasValue && hasClearButton; Button derives className from { size, gapped }; ClearButton toggles hasClearButton on mount, conditionally renders when both hasValue and clearSlot are present, and renders via createPortal with classes derived from { size, gapped }.
Storybook and Figma Code Connect documentation
libs/ui/stories/molecules/search-form.stories.tsx, libs/ui/stories/overview/component-comparison.stories.tsx, libs/ui/src/molecules/search-form.figma.tsx
Updates Figma Code Connect to reference a new design node and expose the gapped prop in props mapping, reorganising the example to nest subcomponents under SearchForm.Control. Adds boolean gapped argType to Storybook metadata, exports a new Gapped story demonstrating detached spacing with independent focus rings, and adds component comparison cards for both default and gapped variants across sm and md sizes.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Possibly related PRs

  • TechsioCZ/new-engine#340: Both PRs modify searchFormVariants and form-control styling in SearchForm; this PR additionally introduces the new gapped variant and clear-button portal infrastructure.
🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Title check ⚠️ Warning The title refers to 'separate focus states' but the PR's primary change is introducing a gapped variant that separates input/button with spacing and restored rounded corners; focus state refactoring is a supporting aspect, not the main objective. Consider a title like 'feat(ui): add gapped variant to SearchForm with independent focus states' to better reflect the primary addition of the gapped prop and spacing feature.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch claude/search-input-focus-states-9uwxy6
✨ Simplify code
  • Create PR with simplified code
  • Commit simplified code in branch claude/search-input-focus-states-9uwxy6

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

libs/ui/src/molecules/search-form.tsx

Oops! Something went wrong! :(

ESLint: 9.39.1

TypeError: Key "rules": Key "tailwindcss/enforces-negative-arbitrary-values": Could not find "enforces-negative-arbitrary-values" in plugin "tailwindcss".
at throwRuleNotFoundError (/node_modules/.pnpm/eslint@9.39.1_jiti@2.6.1/node_modules/eslint/lib/config/config.js:100:16)
at Config.validateRulesConfig (/node_modules/.pnpm/eslint@9.39.1_jiti@2.6.1/node_modules/eslint/lib/config/config.js:603:5)
at new Config (/node_modules/.pnpm/eslint@9.39.1_jiti@2.6.1/node_modules/eslint/lib/config/config.js:484:9)
at [finalizeConfig] (/node_modules/.pnpm/eslint@9.39.1_jiti@2.6.1/node_modules/eslint/lib/config/flat-config-array.js:212:10)
at FlatConfigArray.getConfigWithStatus (/node_modules/.pnpm/@eslint+config-array@0.21.1/node_modules/@eslint/config-array/dist/cjs/index.cjs:1409:55)
at FlatConfigArray.getConfig (/node_modules/.pnpm/@eslint+config-array@0.21.1/node_modules/@eslint/config-array/dist/cjs/index.cjs:1427:15)
at /node_modules/.pnpm/eslint@9.39.1_jiti@2.6.1/node_modules/eslint/lib/eslint/eslint.js:630:27
at Array.map ()
at lintFilesWithoutMultithreading (/node_modules/.pnpm/eslint@9.39.1_jiti@2.6.1/node_modules/eslint/lib/eslint/eslint.js:628:13)
at ESLint.lintFiles (/node_modules/.pnpm/eslint@9.39.1_jiti@2.6.1/node_modules/eslint/lib/eslint/eslint.js:1060:20)

libs/ui/stories/overview/component-comparison.stories.tsx

Oops! Something went wrong! :(

ESLint: 9.39.1

TypeError: Key "rules": Key "tailwindcss/enforces-negative-arbitrary-values": Could not find "enforces-negative-arbitrary-values" in plugin "tailwindcss".
at throwRuleNotFoundError (/node_modules/.pnpm/eslint@9.39.1_jiti@2.6.1/node_modules/eslint/lib/config/config.js:100:16)
at Config.validateRulesConfig (/node_modules/.pnpm/eslint@9.39.1_jiti@2.6.1/node_modules/eslint/lib/config/config.js:603:5)
at new Config (/node_modules/.pnpm/eslint@9.39.1_jiti@2.6.1/node_modules/eslint/lib/config/config.js:484:9)
at [finalizeConfig] (/node_modules/.pnpm/eslint@9.39.1_jiti@2.6.1/node_modules/eslint/lib/config/flat-config-array.js:212:10)
at FlatConfigArray.getConfigWithStatus (/node_modules/.pnpm/@eslint+config-array@0.21.1/node_modules/@eslint/config-array/dist/cjs/index.cjs:1409:55)
at FlatConfigArray.getConfig (/node_modules/.pnpm/@eslint+config-array@0.21.1/node_modules/@eslint/config-array/dist/cjs/index.cjs:1427:15)
at /node_modules/.pnpm/eslint@9.39.1_jiti@2.6.1/node_modules/eslint/lib/eslint/eslint.js:630:27
at Array.map ()
at lintFilesWithoutMultithreading (/node_modules/.pnpm/eslint@9.39.1_jiti@2.6.1/node_modules/eslint/lib/eslint/eslint.js:628:13)
at ESLint.lintFiles (/node_modules/.pnpm/eslint@9.39.1_jiti@2.6.1/node_modules/eslint/lib/eslint/eslint.js:1060:20)


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.

@github-actions

github-actions Bot commented Jun 17, 2026

Copy link
Copy Markdown

Storybook A11y Report

⚠️ Non-blocking mode: violations will NOT fail CI (A11Y_REPORT_FAIL_ON_VIOLATIONS=false).

Light

No a11y report JSON found for light. Storybook test-runner likely failed before reporting.

Dark

No a11y report JSON found for dark. Storybook test-runner likely failed before reporting.

@greptile-apps

greptile-apps Bot commented Jun 17, 2026

Copy link
Copy Markdown

Greptile Summary

Reworks SearchForm so the input and button are independent controls with separate focus rings, adds a gapped boolean prop for an 8px-detached layout, and repositions ClearButton as a portal inside the input wrapper.

  • Separate focus states — Removed the shared focus-within wrapper; each atom now manages its own ring via outline-input-ring / outline-button-ring, with focus-within:z-10 / focus-visible:z-10 ensuring the focused control's outline always wins the stacking order.
  • gapped prop — New --spacing-search-form-gapped token (8px), threaded through context and VariantProps, exposed in Storybook and Figma Code Connect. Default (false) strips touching corners via rounded-e-none / rounded-s-none; true restores full radius and inserts the gap.
  • Portal-based ClearButtonClearButton now renders into a slot (clearSlot) inside the inputWrapper div via createPortal, so it always appears at the input's trailing edge regardless of JSX composition order.

Confidence Score: 5/5

Safe to merge; the architectural rework is sound and all variant paths are covered.

The gapped prop, portal-based clear button, and independent focus rings are all correctly wired through context and variants. The only finding is a one-frame layout flash when the form is initialized with a non-empty value and a ClearButton is composed — a cosmetic edge-case that does not break functionality.

libs/ui/src/molecules/search-form.tsx — the useEffect / useLayoutEffect distinction for hasClearButton registration.

Important Files Changed

Filename Overview
libs/ui/src/molecules/search-form.tsx Core rework: independent focus rings, gapped prop, portal-based ClearButton. One subtle timing issue: useEffect instead of useLayoutEffect for hasClearButton registration can produce a one-frame layout flash with pre-filled values.
libs/ui/src/tokens/components/molecules/_search-form.css Adds --spacing-search-form-gapped aliasing --dimension-8 (8px). Token declaration follows @theme static pattern correctly.
libs/ui/stories/molecules/search-form.stories.tsx Adds gapped control and Gapped story with fn() event handler. Default story still uses console.log for onSubmit — unaddressed pre-existing issue.
libs/ui/src/molecules/search-form.figma.tsx Updates Figma node ID and threads gapped boolean prop through the Code Connect example. Mirrors the component API correctly.
libs/ui/stories/overview/component-comparison.stories.tsx Adds SearchForm and SearchForm (gapped) comparison cards for sm/md sizes. Straightforward addition, no issues.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    SF["SearchForm\nroot context: size, gapped, clearSlot, hasClearButton"]
    SF --> SFC["SearchForm.Control\nflex items-stretch"]
    SFC --> IW["inputWrapper div\nposition relative, flex-1\nfocus-within z-10\nref sets clearSlot"]
    SFC --> SFB["SearchForm.Button\nButton atom\nfocus-visible z-10\nh-form-control-size\ngapped false: rounded-s-none"]
    IW --> IN["SearchForm.Input\nInput atom, w-full\ngapped false: rounded-e-none\nwithButtonInside when hasClearButton and hasValue"]
    IW -.->|createPortal| CB["SearchForm.ClearButton\nabsolute inset-y-0\nend-padding-input-size"]
    CB -->|useEffect sets| HC["hasClearButton = true"]
    HC --> IN
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
    SF["SearchForm\nroot context: size, gapped, clearSlot, hasClearButton"]
    SF --> SFC["SearchForm.Control\nflex items-stretch"]
    SFC --> IW["inputWrapper div\nposition relative, flex-1\nfocus-within z-10\nref sets clearSlot"]
    SFC --> SFB["SearchForm.Button\nButton atom\nfocus-visible z-10\nh-form-control-size\ngapped false: rounded-s-none"]
    IW --> IN["SearchForm.Input\nInput atom, w-full\ngapped false: rounded-e-none\nwithButtonInside when hasClearButton and hasValue"]
    IW -.->|createPortal| CB["SearchForm.ClearButton\nabsolute inset-y-0\nend-padding-input-size"]
    CB -->|useEffect sets| HC["hasClearButton = true"]
    HC --> IN
Loading

Reviews (6): Last reviewed commit: "Merge branch 'master' into claude/search..." | Re-trigger Greptile

Comment thread libs/ui/src/molecules/search-form.tsx Outdated
Comment thread libs/ui/stories/molecules/search-form.stories.tsx Outdated
- ClearButton corners now follow the gapped variant (square when joined,
  rounded when detached) instead of being hard-coded square in the base slot
- Gapped story uses fn() for onSubmit per the Storybook style guide
- Point Code Connect at the rebuilt SearchForm Figma node
- Add SearchForm (joined + gapped) to the component-comparison overview

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
… z-index

- Clear button is now absolutely positioned inside the input at its trailing
  edge (= input padding-inline-end) via a portal into the input wrapper,
  instead of sitting as a flex sibling between the input and the button. The
  input reserves trailing padding (withButtonInside) only when a clear button
  is composed.
- Focused control now wins the stacking order (focus-within/focus-visible
  z-10 on the input wrapper and button), so the focus ring is never painted
  underneath the adjacent control.
- Drop the now-unused clearButton rounded-none joined-corner handling.
- component-comparison: SearchForm has an integrated search button, so remove
  the extra standalone Button placed next to it.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@libs/ui/stories/overview/component-comparison.stories.tsx`:
- Around line 450-451: Replace the hardcoded Tailwind width utility class w-64
with the project's semantic or layout token utility class in the bodyClassName
attributes. Update both instances where w-64 appears (in the bodyClassName at
line 450 and line 464) to use the appropriate semantic token class from the
design system instead. Consult the project's design token documentation or
existing story files to identify the correct semantic/layout token class name
that provides the equivalent width sizing.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 49cdc916-4886-408e-b255-bea615a4c9f9

📥 Commits

Reviewing files that changed from the base of the PR and between 60c1ebe and 6f9cece.

📒 Files selected for processing (2)
  • libs/ui/src/molecules/search-form.tsx
  • libs/ui/stories/overview/component-comparison.stories.tsx
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
  • GitHub Check: storybook-a11y / storybook-a11y
  • GitHub Check: Greptile Review
  • GitHub Check: main
  • GitHub Check: Analyze (javascript-typescript)
  • GitHub Check: Kilo Code Review
🧰 Additional context used
📓 Path-based instructions (5)
libs/ui/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Implement UI library components using Zag.js for React and Tailwind CSS for styling

libs/ui/**/*.{ts,tsx}: UI library must use Zag.js for React components with Tailwind CSS styling
Organize UI library components into Atoms, Molecules, and Tokens directories following atomic design pattern

Files:

  • libs/ui/stories/overview/component-comparison.stories.tsx
  • libs/ui/src/molecules/search-form.tsx
libs/ui/stories/**/*.stories.{tsx,ts}

📄 CodeRabbit inference engine (libs/ui/AGENTS.md)

libs/ui/stories/**/*.stories.{tsx,ts}: Define Storybook stories using CSF3 format with autodocs support
Use components from src/ instead of native HTML elements in Storybook stories
Use semantic and layout tokens in story className attributes instead of hardcoded Tailwind values
Define Storybook controls only for props that change appearance or behavior; exclude id, ref, internal callbacks
Order Storybook stories as: Playground, Variants (if exist), Sizes (if exist), States (if exist), Component-specific stories
Use VariantContainer and VariantGroup for visual matrices in Storybook stories
Use fn() from storybook/test for event handlers in Storybook stories

Files:

  • libs/ui/stories/overview/component-comparison.stories.tsx
libs/**

📄 CodeRabbit inference engine (AGENTS.md)

Use RSLib for building libraries in the monorepo

Files:

  • libs/ui/stories/overview/component-comparison.stories.tsx
  • libs/ui/src/molecules/search-form.tsx
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

Run Biome linting and formatting only on changed files using 'bunx biome check --write path/to/file'

Files:

  • libs/ui/stories/overview/component-comparison.stories.tsx
  • libs/ui/src/molecules/search-form.tsx
libs/ui/src/**/*.{tsx,ts}

📄 CodeRabbit inference engine (libs/ui/AGENTS.md)

libs/ui/src/**/*.{tsx,ts}: Use tv() for styling components instead of manual class concatenation
Never use forwardRef or useCallback for handlers in components (React 19 doesn't need them)
Use type for type definitions instead of interface
Never use arbitrary Tailwind values (e.g., bg-[#ff0000], p-[1rem]); use tokens instead
Never use default exports or barrel files (index.ts) unless the framework requires them
Use data attributes for state styling in Tailwind (e.g., data-disabled:..., data-[state=open]:...)
Use component-specific token classes in component implementations, not direct semantic tokens like bg-primary or text-fg
Implement compound components using Component.Subcomponent = function ... syntax instead of object exports

Files:

  • libs/ui/src/molecules/search-form.tsx
🧠 Learnings (6)
📚 Learning: 2025-12-16T19:45:17.746Z
Learnt from: BleedingDev
Repo: NMIT-WR/new-engine PR: 207
File: libs/ui/src/molecules/select.tsx:50-50
Timestamp: 2025-12-16T19:45:17.746Z
Learning: When reviewing Tailwind classes in TSX/TS files, prefer using square brackets for arbitrary CSS values and complex expressions. Specifically: - Do not use the parentheses syntax (z-(--z-index)) for anything beyond simple CSS variable references; this syntax auto-wraps in var() and cannot handle calc or complex functions. - Use the square brackets syntax (e.g., h-[calc(var(--available-height)-var(--spacing-content))]) for calc expressions, var with calc, and any complex CSS expressions. This rule applies broadly to Tailwind v4 usage in TSX code across the project.

Applied to files:

  • libs/ui/stories/overview/component-comparison.stories.tsx
  • libs/ui/src/molecules/search-form.tsx
📚 Learning: 2025-12-29T13:25:52.634Z
Learnt from: KaiUweCZE
Repo: NMIT-WR/new-engine PR: 250
File: libs/ui/src/molecules/slider.tsx:277-285
Timestamp: 2025-12-29T13:25:52.634Z
Learning: In the libs/ui project, when a child component defines a default value for a prop (for example StatusText has status = 'default'), do not override this value from the parent with a nullish coalescing operator (??) or other fallbacks. Centralize defaults in the child component (via default parameter or defaultProps) to ensure a single source of truth. Apply this pattern to TSX components under libs/ui (e.g., any files in libs/ui/src/**/*.tsx).

Applied to files:

  • libs/ui/stories/overview/component-comparison.stories.tsx
  • libs/ui/src/molecules/search-form.tsx
📚 Learning: 2026-06-12T05:11:34.288Z
Learnt from: Luko248
Repo: TechsioCZ/new-engine PR: 439
File: libs/ui/src/molecules/combobox.tsx:96-98
Timestamp: 2026-06-12T05:11:34.288Z
Learning: When reviewing Tailwind `text-*` class usage in `libs/ui` components (including `libs/ui/src/molecules/combobox.tsx`), note that `text-*` may map to Figma tokens that are intentionally namespace-ambiguous: e.g. `text-combobox-trigger` may resolve to a **font-size** token (CSS `font-size`), while `text-combobox-trigger-fg-base` may resolve to a **color** token (CSS `color`). Because they set different CSS properties, both classes may coexist on the same element without overriding each other. Do not flag these as duplicate/dead classes; instead, verify whether the referenced token is a size vs. color (and thus whether they affect `font-size` vs `color`) before raising any concern.

Applied to files:

  • libs/ui/stories/overview/component-comparison.stories.tsx
  • libs/ui/src/molecules/search-form.tsx
📚 Learning: 2026-03-26T09:04:02.783Z
Learnt from: KaiUweCZE
Repo: TechsioCZ/new-engine PR: 358
File: libs/ui/src/molecules/radio-card.tsx:337-401
Timestamp: 2026-03-26T09:04:02.783Z
Learning: In libs/ui compound components (e.g., Select/TreeView/RadioCard under libs/ui/src/molecules/), the established pattern is to implement the main component as a plain exported function and attach sub-components and metadata directly as static properties (e.g., `Select.Label = ...`, `Select.displayName = "Select"`). Do not require `Object.assign` or a typed compound-component interface for these components; if this static-property pattern is used, do not flag it as a TypeScript/type-declaration issue as long as declaration emit/type checking passes.

Applied to files:

  • libs/ui/src/molecules/search-form.tsx
📚 Learning: 2026-05-11T12:36:23.341Z
Learnt from: BleedingDev
Repo: TechsioCZ/new-engine PR: 404
File: libs/ui/src/molecules/figma/tree-view.figma.tsx:2-2
Timestamp: 2026-05-11T12:36:23.341Z
Learning: Inside the `libs/ui` library source (e.g., under `libs/ui/src/`), require component imports to use relative paths (such as `../tree-view`) instead of the `libs/ui` alias. Treat `libs/ui/...` imports as reserved for external consumers of the published library; do not flag them or suggest replacing them with relative imports when they appear in consumer code or in contexts outside the library source.

Applied to files:

  • libs/ui/src/molecules/search-form.tsx
📚 Learning: 2026-06-15T07:26:29.844Z
Learnt from: Luko248
Repo: TechsioCZ/new-engine PR: 448
File: libs/ui/src/organisms/footer.tsx:0-0
Timestamp: 2026-06-15T07:26:29.844Z
Learning: In `libs/ui` components, when using Tailwind v4 border-width utilities with a CSS variable (e.g., `--border-footer-width`, `--border-table-width`), always use the explicit `length:` hint syntax so the variable is treated as a border *width* (e.g., `border-t-(length:--border-footer-width)`, `border-b-(length:--border-table-width)`). If you use bare `(--var)` without `length:`, Tailwind v4 interprets it as a border *color* and the width will not be applied. Apply this rule to all border-width utilities: `border-t`, `border-b`, `border-l`, `border-r`, and `border`.

Applied to files:

  • libs/ui/src/molecules/search-form.tsx
🔇 Additional comments (2)
libs/ui/src/molecules/search-form.tsx (1)

8-12: LGTM!

Also applies to: 26-70, 90-97, 135-136, 168-171, 233-260, 306-341

libs/ui/stories/overview/component-comparison.stories.tsx (1)

452-459: LGTM!

Also applies to: 460-463, 466-471

Comment thread libs/ui/stories/overview/component-comparison.stories.tsx Outdated
Comment thread libs/ui/src/molecules/search-form.tsx
Comment thread libs/ui/src/molecules/search-form.tsx
Comment thread libs/ui/src/molecules/search-form.tsx
@kilo-code-bot

kilo-code-bot Bot commented Jun 18, 2026

Copy link
Copy Markdown

Code Review Summary

Status: No Issues Found | Recommendation: Merge

Files Reviewed (2 files)
  • libs/ui/src/molecules/search-form.tsx - previous warnings resolved in latest incremental diff
  • libs/ui/stories/overview/component-comparison.stories.tsx - previous warning resolved in latest incremental diff
Previous Review Summary (commit 6f9cece)

Current summary above is authoritative. Previous snapshots are kept for context only.

Previous review (commit 6f9cece)

Status: 3 Issues Found | Recommendation: Address before merge

Overview

Severity Count
CRITICAL 0
WARNING 3
SUGGESTION 0
Issue Details (click to expand)

CRITICAL

File Line Issue

WARNING

File Line Issue
libs/ui/src/molecules/search-form.tsx 38 Clear button may have an undersized hit target because clearButton has no explicit sizing/padding while the rendered button is unstyled/current-size.
libs/ui/src/molecules/search-form.tsx 67 Joined input/button will render a double border at the seam because both controls keep their own full borders after touching radii are removed.
libs/ui/src/molecules/search-form.tsx 257 Consumers can override the internal withButtonInside prop and break clear-button spacing because it is exposed and spread after the internal value.

SUGGESTION

File Line Issue
Other Observations (not in diff)

Issues found in unchanged code that cannot receive inline comments:

File Line Issue
None
Files Reviewed (5 files)
  • libs/ui/src/molecules/search-form.figma.tsx - 0 issues
  • libs/ui/src/molecules/search-form.tsx - 3 issues
  • libs/ui/src/tokens/components/molecules/_search-form.css - 0 issues
  • libs/ui/stories/molecules/search-form.stories.tsx - 0 issues
  • libs/ui/stories/overview/component-comparison.stories.tsx - 0 issues

Fix Link: Fix these issues in Kilo Cloud


Reviewed by nex-n2-pro:free · 1,645,051 tokens

- Clear button hit target now spans the full input height (inset-y-0)
  instead of collapsing to the icon size (Kilo)
- Omit the internal withButtonInside prop from SearchForm.Input's public
  props so consumers can't override the reserved clear-button padding (Kilo)
- Use token width (w-full max-w-xs) for the SearchForm comparison cards to
  match the other form-control cards (CodeRabbit)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@BleedingDev
BleedingDev merged commit 51c1c06 into master Jun 21, 2026
8 checks passed
@github-actions

Copy link
Copy Markdown

🎉 This PR is included in version 0.16.0 🎉

The release is available on:

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants