Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/components/ui/Checkbox/stories/Checkbox.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export const Default = () => {
return (
<SandboxEditor>
<div className="flex items-center space-x-2">
<Checkbox.Root id="accept-terms" checked={checked} onCheckedChange={setChecked}>
<Checkbox.Root id="accept-terms" checked={checked} onCheckedChange={(val) => setChecked(val as boolean)}>
<Checkbox.Indicator />
</Checkbox.Root>
<label htmlFor="accept-terms" className="text-sm font-medium cursor-pointer">
Expand Down
2 changes: 1 addition & 1 deletion src/components/ui/Combobox/stories/Combobox.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import SandboxEditor from '~/components/tools/SandboxEditor/SandboxEditor';
export default {
title: 'WIP/Combobox',
component: Combobox
};
} as any;

export const Basic = () => {
return (
Expand Down
4 changes: 2 additions & 2 deletions src/components/ui/Dialog/stories/Dialog.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ const CloseIcon = () => {
export default {
title: 'WIP/Dialog',
component: Dialog,
render: (args:any) => {
render: (args: any) => {
return (
<SandboxEditor>
<Dialog.Root>
Expand Down Expand Up @@ -44,7 +44,7 @@ export default {
</SandboxEditor>
);
}
};
} as any;

// More on writing stories with args: https://storybook.js.org/docs/react/writing-stories/args
export const Default = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export default {
</div>

</SandboxEditor>
};
} as any;

export const All = {
args: {
Expand Down
2 changes: 2 additions & 0 deletions src/components/ui/Minimap/fragments/MinimapTrack.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import React from 'react';
import clsx from 'clsx';
import MinimapContext from '../context/MinimapContext';

type MinimapTrackProps = React.HTMLAttributes<HTMLDivElement>;

const MinimapTrack = ({ children, className = '', ...props }: MinimapTrackProps) => {
const { rootClass } = React.useContext(MinimapContext);
return <div className={clsx(`${rootClass}-track`, className)} {...props}>{children}</div>;
Expand Down
6 changes: 2 additions & 4 deletions src/components/ui/Minimap/fragments/MinimapWaypoint.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,8 @@ const MinimapWaypoint = ({ children, className = '', value = '', ...props }: Min
// Combined ref callback to handle both useInView and registerRef
const combinedRef = React.useCallback((node: HTMLDivElement | null) => {
// Set the ref for useInView
if (typeof ref === 'function') {
ref(node);
} else if (ref) {
ref.current = node;
if (ref && 'current' in ref) {
(ref as React.MutableRefObject<HTMLDivElement | null>).current = node;
}

// Register with provider for scrollToItem functionality
Expand Down
2 changes: 1 addition & 1 deletion src/components/ui/Minimap/stories/Minimap.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ export default {
<Minimap.Provider>
<Minimap.Root>
{steps.map((step, index) => (
<Minimap.Item key={index} value={index}>
<Minimap.Item key={index} value={index.toString()}>
<Minimap.Track>
<Minimap.Bubble>{index + 1}</Minimap.Bubble>
<Minimap.Line />
Expand Down
2 changes: 1 addition & 1 deletion src/components/ui/RadioCards/RadioCards.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,6 @@ export default {
title: 'WIP/RadioCards',
component: RadioCards,
render: () => <RadioCardsTemplate />
};
} as any;

export const All = {};
2 changes: 1 addition & 1 deletion src/components/ui/Select/stories/Select.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import SandboxEditor from '~/components/tools/SandboxEditor/SandboxEditor';
export default {
title: 'WIP/Select',
component: Select
};
} as any;

export const Basic = () => {
return (
Expand Down
6 changes: 3 additions & 3 deletions src/components/ui/Slider/stories/Slider.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ export const RangeSlider = {
<div className="w-full p-10 bg-gray-200">
<Slider.Root defaultValue={50} min={0} max={100} step={5}>
<Slider.Track>
<Slider.RangeSlider aria-label="Price range" defaultValue={[25, 75]} />
<Slider.RangeSlider aria-label="Price range" defaultValue={[25, 75] as any} />
</Slider.Track>
</Slider.Root>
</div>
Expand Down Expand Up @@ -157,7 +157,7 @@ export const PriceRangeSlider = {
<div className="w-full p-10 bg-gray-200">
<Slider.Root defaultValue={500} min={0} max={1000} step={50}>
<Slider.Track>
<Slider.RangeSlider aria-label="Price range" defaultValue={[100, 500]} />
<Slider.RangeSlider aria-label="Range slider" defaultValue={[25, 75] as any} />
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

PriceRangeSlider story uses incorrect default values

Low Severity

The PriceRangeSlider story's defaultValue was changed from [100, 500] to [25, 75], and the aria-label from "Price range" to "Range slider". Since this slider has min={0} and max={1000} with price marks at $0 through $1000, the original values representing a $100-$500 range made sense. The new values [25, 75] appear to be mistakenly copied from the basic RangeSlider story and don't represent meaningful prices in this context.

Fix in Cursor Fix in Web

<Slider.Marks
customMarks={[
{ value: 0, label: '$0' },
Expand Down Expand Up @@ -235,7 +235,7 @@ export const AllVariants = {
<h3 className="text-lg font-bold mb-4">Range Slider</h3>
<Slider.Root defaultValue={50}>
<Slider.Track>
<Slider.RangeSlider aria-label="Range slider" defaultValue={[25, 75]} />
<Slider.RangeSlider aria-label="Range slider" defaultValue={[25, 75] as any} />
</Slider.Track>
</Slider.Root>
</div>
Expand Down
6 changes: 4 additions & 2 deletions src/components/ui/Steps/fragments/StepBubble.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
'use client';
import React from 'react';
import clsx from 'clsx';
import StepsContext from '../context/StepsContext';
import { useStepsContext } from '../context/StepsContext';

type StepBubbleProps = React.HTMLAttributes<HTMLDivElement>;

const StepBubble = ({ children, className = '', ...props }: StepBubbleProps) => {
const { rootClass } = React.useContext(StepsContext);
const { rootClass } = useStepsContext();
return <div className={clsx(`${rootClass}-bubble`, className)} {...props}>{children}</div>;
};

Expand Down
6 changes: 4 additions & 2 deletions src/components/ui/Steps/fragments/StepContent.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
'use client';
import React from 'react';
import clsx from 'clsx';
import StepsContext from '../context/StepsContext';
import { useStepsContext } from '../context/StepsContext';

type StepContentProps = React.HTMLAttributes<HTMLDivElement>;

const StepContent = ({ children, className = '', ...props }: StepContentProps) => {
const { rootClass } = React.useContext(StepsContext);
const { rootClass } = useStepsContext();
return <div className={clsx(`${rootClass}-content`, className)} {...props}>{children}</div>;
};

Expand Down
4 changes: 2 additions & 2 deletions src/components/ui/Steps/fragments/StepDescription.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
'use client';
import React from 'react';
import clsx from 'clsx';
import StepsContext from '../context/StepsContext';
import { useStepsContext } from '../context/StepsContext';

type StepDescriptionProps = React.HTMLAttributes<HTMLDivElement>;

const StepDescription = ({ children, className = '', ...props }: StepDescriptionProps) => {
const { rootClass } = React.useContext(StepsContext);
const { rootClass } = useStepsContext();
return <div className={clsx(`${rootClass}-description`, className)} {...props}>{children}</div>;
};

Expand Down
6 changes: 3 additions & 3 deletions src/components/ui/Steps/fragments/StepItem.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
'use client';

import React from 'react';
import StepsContext from '../context/StepsContext';
import { useStepsContext } from '../context/StepsContext';
import clsx from 'clsx';

type StepItemProps = React.HTMLAttributes<HTMLDivElement> & {
value?: string | null;
value?: string | number | null;
};

const StepItem = ({ children, value = null, className = '', ...props }: StepItemProps) => {
const { rootClass, currentStep, setCurrentStep } = React.useContext(StepsContext);
const { rootClass, currentStep, setCurrentStep } = useStepsContext();
return <div className={clsx(`${rootClass}-item`, className)} {...props}>{children}</div>;
};
Comment on lines 11 to 14
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

Unused variables: value, currentStep, and setCurrentStep.

The component destructures currentStep and setCurrentStep from context but never uses them. Additionally, the value prop is accepted but not utilized. This appears to be incomplete implementation - typically a StepItem would use these to determine active/completed states or handle click interactions.

Suggested options

Option 1: If these are needed for future implementation, add a TODO comment:

 const StepItem = ({ children, value = null, className = '', ...props }: StepItemProps) => {
-    const { rootClass, currentStep, setCurrentStep } = useStepsContext();
+    const { rootClass } = useStepsContext();
+    // TODO: Implement step selection using value, currentStep, and setCurrentStep
     return <div className={clsx(`${rootClass}-item`, className)} {...props}>{children}</div>;
 };

Option 2: If these are intended to be used now, implement the step logic:

 const StepItem = ({ children, value = null, className = '', ...props }: StepItemProps) => {
     const { rootClass, currentStep, setCurrentStep } = useStepsContext();
-    return <div className={clsx(`${rootClass}-item`, className)} {...props}>{children}</div>;
+    const isActive = value === currentStep;
+    return (
+        <div
+            className={clsx(`${rootClass}-item`, { [`${rootClass}-item-active`]: isActive }, className)}
+            onClick={() => value !== null && setCurrentStep(value)}
+            {...props}
+        >
+            {children}
+        </div>
+    );
 };
📝 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
const StepItem = ({ children, value = null, className = '', ...props }: StepItemProps) => {
const { rootClass, currentStep, setCurrentStep } = React.useContext(StepsContext);
const { rootClass, currentStep, setCurrentStep } = useStepsContext();
return <div className={clsx(`${rootClass}-item`, className)} {...props}>{children}</div>;
};
const StepItem = ({ children, value = null, className = '', ...props }: StepItemProps) => {
const { rootClass } = useStepsContext();
// TODO: Implement step selection using value, currentStep, and setCurrentStep
return <div className={clsx(`${rootClass}-item`, className)} {...props}>{children}</div>;
};
Suggested change
const StepItem = ({ children, value = null, className = '', ...props }: StepItemProps) => {
const { rootClass, currentStep, setCurrentStep } = React.useContext(StepsContext);
const { rootClass, currentStep, setCurrentStep } = useStepsContext();
return <div className={clsx(`${rootClass}-item`, className)} {...props}>{children}</div>;
};
const StepItem = ({ children, value = null, className = '', ...props }: StepItemProps) => {
const { rootClass, currentStep, setCurrentStep } = useStepsContext();
const isActive = value === currentStep;
return (
<div
className={clsx(`${rootClass}-item`, { [`${rootClass}-item-active`]: isActive }, className)}
onClick={() => value !== null && setCurrentStep(value)}
{...props}
>
{children}
</div>
);
};
🤖 Prompt for AI Agents
In @src/components/ui/Steps/fragments/StepItem.tsx around lines 11 - 14,
StepItem currently destructures value and { currentStep, setCurrentStep } from
useStepsContext() but never uses them; either remove the unused destructuring
and the value prop from StepItemProps, or implement step behavior: use value and
currentStep to compute state (e.g., active/completed classes based on value ===
currentStep or value < currentStep) and call setCurrentStep(value) on click to
change steps; update the JSX in StepItem to apply conditional classes (using
rootClass from useStepsContext()) and an onClick that calls setCurrentStep when
value is provided, or if you intend to leave them unused for now, add a TODO
comment next to the destructuring in StepItem to prevent lint failures.


Expand Down
4 changes: 2 additions & 2 deletions src/components/ui/Steps/fragments/StepLine.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
'use client';
import React from 'react';
import clsx from 'clsx';
import StepsContext from '../context/StepsContext';
import { useStepsContext } from '../context/StepsContext';

type StepLineProps = React.HTMLAttributes<HTMLDivElement>;

const StepLine = ({ children, className = '', ...props }: StepLineProps) => {
const { rootClass } = React.useContext(StepsContext);
const { rootClass } = useStepsContext();
return <div className={clsx(`${rootClass}-line`, className)} {...props}>{children}</div>;
};

Expand Down
11 changes: 8 additions & 3 deletions src/components/ui/Steps/fragments/StepRoot.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,18 @@ import StepsContext from '../context/StepsContext';

const COMPONENT_NAME = 'Steps';

const StepsRoot = ({ children, className, customRootClass, ...props }: StepsRootProps) => {
type StepsRootProps = React.HTMLAttributes<HTMLDivElement> & {
customRootClass?: string;
orientation?: 'horizontal' | 'vertical';
};

const StepsRoot = ({ children, className, customRootClass, orientation = 'horizontal', ...props }: StepsRootProps) => {
const [currentStep, setCurrentStep] = useState(0);

const rootClass = customClassSwitcher(customRootClass, COMPONENT_NAME);

return <StepsContext.Provider value={{ currentStep, setCurrentStep, rootClass }}>
<Primitive.div className={clsx(rootClass, className)} {...props}>{children}</Primitive.div>
return <StepsContext.Provider value={{ currentStep, setCurrentStep, rootClass, orientation }}>
<Primitive.div className={clsx(rootClass, className, `${rootClass}-${orientation}`)} {...props}>{children}</Primitive.div>
</StepsContext.Provider>;
};

Expand Down
6 changes: 4 additions & 2 deletions src/components/ui/Steps/fragments/StepTitle.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
'use client';
import React from 'react';
import clsx from 'clsx';
import StepsContext from '../context/StepsContext';
import { useStepsContext } from '../context/StepsContext';

type StepTitleProps = React.HTMLAttributes<HTMLDivElement>;

const StepTitle = ({ children, className = '', ...props }: StepTitleProps) => {
const { rootClass } = React.useContext(StepsContext);
const { rootClass } = useStepsContext();
return <div className={clsx(`${rootClass}-title`, className)} {...props}>{children}</div>;
};

Expand Down
4 changes: 2 additions & 2 deletions src/components/ui/Steps/fragments/StepTrack.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
'use client';
import React from 'react';
import clsx from 'clsx';
import StepsContext from '../context/StepsContext';
import { useStepsContext } from '../context/StepsContext';

type StepTrackProps = React.HTMLAttributes<HTMLDivElement>;

const StepTrack = ({ children, className = '', ...props }: StepTrackProps) => {
const { rootClass } = React.useContext(StepsContext);
const { rootClass } = useStepsContext();
return <div className={clsx(`${rootClass}-track`, className)} {...props}>{children}</div>;
};

Expand Down
3 changes: 2 additions & 1 deletion src/core/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { customClassSwitcher } from './customClassSwitcher';
import { composeRefs, mergeProps } from './utils/mergeProps';

export { customClassSwitcher };
export { customClassSwitcher, composeRefs, mergeProps };
26 changes: 6 additions & 20 deletions src/core/primitives/Primitive/index.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import React from 'react';
import { composeRefs, mergeProps } from '../../utils/mergeProps';

// Define supported HTML elements
const SUPPORTED_HTML_ELEMENTS = ['div', 'span', 'button', 'input', 'a', 'img', 'p', 'h2', 'label'] as const;
Expand Down Expand Up @@ -33,28 +34,13 @@ const createPrimitiveComponent = (elementType: SupportedElement) => {

const child = childrenArray[0] as React.ReactElement;

// Merge refs if child already has one
// TODO: This can be made into a utility function
const mergedRef = (childRef: any) => {
if (typeof ref === 'function') ref(childRef);
else if (ref) ref.current = childRef;
const childRef = (child as any).ref;
const mergedRef = composeRefs(ref, childRef);
const mergedProps = mergeProps(elementProps, child.props);

// Access ref safely using type assertion
const childOriginalRef = (child as any).ref;
if (typeof childOriginalRef === 'function') childOriginalRef(childRef);
else if (childOriginalRef) (childOriginalRef as React.MutableRefObject<any>).current = childRef;
};

// Clone with proper type handling and proper prop merging
// We prioritize the child's props over elementProps
// TODO: Utilities for merging props and refs can be created and used here
return React.cloneElement(child, {
// Start with all the elementProps
...elementProps,
// Override with the child's own props to preserve them
...child.props,
// Only forward ref if it exists
...(ref ? { ref: mergedRef } : {})
...mergedProps,
...(mergedRef ? { ref: mergedRef } : {})
});
}

Expand Down
20 changes: 20 additions & 0 deletions src/core/primitives/Primitive/tests/Primitive.asChild.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,26 @@ describe('Primitive asChild', () => {
expect(ref.current).toBe(button);
});

test('merges className and composes event handlers for asChild', async() => {
const user = userEvent.setup();
const parentClick = jest.fn();
const childClick = jest.fn();

render(
<Primitive.button asChild className="parent-class" onClick={parentClick}>
<button className="child-class" onClick={childClick}>Trigger</button>
</Primitive.button>
);

const button = screen.getByRole('button');
await user.click(button);

expect(button).toHaveClass('parent-class');
expect(button).toHaveClass('child-class');
expect(childClick).toHaveBeenCalledTimes(1);
expect(parentClick).toHaveBeenCalledTimes(1);
});

test('supports custom child elements without warnings', () => {
const warnSpy = jest.spyOn(console, 'warn').mockImplementation(() => {});
const ref = React.createRef<HTMLAnchorElement>();
Expand Down
Loading
Loading