Skip to content

Chore/refactors and updates #83

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 10 commits into from
Aug 11, 2025
Merged

Chore/refactors and updates #83

merged 10 commits into from
Aug 11, 2025

Conversation

tractorss
Copy link
Contributor

@tractorss tractorss commented Aug 11, 2025

Changes:

  • BigNumberField now accepts inputRef and buttonRef
  • Timeline interface exported from Timeline Component
  • Simplified item prop's type in Timeline Component
  • Added classNames to target popovers in Dropdown and DatePicker components
  • Allow custom validation of files in FileUploader by passing a validationFunction and returning a boolean value to signify the validation.

Bug fixes:

  • Hide icon when Button is in loading state
  • Avoid wrapping of DatePicker on Small screens
  • Addressed Interactive role warning in Tooltip

PR-Codex overview

This PR focuses on enhancing the functionality and usability of various components, including Timeline, Dropdown, Button, and FileUploader, while adding new features like custom validation and controlled behavior for file uploads.

Detailed summary

  • Changed TimelineItem and TimelineProps to export in custom.tsx and index.tsx.
  • Added role attribute to the div in TooltipTrigger.
  • Introduced dropdownClassName prop in DropdownCascader and DropdownSelect.
  • Improved ButtonIcon return logic for handling icon and isLoading.
  • Added FileUploaderWithCustomValidation and FileUploaderWithControlledBehaviour stories.
  • Enhanced DropdownContainer and DatePicker to accept className and popoverClassName.
  • Updated BigNumberField to accept inputRef and buttonRef.
  • Implemented custom validation logic in FileUploader for file selection.

✨ Ask PR-Codex anything about this PR by commenting with /codex {your question}

Summary by CodeRabbit

  • New Features

    • Dropdown Select/Cascader: add dropdownClassName; containers accept className for styling.
    • DatePicker: add popoverClassName; updated popover layout and scrolling.
    • FileUploader: support custom validation and controlled preselected file.
    • BigNumberField: expose refs for input and increment button.
    • Timeline: export TimelineItem and TimelineProps types.
    • Tooltip: improved accessibility with role on trigger wrapper.
  • Bug Fixes

    • ButtonIcon: custom icons hidden while loading.
  • Documentation

    • New stories: dropdown items with icons; FileUploader validation and controlled-file demos.

Copy link
Contributor

coderabbitai bot commented Aug 11, 2025

Walkthrough

Adds style-prop passthroughs for dropdowns and datepicker, ref support to BigNumberField, validation and controlled state to FileUploader, exports Timeline types, a11y role to Tooltip, icon rendering gating by isLoading in ButtonIcon, minor layout tweaks, and new Storybook stories for dropdown select icons and FileUploader behaviors.

Changes

Cohort / File(s) Summary
Button Icon Loading Gate
src/lib/button/ButtonIcon.tsx
Change rendering to suppress custom icon when isLoading (renders invisible placeholder); otherwise render provided icon or fallback Icon with existing styling. No public API change.
Cascader: dropdownClass passthrough
src/lib/dropdown/cascader/dropdown-container.tsx, src/lib/dropdown/cascader/index.tsx
Add optional className to container and dropdownClassName to cascader, pass through to Popover using cn, add Tree id="dropdown-tree". Public interface updated (IDropdownContainer.dropdownClassName / IDropdownCascader.dropdownClassName).
Select: dropdownClass passthrough
src/lib/dropdown/select/dropdown-container.tsx, src/lib/dropdown/select/index.tsx
Add optional className to container and dropdownClassName to Select, pass through to Popover using cn, add ListBox id="listbox". Public interfaces updated.
BigNumberField refs
src/lib/form/bignumber-field/index.tsx
Add inputRef?: React.Ref<HTMLInputElement> and buttonRef?: React.Ref<HTMLButtonElement> props and forward to Input and increment Button. Public props updated.
DatePicker popover layout & prop
src/lib/form/datepicker/index.tsx
Add popoverClassName?: string; change Popover overflow from overflow-y-scroll to overflow-scroll; wrap Calendar and TimeControl in a width-adjusted inner flex container. Public props updated.
FileUploader validation & controlled selectedFile
src/lib/form/file-uploader.tsx
Add validationFunction?: (file?: File)=>boolean and selectedFile?: File; initialize internal state from selectedFile and sync via useEffect; validate on drop/select and abort on failure; minor alignment class change. Public props updated.
Timeline type exports
src/lib/progress/timeline/index.tsx, src/lib/progress/timeline/custom.tsx
Export TimelineItem and TimelineProps (made public). Public API surface expanded.
Tooltip a11y role
src/lib/tooltip/index.tsx
Add role handling to trigger wrapper (role={wrapperProps?.role ?? "button"}) and spread wrapperProps. No prop type changes.
Stories: Dropdown Select item icons
src/stories/dropdown-select.stories.tsx
Add CustomItemIcon story demonstrating per-item SVG icons (Telegram SVG).
Stories: FileUploader variants
src/stories/fileuploader.stories.tsx
Add FileUploaderWithCustomValidation (validation fails) and FileUploaderWithControlledBehaviour (preselected selectedFile) stories.

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant FileUploader
  participant Validator as validationFunction
  participant Callback as onChange/callback

  User->>FileUploader: Drop/select file
  alt validationFunction provided
    FileUploader->>Validator: validate(file)
    alt valid
      FileUploader->>FileUploader: set state (fileSelected) if uncontrolled
      FileUploader-->>Callback: emit file
    else invalid
      FileUploader->>FileUploader: abort update
    end
  else no validator
    FileUploader->>FileUploader: set state (fileSelected) if uncontrolled
    FileUploader-->>Callback: emit file
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested reviewers

  • alcercu

