Fix failing tests
CI Pipeline / test (20) (pull_request) Successful in 2m30s
CI Pipeline / test (18) (pull_request) Successful in 3m51s
CI Pipeline / e2e (firefox) (pull_request) Successful in 3m22s
CI Pipeline / e2e (webkit) (pull_request) Successful in 3m45s
CI Pipeline / e2e (chromium) (pull_request) Successful in 11m49s
CI Pipeline / visual-regression (pull_request) Successful in 6m48s
CI Pipeline / storybook (pull_request) Successful in 1m35s
CI Pipeline / lint (pull_request) Successful in 1m12s
CI Pipeline / build (pull_request) Successful in 1m54s
CI Pipeline / performance (pull_request) Successful in 4m6s

This commit is contained in:
adilallo
2025-10-14 20:47:34 -06:00
parent c4a631a5d8
commit fa5a190416
20 changed files with 4638 additions and 1242 deletions
+1 -1
View File
@@ -160,7 +160,7 @@ const Checkbox = memo(
/>
</label>
);
}
},
);
Checkbox.displayName = "Checkbox";
+1 -1
View File
@@ -80,7 +80,7 @@ const RadioButton = ({
onChange({ checked: true, value });
}
},
[disabled, onChange, checked, value]
[disabled, onChange, checked, value],
);
return (
+1 -1
View File
@@ -24,7 +24,7 @@ const RadioGroup = ({
onChange({ value: optionValue });
}
},
[disabled, onChange]
[disabled, onChange],
);
return (
+15 -17
View File
@@ -9,10 +9,8 @@ import React, {
useCallback,
memo,
} from "react";
import ContextMenu from "./ContextMenu";
import ContextMenuItem from "./ContextMenuItem";
import ContextMenuSection from "./ContextMenuSection";
import ContextMenuDivider from "./ContextMenuDivider";
import SelectDropdown from "./SelectDropdown";
import SelectOption from "./SelectOption";
const Select = forwardRef(
(
@@ -31,7 +29,7 @@ const Select = forwardRef(
onChange,
...props
},
ref
ref,
) => {
const generatedId = useId();
const selectId = id || `select-${generatedId}`;
@@ -74,7 +72,7 @@ const Select = forwardRef(
selectRef.current.focus();
}
},
[onChange]
[onChange],
);
// Handle select button click
@@ -96,7 +94,7 @@ const Select = forwardRef(
setIsOpen(false);
}
},
[disabled, isOpen]
[disabled, isOpen],
);
const getSizeStyles = () => {
@@ -230,14 +228,14 @@ const Select = forwardRef(
// Handle options prop
if (props.options && Array.isArray(props.options)) {
const selectedOption = props.options.find(
(option) => option.value === selectedValue
(option) => option.value === selectedValue,
);
return selectedOption ? selectedOption.label : placeholder;
}
// Handle children (option elements)
const selectedOption = React.Children.toArray(children).find(
(child) => child.props.value === selectedValue
(child) => child.props.value === selectedValue,
);
return selectedOption ? selectedOption.props.children : placeholder;
};
@@ -294,10 +292,10 @@ const Select = forwardRef(
ref={menuRef}
className="absolute top-full left-0 right-0 z-50 mt-1"
>
<ContextMenu>
<SelectDropdown>
{props.options && Array.isArray(props.options)
? props.options.map((option) => (
<ContextMenuItem
<SelectOption
key={option.value}
selected={option.value === selectedValue}
size={size}
@@ -306,35 +304,35 @@ const Select = forwardRef(
}
>
{option.label}
</ContextMenuItem>
</SelectOption>
))
: React.Children.map(children, (child) => {
if (child.type === "option") {
return (
<ContextMenuItem
<SelectOption
key={child.props.value}
selected={child.props.value === selectedValue}
size={size}
onClick={() =>
handleOptionSelect(
child.props.value,
child.props.children
child.props.children,
)
}
>
{child.props.children}
</ContextMenuItem>
</SelectOption>
);
}
return child;
})}
</ContextMenu>
</SelectDropdown>
</div>
)}
</div>
</div>
);
}
},
);
Select.displayName = "Select";
+37
View File
@@ -0,0 +1,37 @@
"use client";
import React, { forwardRef, memo } from "react";
const SelectDropdown = forwardRef(
({ className = "", children, ...props }, ref) => {
const menuClasses = `
bg-black
border border-[var(--color-border-default-tertiary)]
rounded-[var(--measures-radius-medium)]
shadow-lg
p-[4px]
min-w-[200px]
max-w-[300px]
${className}
`
.trim()
.replace(/\s+/g, " ");
return (
<div
ref={ref}
className={menuClasses}
role="listbox"
aria-label="Select an option"
style={{ backgroundColor: "#000000" }}
{...props}
>
{children}
</div>
);
},
);
SelectDropdown.displayName = "SelectDropdown";
export default memo(SelectDropdown);
+111
View File
@@ -0,0 +1,111 @@
"use client";
import React, { forwardRef, memo, useCallback } from "react";
const SelectOption = forwardRef(
(
{
children,
selected = false,
disabled = false,
className = "",
onClick,
size = "medium",
...props
},
ref,
) => {
const getTextSize = () => {
switch (size) {
case "small":
return "text-[10px] leading-[14px]";
case "medium":
return "text-[14px] leading-[20px]";
case "large":
return "text-[16px] leading-[24px]";
default:
return "text-[14px] leading-[20px]";
}
};
const itemClasses = `
flex items-center justify-between
px-[8px] py-[4px]
text-[var(--color-content-default-brand-primary)]
${getTextSize()}
cursor-pointer
transition-colors duration-150
${
selected
? "bg-[var(--color-surface-default-secondary)] rounded-[var(--measures-radius-small)]"
: ""
}
${
disabled
? "opacity-50 cursor-not-allowed"
: "hover:!bg-[var(--color-surface-default-secondary)] hover:!rounded-[var(--measures-radius-small)]"
}
${className}
`
.trim()
.replace(/\s+/g, " ");
const handleClick = useCallback(
(e) => {
if (!disabled && onClick) {
onClick(e);
}
},
[disabled, onClick],
);
const handleKeyDown = useCallback(
(e) => {
if (e.key === "Enter" || e.key === " ") {
e.preventDefault();
if (!disabled && onClick) {
onClick(e);
}
}
},
[disabled, onClick],
);
return (
<div
ref={ref}
className={itemClasses}
role="option"
tabIndex={disabled ? -1 : 0}
aria-selected={selected}
aria-disabled={disabled}
onClick={handleClick}
onKeyDown={handleKeyDown}
{...props}
>
<div className="flex items-center gap-[8px]">
{selected && (
<svg
className="w-4 h-4 text-[var(--color-content-default-brand-primary)]"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d="M5 13l4 4L19 7"
/>
</svg>
)}
<span>{children}</span>
</div>
</div>
);
},
);
SelectOption.displayName = "SelectOption";
export default memo(SelectOption);
-90
View File
@@ -1,90 +0,0 @@
"use client";
import React, { useState } from "react";
import Switch from "../components/Switch";
export default function FormsPlayground() {
const [switchStates, setSwitchStates] = useState({
switch1: false,
switch2: true,
switch3: false,
switch4: true,
});
const handleSwitchChange = (switchName) => {
setSwitchStates((prev) => ({
...prev,
[switchName]: !prev[switchName],
}));
};
return (
<div className="p-[24px] space-y-[24px]">
<h1 className="font-bricolage text-[24px]">Forms Playground</h1>
<section className="space-y-[12px]">
<h2 className="font-space text-[18px]">Switch Examples</h2>
<div
className="max-w-[520px] space-y-[16px] bg-white p-6 rounded-lg border border-gray-200 shadow-lg"
//style={{ backgroundColor: "white" }}
>
<div>
<h3 className="font-space text-[14px] mb-[8px]">Switch States</h3>
<div className="space-y-4">
<Switch
checked={switchStates.switch1}
onChange={() => handleSwitchChange("switch1")}
label="Switch label"
/>
<Switch
checked={switchStates.switch2}
onChange={() => handleSwitchChange("switch2")}
label="Switch label"
/>
<Switch
checked={switchStates.switch3}
onChange={() => handleSwitchChange("switch3")}
state="focus"
label="Switch label"
/>
<Switch
checked={switchStates.switch4}
onChange={() => handleSwitchChange("switch4")}
state="focus"
label="Switch label"
/>
</div>
</div>
<div>
<h3 className="font-space text-[14px] mb-[8px]">
Interactive Example
</h3>
<div className="space-y-4">
<Switch
checked={switchStates.switch1}
onChange={() => handleSwitchChange("switch1")}
label="Enable notifications"
/>
<Switch
checked={switchStates.switch2}
onChange={() => handleSwitchChange("switch2")}
label="Auto-save documents"
/>
<Switch
checked={switchStates.switch3}
onChange={() => handleSwitchChange("switch3")}
label="Dark mode"
/>
<Switch
checked={switchStates.switch4}
onChange={() => handleSwitchChange("switch4")}
label="Email updates"
/>
</div>
</div>
</div>
</section>
</div>
);
}