Skip to content

fix(#736): updates for doc issues found in apsara audit#756

Open
Shreyag02 wants to merge 7 commits intomainfrom
fix/doc_issues_from_apsara_audit
Open

fix(#736): updates for doc issues found in apsara audit#756
Shreyag02 wants to merge 7 commits intomainfrom
fix/doc_issues_from_apsara_audit

Conversation

@Shreyag02
Copy link
Copy Markdown
Contributor

Description

Resolves multiple documentation issues identified in the Apsara UI audit. Fixes include:

  • Fix demo container overflow clipping indicator dots and slider labels
  • Fix accordion controlled mode losing state on close/reopen
  • Fix breadcrumb demo links navigating to 404 pages
  • Add calendar month/year dropdown demo
  • Split datatable demo into virtualized/non-virtualized tabs with synced code preview
  • Add uncontrolled clear support and click-to-focus in search component
  • Expose inputRef prop in search for external access
  • Add interactive chips demo for input field with enter-to-add behavior
  • Create custom 404 page using apsara theme tokens for light/dark mode support

Type of Change

  • Bug fix (non-breaking change that fixes an issue)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected) -> might affect usage of accordion and search
  • Documentation update
  • Improvement (Improvements to existing code)

How Has This Been Tested?

  • Verified accordion controlled mode opens/closes/reopens correctly
  • Verified breadcrumb demo links no longer navigate to 404
  • Verified calendar dropdown demo renders month/year selects
  • Verified datatable tabs switch between virtualized/non-virtualized with synced code preview
  • Verified indicator dots and slider labels are no longer clipped in demo previews
  • Verified search clear button works in both controlled and uncontrolled modes
  • Verified search container click focuses the input
  • Verified input field interactive chips demo adds on Enter and removes on dismiss
  • Verified 404 page renders correctly in both light and dark themes

Checklist:

  • My code follows the style guidelines of this project
  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation (.mdx files)
  • My changes generate no new warnings
  • I have added tests that prove my fix is effective or that my feature works

Related Issues

#736

@vercel
Copy link
Copy Markdown

vercel Bot commented Apr 23, 2026

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

Project Deployment Actions Updated (UTC)
apsara Ready Ready Preview, Comment Apr 29, 2026 11:01am

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 23, 2026

Warning

Rate limit exceeded

@Shreyag02 has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 53 minutes and 56 seconds before requesting another review.

To keep reviews running without waiting, you can enable usage-based add-on for your organization. This allows additional reviews beyond the hourly cap. Account admins can enable it under billing.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 0109eafe-ecff-4470-b283-420e316989d7

📥 Commits

Reviewing files that changed from the base of the PR and between 962b26a and a39324b.

📒 Files selected for processing (3)
  • apps/www/src/components/demo/demo.tsx
  • apps/www/src/content/docs/components/datatable/demo.ts
  • apps/www/src/content/docs/components/datatable/index.mdx
📝 Walkthrough

Walkthrough

This PR adds a site-level 404 page and a new ChipInput demo component. It introduces a named DataTableVirtualizedDemo and updates datatable docs to include a virtualized preview. Demo preview components (Preview, DemoPreview, DemoPlayground) and demo types now accept an optional inline style prop and propagate it through previews; multiple docs/demo objects were updated to provide style overrides. Search now supports an external inputRef and unified controlled/uncontrolled value handling. Accordion value normalization behavior was adjusted. Several demos, CSS rules, and demo code snippets were modified or extended.

Sequence Diagram(s)

Suggested reviewers

  • rsbh
  • paanSinghCoder
  • rohanchkrabrty
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
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 (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and specifically identifies the fix as addressing documentation issues from an Apsara audit (issue #736), directly summarizing the main purpose of the changeset.
Description check ✅ Passed The description is directly related to the changeset, providing a detailed list of specific fixes and improvements (accordion state, breadcrumb links, calendar demo, datatable tabs, search component, input field chips, 404 page) that align with the changes in the raw summary.
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.


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
Review rate limit: 0/1 reviews remaining, refill in 53 minutes and 56 seconds.

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

@Shreyag02 Shreyag02 requested review from paanSinghCoder and rohanchkrabrty and removed request for rohanchkrabrty April 23, 2026 11:57
Copy link
Copy Markdown
Contributor

@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: 2

🧹 Nitpick comments (2)
apps/www/src/content/docs/components/input-field/demo.ts (1)

131-159: Consider deduplicating/guarding chip entries.

Minor UX polish for the demo: pressing Enter on an already-present label will add a duplicate chip (e.g., Tag1 twice), and very long input produces a chip that may push the layout. Not a bug, but since this demo is meant to showcase realistic usage, a small guard would make it a better reference implementation for consumers.

♻️ Suggested tweak
       onKeyDown={(e) => {
-        if (e.key === "Enter" && input.trim()) {
-          setChips([...chips, { label: input.trim() }]);
-          setInput("");
+        if (e.key === "Enter" && input.trim()) {
+          e.preventDefault();
+          const label = input.trim();
+          if (!chips.some((c) => c.label === label)) {
+            setChips([...chips, { label }]);
+          }
+          setInput("");
         }
       }}

The e.preventDefault() also avoids any accidental form submission if this demo is ever embedded inside a <form>.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/www/src/content/docs/components/input-field/demo.ts` around lines 131 -
159, In ChipInputDemo, prevent adding duplicate or excessively long chips by
enhancing the onKeyDown handler on the InputField: call e.preventDefault(),
compute const value = input.trim(), check that value is non-empty, not already
present in chips (compare against chips.map(c=>c.label)), and optionally limit
length (e.g., value.length <= MAX_LABEL_LENGTH) before calling
setChips([...chips, {label: value}]) and clearing setInput(""); update the chips
onRemove logic remains the same.
apps/www/src/app/not-found.tsx (1)

13-17: Render the 404 copy with semantic elements.

Text defaults to span, so this page lacks heading and paragraph semantics for assistive-tech navigation. Use the render prop to render the status as h1 and message as p while preserving visual styling.

Proposed semantic markup update
-      <Text size={10} weight='bold'>
+      <Text render={<h1 />} size={10} weight='bold' style={{ margin: 0 }}>
         404
       </Text>
       <div className={styles.divider} />
-      <Text size={7}>This page could not be found.</Text>
+      <Text render={<p />} size={7} style={{ margin: 0 }}>
+        This page could not be found.
+      </Text>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/www/src/app/not-found.tsx` around lines 13 - 17, The Text component is
currently rendering as a span, so update the two Text usages to use the render
prop to provide semantic elements: render the status Text (the one with
size={10} weight='bold') as an h1 and render the message Text (size={7}) as a p,
preserving their size/weight props and keeping the existing divider
(styles.divider) in place; locate the Text usages in not-found.tsx and add
render="h1" and render="p" respectively.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@apps/www/src/content/docs/components/search/demo.ts`:
- Around line 46-60: The ControlledSearch component is defined but never
rendered; after the ControlledSearch function declaration add an instance of it
(i.e., render <ControlledSearch />) so the controlled demo appears in the live
preview — locate the ControlledSearch function in the diff and append a JSX
mount of ControlledSearch right after its definition.

In `@packages/raystack/components/search/search.tsx`:
- Around line 35-36: The uncontrolled Search initializes internalValue to '' so
a passed defaultValue is ignored and both value and defaultValue get forwarded;
change the uncontrolled initialization in the Search component so internalValue
is initialized from props.defaultValue (e.g., const [internalValue,
setInternalValue] = useState(() => props.defaultValue ?? '')), keep currentValue
= isControlled ? controlledValue : internalValue, and when rendering the
underlying input only pass value when isControlled (so the uncontrolled case
only forwards defaultValue in ...props); update references to internalValue,
setInternalValue, currentValue, isControlled and controlledValue accordingly.

---

Nitpick comments:
In `@apps/www/src/app/not-found.tsx`:
- Around line 13-17: The Text component is currently rendering as a span, so
update the two Text usages to use the render prop to provide semantic elements:
render the status Text (the one with size={10} weight='bold') as an h1 and
render the message Text (size={7}) as a p, preserving their size/weight props
and keeping the existing divider (styles.divider) in place; locate the Text
usages in not-found.tsx and add render="h1" and render="p" respectively.

In `@apps/www/src/content/docs/components/input-field/demo.ts`:
- Around line 131-159: In ChipInputDemo, prevent adding duplicate or excessively
long chips by enhancing the onKeyDown handler on the InputField: call
e.preventDefault(), compute const value = input.trim(), check that value is
non-empty, not already present in chips (compare against chips.map(c=>c.label)),
and optionally limit length (e.g., value.length <= MAX_LABEL_LENGTH) before
calling setChips([...chips, {label: value}]) and clearing setInput(""); update
the chips onRemove logic remains the same.
🪄 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: CHILL

Plan: Pro

Run ID: 64524df2-bf9e-4881-9147-e69994eb7b89

📥 Commits

Reviewing files that changed from the base of the PR and between 08768b4 and 01eeb11.

📒 Files selected for processing (15)
  • apps/www/src/app/not-found.module.css
  • apps/www/src/app/not-found.tsx
  • apps/www/src/components/datatable-demo.tsx
  • apps/www/src/components/demo/demo-preview.tsx
  • apps/www/src/components/demo/demo.tsx
  • apps/www/src/components/demo/styles.module.css
  • apps/www/src/components/preview/preview.module.css
  • apps/www/src/content/docs/components/breadcrumb/demo.ts
  • apps/www/src/content/docs/components/calendar/demo.ts
  • apps/www/src/content/docs/components/datatable/demo.ts
  • apps/www/src/content/docs/components/input-field/demo.ts
  • apps/www/src/content/docs/components/input-field/index.mdx
  • apps/www/src/content/docs/components/search/demo.ts
  • packages/raystack/components/accordion/accordion-root.tsx
  • packages/raystack/components/search/search.tsx

Comment on lines +46 to +60
function ControlledSearch() {
const [value, setValue] = React.useState("Searchable text");

return (
<Flex direction="column" gap="medium" align="center">
<Search
placeholder="Type to search..."
value={value}
onChange={(e) => setValue(e.target.value)}
showClearButton
onClear={() => setValue("")}
/>
</Flex>
);
}`
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.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Description: Verify the controlled Search demo defines and renders the component.
python - <<'PY'
from pathlib import Path
p = Path("apps/www/src/content/docs/components/search/demo.ts")
s = p.read_text()
start = s.index("function ControlledSearch")
snippet = s[start:start + 700]
print(snippet)
print("\nRenders ControlledSearch:", "<ControlledSearch" in snippet)
PY

Repository: raystack/apsara

Length of output: 563


Render the controlled demo component.

The ControlledSearch function is defined but never instantiated, so the controlled demo won't display in the live preview. Add <ControlledSearch /> after the function declaration to mount it.

🐛 Proposed fix
       function ControlledSearch() {
         const [value, setValue] = React.useState("Searchable text");

         return (
           <Flex direction="column" gap="medium" align="center">
             <Search
               placeholder="Type to search..."
               value={value}
               onChange={(e) => setValue(e.target.value)}
               showClearButton
               onClear={() => setValue("")}
             />
           </Flex>
         );
-      }`
+      }
+
+      <ControlledSearch />`
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/www/src/content/docs/components/search/demo.ts` around lines 46 - 60,
The ControlledSearch component is defined but never rendered; after the
ControlledSearch function declaration add an instance of it (i.e., render
<ControlledSearch />) so the controlled demo appears in the live preview —
locate the ControlledSearch function in the diff and append a JSX mount of
ControlledSearch right after its definition.

Comment on lines +35 to +36
const [internalValue, setInternalValue] = useState('');
const currentValue = isControlled ? controlledValue : internalValue;
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.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Description: Confirm Search currently ignores defaultValue while always passing value to InputField.
rg -n -C4 'defaultValue|value=\{currentValue\}|const \[internalValue' packages/raystack/components/search/search.tsx

Repository: raystack/apsara

Length of output: 825


🏁 Script executed:

cd packages/raystack/components/search && cat -n search.tsx | head -100

Repository: raystack/apsara

Length of output: 3433


🏁 Script executed:

# Also check the SearchProps interface definition
rg -n 'interface SearchProps|type SearchProps' packages/raystack/components/search/

Repository: raystack/apsara

Length of output: 184


🏁 Script executed:

# Check InputFieldProps definition to confirm it includes defaultValue
rg -n 'interface InputFieldProps|type InputFieldProps' -A 15 packages/raystack/components/input-field/

Repository: raystack/apsara

Length of output: 1487


🏁 Script executed:

# Also verify what happens when both value and defaultValue are passed to InputField
cat -n packages/raystack/components/input-field/input-field.tsx | head -50

Repository: raystack/apsara

Length of output: 1655


🏁 Script executed:

# Check what InputPrimitive.Props includes from `@base-ui/react`
# First, let's see if there are any imports or type definitions we can examine
rg -n "InputPrimitive" packages/raystack/components/input-field/input-field.tsx -B 5 -A 5

Repository: raystack/apsara

Length of output: 1115


🏁 Script executed:

# Let's check if there are any test files or examples showing defaultValue usage
fd -e test.tsx -e test.ts -e spec.tsx packages/raystack/components/search/

Repository: raystack/apsara

Length of output: 508


🏁 Script executed:

# Check if defaultValue is used anywhere in the codebase with Search component
rg 'defaultValue' packages/raystack/components/search/ -n

Repository: raystack/apsara

Length of output: 41


🏁 Script executed:

# Also check the InputField implementation to see how it handles value and defaultValue
rg -n 'defaultValue' packages/raystack/components/input-field/input-field.tsx -C 3

Repository: raystack/apsara

Length of output: 41


🏁 Script executed:

# Check the full InputField implementation, especially how it handles props
cat -n packages/raystack/components/input-field/input-field.tsx | sed -n '40,120p'

Repository: raystack/apsara

Length of output: 2701


🏁 Script executed:

# Look for any usage examples of Search component in tests or stories
fd . packages/raystack/components/search/ -type f

Repository: raystack/apsara

Length of output: 229


🏁 Script executed:

# Check if there's a storybook or test file for Search
find packages/raystack/components/search -type f \( -name "*.stories.*" -o -name "*.test.*" -o -name "*.spec.*" \)

Repository: raystack/apsara

Length of output: 120


🏁 Script executed:

# Check the test file for Search to understand expected behavior
cat -n packages/raystack/components/search/__tests__/search.test.tsx

Repository: raystack/apsara

Length of output: 9584


Honor defaultValue in uncontrolled Search.

SearchProps accepts defaultValue through InputFieldProps, but uncontrolled state initializes to an empty string while defaultValue is forwarded via ...props. This causes <Search defaultValue="foo" /> to render with value="" and pass both value and defaultValue to the underlying input, making React treat it as controlled and ignoring the default.

🐛 Proposed fix
 export function Search({
   className,
   disabled,
   placeholder = 'Search',
   size,
   showClearButton,
   onClear,
   value: controlledValue,
   onChange,
   width = '100%',
   variant = 'default',
   inputRef: externalRef,
+  defaultValue = '',
   ...props
 }: SearchProps) {
   const internalRef = useRef<HTMLInputElement>(null);
   const inputRef = externalRef ?? internalRef;
   const isControlled = controlledValue !== undefined;
-  const [internalValue, setInternalValue] = useState('');
+  const [internalValue, setInternalValue] = useState(() =>
+    defaultValue == null ? '' : String(defaultValue)
+  );
   const currentValue = isControlled ? controlledValue : internalValue;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/raystack/components/search/search.tsx` around lines 35 - 36, The
uncontrolled Search initializes internalValue to '' so a passed defaultValue is
ignored and both value and defaultValue get forwarded; change the uncontrolled
initialization in the Search component so internalValue is initialized from
props.defaultValue (e.g., const [internalValue, setInternalValue] = useState(()
=> props.defaultValue ?? '')), keep currentValue = isControlled ?
controlledValue : internalValue, and when rendering the underlying input only
pass value when isControlled (so the uncontrolled case only forwards
defaultValue in ...props); update references to internalValue, setInternalValue,
currentValue, isControlled and controlledValue accordingly.

showClearButton?: boolean;
onClear?: () => void;
variant?: 'default' | 'borderless';
inputRef?: RefObject<HTMLInputElement | null>;
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.

I think we can just name this ref as it will be almost always known that ref will be pointing to the input field.

Moreover, lets add this in the Search docs as well.

(onValueChange as (value: string | undefined) => void)(
newValue[0] || undefined
);
(onValueChange as (value: string) => void)(newValue[0] ?? '');
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.

Why did we change newValue[0] || undefined to newValue[0] ?? ''?

Comment thread apps/www/src/content/docs/components/breadcrumb/demo.ts Outdated
Comment thread apps/www/src/app/not-found.tsx Outdated
const internalRef = useRef<HTMLInputElement>(null);
const inputRef = externalRef ?? internalRef;
const isControlled = controlledValue !== undefined;
const [internalValue, setInternalValue] = useState('');
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.

The defaultValue prop is probably getting ignored. It is inherited from InputField component. Please check this once.

Previously if the value prop is undefined it treats Search as uncontrolled and defaultValue is rendered.

Comment thread apps/www/src/components/demo/demo-preview.tsx Outdated
className={styles.container}
role='search'
style={{ width }}
onClick={() => inputRef.current?.focus()}
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.

Let's not do this as a solution to fix focus, it is very hacky. We should update the InputField where the root cause is. And we should be using absolute positioned elements for leadingIcon and trailingIcon to solve this.

Copy link
Copy Markdown
Contributor

@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: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@apps/www/src/components/demo/demo-preview.tsx`:
- Around line 47-74: The UI branches assume codePreview is a non-empty array and
directly index into codePreview[0] and codePreview[activeCodePreviewTab]; guard
against empty arrays by checking Array.isArray(codePreview) &&
codePreview.length > 0 before indexing, and render a sensible fallback (e.g.,
null/placeholder) when empty. Update the two branches that render Editor (where
code is taken from codePreview[activeTab] / codePreview[0] /
codePreview[activeCodePreviewTab]) to use a safe expression or early return when
codePreview.length === 0, ensuring Editor only receives a defined code string
and buttons map over the array only when it has items.
🪄 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: CHILL

Plan: Pro

Run ID: 0c9a66f9-898f-4f5a-b18e-9cb302b191e7

📥 Commits

Reviewing files that changed from the base of the PR and between 01eeb11 and 0411367.

📒 Files selected for processing (13)
  • apps/www/src/app/not-found.tsx
  • apps/www/src/components/demo/demo-playground.tsx
  • apps/www/src/components/demo/demo-preview.tsx
  • apps/www/src/components/demo/styles.module.css
  • apps/www/src/components/demo/types.ts
  • apps/www/src/components/preview/preview.module.css
  • apps/www/src/components/preview/preview.tsx
  • apps/www/src/content/docs/components/accordion/demo.ts
  • apps/www/src/content/docs/components/announcement-bar/demo.ts
  • apps/www/src/content/docs/components/breadcrumb/demo.ts
  • apps/www/src/content/docs/components/datatable/demo.ts
  • apps/www/src/content/docs/components/navbar/demo.ts
  • apps/www/src/content/docs/components/sidebar/demo.ts
✅ Files skipped from review due to trivial changes (6)
  • apps/www/src/components/demo/styles.module.css
  • apps/www/src/content/docs/components/announcement-bar/demo.ts
  • apps/www/src/content/docs/components/accordion/demo.ts
  • apps/www/src/app/not-found.tsx
  • apps/www/src/components/demo/types.ts
  • apps/www/src/content/docs/components/breadcrumb/demo.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • apps/www/src/components/preview/preview.module.css

Comment thread apps/www/src/components/demo/demo-preview.tsx Outdated
Copy link
Copy Markdown
Contributor

@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: 1

🧹 Nitpick comments (1)
apps/www/src/components/datatable-demo.tsx (1)

113-119: Extract duplicated literals (height, defaultSort, rowHeight) into named constants.

This avoids drift between demo variants and makes tuning easier.

♻️ Proposed refactor
+const TABLE_HEIGHT = 400;
+const DEFAULT_SORT = { name: 'email', order: 'asc' } as const;
+const VIRTUALIZED_ROW_HEIGHT = 44.5;
+
 const DataTableDemo = () => {
   const data = useMemo(() => generateData(100), []);
   return (
     <Flex direction='column' gap={4} width='full'>
-      <div style={{ height: 400 }}>
+      <div style={{ height: TABLE_HEIGHT }}>
         <DataTable
           data={data}
           mode='client'
           columns={columns}
-          defaultSort={{ name: 'email', order: 'asc' }}
+          defaultSort={DEFAULT_SORT}
         >
           <DataTable.Toolbar />
           <DataTable.Content />
@@
 const DataTableVirtualizedDemo = () => {
   const data = useMemo(() => generateData(1000), []);
@@
     <Flex direction='column' gap={4} width='full'>
-      <div style={{ height: 400 }}>
+      <div style={{ height: TABLE_HEIGHT }}>
         <DataTable
           data={data}
           mode='client'
           columns={columns}
-          defaultSort={{ name: 'email', order: 'asc' }}
+          defaultSort={DEFAULT_SORT}
         >
           <DataTable.Toolbar />
-          <DataTable.VirtualizedContent rowHeight={44.5} />
+          <DataTable.VirtualizedContent rowHeight={VIRTUALIZED_ROW_HEIGHT} />
         </DataTable>

Also applies to: 133-139, 142-142

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/www/src/components/datatable-demo.tsx` around lines 113 - 119, The
DataTable demo duplicates literals for the container height, defaultSort and
rowHeight across variants; create named constants (e.g., TABLE_HEIGHT,
DEFAULT_SORT, ROW_HEIGHT) at the top of the component and replace inline
literals in the DataTable usage and surrounding div style (references: the
<DataTable ... defaultSort=... rowHeight=... /> usage and the enclosing div
style={{ height: ... }}), then reuse those constants for the other demo blocks
mentioned to keep values consistent and easy to tune.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@apps/www/src/components/inputfield-chip-demo.tsx`:
- Around line 20-29: The add/remove handlers for chips capture the stale chips
array from render; change both setChips usages to the functional updater form to
base changes on the latest state: in the onKeyDown handler that currently does
setChips([...chips, { label: input.trim() }]) use setChips(prev => [...prev, {
label: input.trim() }]) and in the chips mapping where onRemove calls
setChips(chips.filter((_, j) => j !== i)) use setChips(prev => prev.filter((_,
j) => j !== i)); keep clearing input with setInput('') as before and ensure you
still reference input.trim() for the new label.

---

Nitpick comments:
In `@apps/www/src/components/datatable-demo.tsx`:
- Around line 113-119: The DataTable demo duplicates literals for the container
height, defaultSort and rowHeight across variants; create named constants (e.g.,
TABLE_HEIGHT, DEFAULT_SORT, ROW_HEIGHT) at the top of the component and replace
inline literals in the DataTable usage and surrounding div style (references:
the <DataTable ... defaultSort=... rowHeight=... /> usage and the enclosing div
style={{ height: ... }}), then reuse those constants for the other demo blocks
mentioned to keep values consistent and easy to tune.
🪄 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: CHILL

Plan: Pro

Run ID: 42769879-0019-4ceb-8087-3388aaca0d1e

📥 Commits

Reviewing files that changed from the base of the PR and between 87bc3c8 and 962b26a.

📒 Files selected for processing (5)
  • apps/www/src/components/datatable-demo.tsx
  • apps/www/src/components/demo/demo.tsx
  • apps/www/src/components/inputfield-chip-demo.tsx
  • apps/www/src/content/docs/components/input-field/demo.ts
  • apps/www/src/content/docs/components/input-field/index.mdx
🚧 Files skipped from review as they are similar to previous changes (3)
  • apps/www/src/content/docs/components/input-field/index.mdx
  • apps/www/src/components/demo/demo.tsx
  • apps/www/src/content/docs/components/input-field/demo.ts

Comment on lines +20 to +29
onKeyDown={e => {
if (e.key === 'Enter' && input.trim()) {
setChips([...chips, { label: input.trim() }]);
setInput('');
}
}}
chips={chips.map((c, i) => ({
label: c.label,
onRemove: () => setChips(chips.filter((_, j) => j !== i))
}))}
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.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify direct state-captured chip mutations in this component.
rg -nP --type=tsx 'setChips\(\s*\[\.\.\.chips|setChips\(\s*chips\.filter' apps/www/src/components/inputfield-chip-demo.tsx

Repository: raystack/apsara

Length of output: 87


🏁 Script executed:

cat -n apps/www/src/components/inputfield-chip-demo.tsx | head -50

Repository: raystack/apsara

Length of output: 1124


Use functional state updaters for chip add and remove operations.

Both setChips calls capture chips from the render scope rather than using the current state. Line 22 spreads the captured chips, and line 28 filters from it. Under batched updates, this can cause lost state transitions. Use functional form setChips(prev => ...) in both places.

Proposed fix
       onKeyDown={e => {
         if (e.key === 'Enter' && input.trim()) {
-          setChips([...chips, { label: input.trim() }]);
+          setChips(prev => [...prev, { label: input.trim() }]);
           setInput('');
         }
       }}
       chips={chips.map((c, i) => ({
         label: c.label,
-        onRemove: () => setChips(chips.filter((_, j) => j !== i))
+        onRemove: () => setChips(prev => prev.filter((_, j) => j !== i))
       }))}
📝 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
onKeyDown={e => {
if (e.key === 'Enter' && input.trim()) {
setChips([...chips, { label: input.trim() }]);
setInput('');
}
}}
chips={chips.map((c, i) => ({
label: c.label,
onRemove: () => setChips(chips.filter((_, j) => j !== i))
}))}
onKeyDown={e => {
if (e.key === 'Enter' && input.trim()) {
setChips(prev => [...prev, { label: input.trim() }]);
setInput('');
}
}}
chips={chips.map((c, i) => ({
label: c.label,
onRemove: () => setChips(prev => prev.filter((_, j) => j !== i))
}))}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/www/src/components/inputfield-chip-demo.tsx` around lines 20 - 29, The
add/remove handlers for chips capture the stale chips array from render; change
both setChips usages to the functional updater form to base changes on the
latest state: in the onKeyDown handler that currently does setChips([...chips, {
label: input.trim() }]) use setChips(prev => [...prev, { label: input.trim() }])
and in the chips mapping where onRemove calls setChips(chips.filter((_, j) => j
!== i)) use setChips(prev => prev.filter((_, j) => j !== i)); keep clearing
input with setInput('') as before and ensure you still reference input.trim()
for the new label.

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