Poem

I thump my paws on CSS plains,
New props hop in with tidy reins.
Icons hide when loaders spin,
Files get checked before they’re in.
Timelines, popovers, stories cheer—carrot commits bring spring near! 🥕✨

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch chore/refactors-and-updates

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai generate unit tests to generate unit tests for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai or @coderabbitai title anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • 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

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
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: 8

🔭 Outside diff range comments (2)
src/lib/dropdown/select/dropdown-container.tsx (1)

27-31: Use a unique id for ListBox (avoid hard-coded duplicates)

Hard-coding id="listbox" will create duplicate IDs if multiple dropdowns render. Prefer a stable unique id via React.useId, or omit id unless referenced.

-        <ListBox
-          id="listbox"
+        <ListBox
+          id={listBoxId}

Add above the return:

const listBoxId = React.useId();
src/lib/form/file-uploader.tsx (1)

24-24: Type-only nit: Omit syntax is incorrect (string literal used as a key union)

fileTriggerProps?: Omit<FileTriggerProps, "acceptedFileTypes | onSelect"> uses a single string literal as the key, so neither prop is omitted. Use a union of keys.

-  fileTriggerProps?: Omit<FileTriggerProps, "acceptedFileTypes | onSelect">;
+  fileTriggerProps?: Omit<FileTriggerProps, "acceptedFileTypes" | "onSelect">;
🧹 Nitpick comments (5)
src/lib/form/datepicker/index.tsx (2)

63-68: Prefer cn over clsx to tailwind-merge incoming popoverClassName

Using cn here will resolve conflicting Tailwind classes (e.g., widths) when consumers pass popoverClassName.

-          <Popover
-            className={clsx(
+          <Popover
+            className={cn(
               "bg-klerosUIComponentsWhiteBackground shadow-default rounded-base overflow-scroll",
               "border-klerosUIComponentsStroke ease-ease scrollbar border transition",
               time ? "w-82.5 lg:w-112.5" : "w-82.5",
               popoverClassName,
-            )}
+            )}
           >

71-77: Avoid duplicating width constraints on both Popover and inner wrapper

Width is applied to Popover and again to the inner wrapper, which can make overrides harder. Let the Popover own the width and keep the inner wrapper flexible.

-              <div
-                className={clsx("flex", time ? "w-82.5 lg:w-112.5" : "w-82.5")}
-              >
+              <div className="flex">
                 <Calendar />
                 {time && <TimeControl {...{ minValue }} />}
               </div>
src/stories/fileuploader.stories.tsx (1)

68-81: Pass the file argument to validationFunction (and minor copy nit).

Use the file param to better illustrate the API and avoid type surprises. Also tweak the copy for clarity.

-    msg: "This will not accept any file and invalidate",
+    msg: "This will mark any file as invalid.",
-    validationFunction: () => {
-      return false;
-    },
+    validationFunction: (_file) => false,
src/lib/form/bignumber-field/index.tsx (1)

20-21: Clarify ref naming and scope (optional).

buttonRef only targets the increment button; that’s ambiguous. Consider incrementButtonRef (and optionally decrementButtonRef) for clarity and completeness.

