App reorganization

This commit is contained in:
adilallo
2026-04-18 14:12:49 -06:00
parent f866d11ff8
commit e9dab04b34
288 changed files with 2698 additions and 5029 deletions
@@ -16,12 +16,11 @@ import React, {
import { useClickOutside } from "../../../hooks";
import { SelectInputView } from "./SelectInput.view";
import type { SelectInputProps } from "./SelectInput.types";
import {
normalizeState,
normalizeSmallMediumLargeSize,
normalizeLabelVariant,
} from "../../../../lib/propNormalization";
/**
* Figma: "Control / SelectInput" (TODO(figma)). Custom-styled select dropdown
* with a labelled trigger button and floating option menu.
*/
const SelectInputContainer = forwardRef<HTMLButtonElement, SelectInputProps>(
(
{
@@ -53,22 +52,14 @@ const SelectInputContainer = forwardRef<HTMLButtonElement, SelectInputProps>(
const shouldShowLabel =
showLabel !== undefined ? showLabel : labelText !== undefined;
// Normalize state - handle "state5" as disabled
let normalizedState = externalStateProp;
if (normalizedState === "state5" || normalizedState === "State5") {
normalizedState = "default"; // Map to default, disabled prop handles the disabled state
normalizedState = "default";
}
const externalState = normalizeState(normalizedState);
const externalState = normalizedState;
// Normalize props to handle both PascalCase (Figma) and lowercase (codebase)
// Note: labelVariant and size are normalized for future use but not yet implemented in the view
const _labelVariant = labelVariantProp
? normalizeLabelVariant(labelVariantProp)
: undefined;
const _size = sizeProp
? normalizeSmallMediumLargeSize(sizeProp)
: undefined;
// Mark as intentionally unused for future implementation
const _labelVariant = labelVariantProp;
const _size = sizeProp;
void _labelVariant;
void _size;
@@ -7,18 +7,8 @@ export interface SelectOptionData {
import type { StateValue } from "../../../../lib/propNormalization";
export type SelectInputLabelVariantValue =
| "default"
| "horizontal"
| "Default"
| "Horizontal";
export type SelectInputSizeValue =
| "small"
| "medium"
| "large"
| "Small"
| "Medium"
| "Large";
export type SelectInputLabelVariantValue = "default" | "horizontal";
export type SelectInputSizeValue = "small" | "medium" | "large";
export interface SelectInputProps {
id?: string;
@@ -33,18 +23,15 @@ export interface SelectInputProps {
*/
showLabel?: boolean;
/**
* Label variant. Accepts both lowercase and PascalCase (case-insensitive).
* Figma uses PascalCase, codebase uses lowercase - both are supported.
* Label variant.
*/
labelVariant?: SelectInputLabelVariantValue;
/**
* Select input size. Accepts both lowercase and PascalCase (case-insensitive).
* Figma uses PascalCase, codebase uses lowercase - both are supported.
* Select input size.
*/
size?: SelectInputSizeValue;
/**
* Visual state. Accepts "default"/"Default", "active"/"Active", "focus"/"Focus", "error"/"Error", "state5"/"State5" (State5 = Disabled).
* Figma uses PascalCase, codebase uses lowercase - both are supported.
* Visual state. "state5" maps to disabled.
*/
state?: StateValue | "state5" | "State5";
/**
@@ -1,7 +1,7 @@
import React, { Children, type ReactNode } from "react";
import { getAssetPath, ASSETS } from "../../../../lib/assetUtils";
import SelectDropdown from "./SelectDropdown";
import SelectOption from "./SelectOption";
import SelectOption from "../SelectOption";
import type { SelectOptionData } from "./SelectInput.types";
export interface SelectInputViewProps {
@@ -1,98 +0,0 @@
"use client";
import { forwardRef, memo, useCallback } from "react";
import { SelectOptionView } from "./SelectOption.view";
import type { SelectOptionProps } from "./SelectOption.types";
import { normalizeContextMenuItemSize } from "../../../../../lib/propNormalization";
const SelectOptionContainer = forwardRef<HTMLDivElement, SelectOptionProps>(
(
{
children,
selected = false,
disabled = false,
className = "",
onClick,
size: sizeProp = "medium",
...props
},
ref,
) => {
// Normalize props to handle both PascalCase (Figma) and lowercase (codebase)
const size = normalizeContextMenuItemSize(sizeProp);
const getTextSize = (): string => {
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: React.MouseEvent<HTMLDivElement>) => {
if (!disabled && onClick) {
onClick(e);
}
},
[disabled, onClick],
);
const handleKeyDown = useCallback(
(e: React.KeyboardEvent<HTMLDivElement>) => {
if (e.key === "Enter" || e.key === " ") {
e.preventDefault();
if (!disabled && onClick) {
onClick(e);
}
}
},
[disabled, onClick],
);
return (
<SelectOptionView
ref={ref}
selected={selected}
disabled={disabled}
className={className}
itemClasses={itemClasses}
handleClick={handleClick}
handleKeyDown={handleKeyDown}
{...props}
>
{children}
</SelectOptionView>
);
},
);
SelectOptionContainer.displayName = "SelectOption";
export default memo(SelectOptionContainer);
@@ -1,32 +0,0 @@
export type SelectOptionSizeValue =
| "small"
| "medium"
| "large"
| "Small"
| "Medium"
| "Large";
export interface SelectOptionProps {
children?: React.ReactNode;
selected?: boolean;
disabled?: boolean;
className?: string;
onClick?: (
_e: React.MouseEvent<HTMLDivElement> | React.KeyboardEvent<HTMLDivElement>,
) => void;
/**
* Select option size. Accepts both lowercase and PascalCase (case-insensitive).
* Figma uses PascalCase, codebase uses lowercase - both are supported.
*/
size?: SelectOptionSizeValue;
}
export interface SelectOptionViewProps {
children?: React.ReactNode;
selected: boolean;
disabled: boolean;
className: string;
itemClasses: string;
handleClick: (_e: React.MouseEvent<HTMLDivElement>) => void;
handleKeyDown: (_e: React.KeyboardEvent<HTMLDivElement>) => void;
}
@@ -1,55 +0,0 @@
import { forwardRef } from "react";
import type { SelectOptionViewProps } from "./SelectOption.types";
export const SelectOptionView = forwardRef<
HTMLDivElement,
SelectOptionViewProps
>(
(
{
children,
selected,
disabled,
itemClasses,
handleClick,
handleKeyDown,
...props
},
ref,
) => {
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>
);
},
);
SelectOptionView.displayName = "SelectOptionView";
@@ -1,2 +0,0 @@
export { default } from "./SelectOption.container";
export type { SelectOptionProps } from "./SelectOption.types";