-  buttonRef?: React.Ref<HTMLButtonElement>;
+  /** Ref to the increment (up) button. */
+  incrementButtonRef?: React.Ref<HTMLButtonElement>;
+  /** Optional ref to the decrement (down) button. */
+  decrementButtonRef?: React.Ref<HTMLButtonElement>;

And update destructuring/usages accordingly.

Also applies to: 36-38

src/lib/dropdown/select/index.tsx (1)

69-71: LGTM – className passthrough unlocks targeted styling.

Passing dropdownClassName into DropdownContainer is clean and non-breaking.

Add a brief JSDoc for discoverability:

/** Extra className applied to the dropdown popover container. */
dropdownClassName?: string;
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between dde7171 and d800732.

📒 Files selected for processing (12)
  • src/lib/button/ButtonIcon.tsx (1 hunks)
  • src/lib/dropdown/cascader/dropdown-container.tsx (3 hunks)
  • src/lib/dropdown/cascader/index.tsx (3 hunks)
  • src/lib/dropdown/select/dropdown-container.tsx (1 hunks)
  • src/lib/dropdown/select/index.tsx (3 hunks)
  • src/lib/form/bignumber-field/index.tsx (4 hunks)
  • src/lib/form/datepicker/index.tsx (3 hunks)
  • src/lib/form/file-uploader.tsx (5 hunks)
  • src/lib/progress/timeline/index.tsx (1 hunks)
  • src/lib/tooltip/index.tsx (1 hunks)
  • src/stories/dropdown-select.stories.tsx (2 hunks)
  • src/stories/fileuploader.stories.tsx (1 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-06-06T12:11:44.627Z
Learnt from: tractorss
PR: kleros/ui-components-library#80
File: src/lib/draggable-list/index.tsx:69-69
Timestamp: 2025-06-06T12:11:44.627Z
Learning: In React Aria's useDragAndDrop hook with ListBox, the keys passed to the getItems function represent items currently being dragged from the ListBox. These keys are guaranteed to exist, so using getItem(key)! with non-null assertion is safe and follows the documented pattern.

Applied to files:

  • src/lib/dropdown/select/dropdown-container.tsx
🧬 Code Graph Analysis (4)
src/lib/progress/timeline/index.tsx (2)
src/lib/progress/timeline/bullet.tsx (2)
  • SideProp (7-9)
  • VariantProp (3-3)
src/lib/progress/timeline/spine.tsx (1)
  • VariantProp (7-7)
src/lib/button/ButtonIcon.tsx (1)
src/utils/index.ts (1)
  • cn (4-6)
src/lib/dropdown/cascader/dropdown-container.tsx (1)
src/utils/index.ts (1)
  • cn (4-6)
src/lib/dropdown/select/dropdown-container.tsx (2)
src/lib/dropdown/select/item.tsx (1)
  • IItem (19-23)
src/utils/index.ts (1)
  • cn (4-6)
🔇 Additional comments (7)
src/lib/dropdown/select/dropdown-container.tsx (1)

15-23: Good: className passthrough merged via cn

Merging user className into Popover with cn is correct and consistent with the PR’s pattern.

src/lib/dropdown/cascader/index.tsx (1)

61-62: Good: forwards dropdownClassName to container

Prop wiring is clear and matches other dropdown components. Enables targeted styling at the Popover/panel level.

src/lib/dropdown/cascader/dropdown-container.tsx (1)

83-91: Good: className passthrough merged via cn on Popover

Cleanly merged and consistent with Select and DatePicker patterns.

src/lib/progress/timeline/index.tsx (1)

2-2: Verify VariantProp import source

VariantProp appears to be exported from spine.tsx (not bullet.tsx). Ensure this import resolves, or switch to importing from "./spine" (or re-export it from bullet.tsx).

Suggested change if needed:

-import Bullet, { SideProp, VariantProp } from "./bullet";
+import Bullet, { SideProp } from "./bullet";
+import type { VariantProp } from "./spine";
src/lib/form/file-uploader.tsx (2)

82-84: Validation flow is clear

Validation short-circuits updates correctly before mutating state or invoking the callback. Good.

Also applies to: 95-97


124-124: Minor: message row alignment change looks fine

items-start → items-center improves vertical alignment for icon+text.

src/stories/dropdown-select.stories.tsx (1)

114-153: Story is solid; showcases per-item icons well.

Nice, concise demo. Ensure IItem includes an optional icon?: React.ReactNode to align with usage (it likely does).

If not already present, add icon?: React.ReactNode to IItem.

coderabbitai[bot]
coderabbitai bot previously approved these changes Aug 11, 2025
Copy link

Copy link

netlify bot commented Aug 11, 2025

Deploy Preview for kleros-v2-ui-storybook ready!

Name Link
🔨 Latest commit b1e282e
🔍 Latest deploy log https://app.netlify.com/projects/kleros-v2-ui-storybook/deploys/6899ef6cc4a8a10008bcb83d
😎 Deploy Preview https://deploy-preview-83--kleros-v2-ui-storybook.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

Copy link
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

🔭 Outside diff range comments (4)
src/lib/progress/timeline/custom.tsx (2)

12-15: Forwarded props are untyped and aria-label overrides consumer input

  • ICustomTimelineProps doesn’t extend DOM attributes, so ...props here is effectively empty from a typing perspective.
  • aria-label is placed after {...props}, which forces "Timeline" and prevents consumers from overriding.

Fix:

  • Extend React.OlHTMLAttributes so consumers can pass native attributes.
  • Place {...props} last so consumers can override defaults.
-interface ICustomTimelineProps {
+interface ICustomTimelineProps extends React.OlHTMLAttributes<HTMLOListElement> {
   items: [TimelineItem, ...TimelineItem[]];
   className?: string;
 }
@@
 function CustomTimeline({
   items,
   className,
   ...props
 }: Readonly<ICustomTimelineProps>) {
@@
   return (
     <ol
       className={cn("box-border flex flex-col", className)}
-      {...props}
       aria-label="Timeline"
+      {...props}
     >

Optional enhancement: if you want a default aria-label while still allowing override, compute it before render:

  • const ariaLabel = props["aria-label"] ?? "Timeline";
  • Then render aria-label={ariaLabel} and keep {...props} last.

Also applies to: 17-23, 25-29


5-10: Unify TimelineItem and strengthen CustomTimeline typings

There are now two divergent TimelineItem exports (in index.tsx and custom.tsx), which will confuse consumers and lead to broken imports. We should extract a single shared TimelineItem (including SideProp, StateProp, and VariantProp) into a new module (e.g. src/lib/progress/timeline/types.ts), update both index.tsx and custom.tsx to import it, and then tighten up the props on CustomTimeline:

• Consolidate TimelineItem into src/lib/progress/timeline/types.ts with
– party: React.ReactNode
– extends SideProp, StateProp, and VariantProp
• In both index.tsx and custom.tsx, replace the local TimelineItem with the shared one
• In custom.tsx, update ICustomTimelineProps to extend React.OlHTMLAttributes<HTMLOListElement>
• Move the spread ...props after the default aria-label so consumers can override it

Apply these local changes in src/lib/progress/timeline/custom.tsx:

--- a/src/lib/progress/timeline/custom.tsx
+++ b/src/lib/progress/timeline/custom.tsx
@@
-import React from "react";
+import React from "react";
 import Bullet, { StateProp, VariantProp } from "./bullet";
 import { cn } from "../../../utils";

-export interface TimelineItem extends VariantProp, StateProp {
+// ← Remove this local definition once you import the shared TimelineItem
 export interface TimelineItem extends VariantProp, StateProp {
   title: string;
-  party: string | React.ReactElement;
+  party: React.ReactNode;
   subtitle: string;
   Icon?: React.FC<React.SVGAttributes<SVGElement>>;
 }

-interface ICustomTimelineProps {
+interface ICustomTimelineProps extends React.OlHTMLAttributes<HTMLOListElement> {
   items: [TimelineItem, ...TimelineItem[]];
   className?: string;
 }

@@
   return (
-    <ol
-      className={cn("box-border flex flex-col", className)}
-      {...props}
-      aria-label="Timeline"
+    <ol
+      className={cn("box-border flex flex-col", className)}
+      aria-label="Timeline"
+      {...props}
     >
       {items.slice(0, -1).map((item, i) => (
         <Bullet key={i} line {...item} rightSided isLast={false} />

After extracting TimelineItem into types.ts, import it here and in index.tsx, then remove the local interface.

src/lib/form/file-uploader.tsx (2)

24-24: Fix Omit usage: you're omitting a literal string, not a union of keys

Use a union of property names so TypeScript actually omits both keys.

-  fileTriggerProps?: Omit<FileTriggerProps, "acceptedFileTypes | onSelect">;
+  fileTriggerProps?: Omit<FileTriggerProps, "acceptedFileTypes" | "onSelect">;

94-112: Propagate isDisabled to FileTrigger and Button to fully disable interactions

Currently only DropZone is disabled; file dialog can still open. Pass the flag down.

-        <FileTrigger
+        <FileTrigger
+          isDisabled={isDisabled}
           acceptedFileTypes={acceptedFileTypes}
           {...fileTriggerProps}
           onSelect={(e) => {
@@
-          <Button
+          <Button
+            isDisabled={isDisabled}
             className={clsx(
               "box-border size-full cursor-pointer bg-transparent px-2",
               "flex items-center justify-center",
             )}
           >
🧹 Nitpick comments (5)
src/lib/progress/timeline/custom.tsx (2)

2-2: Import shared types from their source to reduce coupling

VariantProp is defined in spine.tsx. Prefer importing it from there (or the new central types file), rather than via bullet.tsx. Keeps dependencies lean and avoids chained type re-exports.

-import Bullet, { StateProp, VariantProp } from "./bullet";
+import Bullet, { StateProp } from "./bullet";
+import type { VariantProp } from "./spine";

30-32: Avoid array index as a React key

If items can be reordered/inserted, using the index as key can cause reconciliation issues. Prefer a stable unique key (e.g., an id field on TimelineItem). If not available, consider using a composite derived from stable fields.

src/lib/form/file-uploader.tsx (3)

28-31: Tighten validationFunction type (param should not be optional)

You always pass a File; making the param optional weakens the contract needlessly.

-  /** Provide a custom validation function, returning false invalidates the file */
-  validationFunction?: (file?: File) => boolean;
+  /** Provide a custom validation function; returning false prevents update and callback */
+  validationFunction?: (file: File) => boolean;

86-89: DRY the validation/state/callback path across onDrop and onSelect

Both handlers duplicate the same steps. Factor into a small helper to reduce drift.

Example:

const acceptFile = (file: File) => {
  if (validationFunction && !validationFunction(file)) return;
  if (selectedFile === undefined) setFileSelected(file);
  callback(file);
};

// onDrop:
const file = await item.getFile();
acceptFile(file);

// onSelect:
const file = e[0];
acceptFile(file);

Also applies to: 100-103


65-75: Handle wildcard and extension patterns in accepted types; prefer validating after reading file

includes(item.type) won’t match "image/*" or ".png" patterns. Consider validating after getFile() using a matcher that supports MIME wildcards and extensions.

Example matcher:

function matchesAccepted(file: File, accepted?: Iterable<string>): boolean {
  if (!accepted) return true;
  const name = file.name.toLowerCase();
  const type = file.type.toLowerCase();
  for (const pat of accepted) {
    const p = pat.toLowerCase();
    if (p === type) return true;                       // exact MIME
    if (p.endsWith("/*") && type.startsWith(p.slice(0, -1))) return true; // wildcard
    if (p.startsWith(".") && name.endsWith(p)) return true; // extension
  }
  return false;
}

Then:

const item = e.items.find((i): i is FileDropItem => i.kind === "file");
if (item) {
  const file = await item.getFile();
  if (!matchesAccepted(file, acceptedFileTypes)) return;
  // continue…
}

Optionally adjust getDropOperation to return "copy" if types.has("file"), and do the stricter check after getFile().

Also applies to: 78-83

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d800732 and b1e282e.

📒 Files selected for processing (5)
  • src/lib/button/ButtonIcon.tsx (2 hunks)
  • src/lib/form/file-uploader.tsx (6 hunks)
  • src/lib/progress/timeline/custom.tsx (1 hunks)
  • src/lib/progress/timeline/index.tsx (1 hunks)
  • src/lib/tooltip/index.tsx (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • src/lib/button/ButtonIcon.tsx
  • src/lib/tooltip/index.tsx
  • src/lib/progress/timeline/index.tsx
🧰 Additional context used
🧬 Code Graph Analysis (1)
src/lib/progress/timeline/custom.tsx (3)
src/lib/progress/timeline/index.tsx (1)
  • TimelineItem (6-10)
src/lib/progress/timeline/bullet.tsx (2)
  • VariantProp (3-3)
  • StateProp (11-13)
src/lib/progress/timeline/spine.tsx (1)
  • VariantProp (7-7)
🔇 Additional comments (1)
src/lib/form/file-uploader.tsx (1)

47-54: Controlled/uncontrolled sync: LGTM and addresses prior feedback

State initializes from prop, syncs on change, and only writes when uncontrolled. This resolves the earlier review concern.

Copy link
Contributor

@alcercu alcercu left a comment

Choose a reason for hiding this comment

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

lgtm

@alcercu alcercu merged commit 74e4cf6 into main Aug 11, 2025
9 checks passed
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.

2 participants