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
14 changes: 4 additions & 10 deletions packages/raystack/components/image/image.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
'use client';

import { type VariantProps, cva } from 'class-variance-authority';
import { ImgHTMLAttributes } from 'react';
import { cva, type VariantProps } from 'class-variance-authority';
import { ComponentProps, SyntheticEvent } from 'react';

import styles from './image.module.css';

Expand All @@ -25,12 +25,8 @@ const image = cva(styles.image, {
}
});

interface ImageProps
extends ImgHTMLAttributes<HTMLImageElement>,
VariantProps<typeof image> {
interface ImageProps extends ComponentProps<'img'>, VariantProps<typeof image> {
fallback?: string;
width?: string | number;
height?: string | number;
}

export function Image({
Expand All @@ -47,9 +43,7 @@ export function Image({
decoding = 'async',
...props
}: ImageProps) {
const handleError = (
event: React.SyntheticEvent<HTMLImageElement, Event>
) => {
const handleError = (event: SyntheticEvent<HTMLImageElement, Event>) => {
if (fallback) {
event.currentTarget.src = fallback;
}
Expand Down
50 changes: 22 additions & 28 deletions packages/raystack/components/indicator/indicator.tsx
Original file line number Diff line number Diff line change
@@ -1,61 +1,55 @@
import { cva, VariantProps } from "class-variance-authority";
import { ComponentPropsWithoutRef, ReactNode } from "react";
import { cva, VariantProps } from 'class-variance-authority';
import { ComponentProps, ReactNode } from 'react';

import styles from './indicator.module.css';

const indicator = cva(styles.indicator, {
variants: {
variant: {
accent: styles["indicator-variant-accent"],
warning: styles["indicator-variant-warning"],
danger: styles["indicator-variant-danger"],
success: styles["indicator-variant-success"],
neutral: styles["indicator-variant-neutral"],
accent: styles['indicator-variant-accent'],
warning: styles['indicator-variant-warning'],
danger: styles['indicator-variant-danger'],
success: styles['indicator-variant-success'],
neutral: styles['indicator-variant-neutral']
}
},
defaultVariants: {
variant: "accent",
},
variant: 'accent'
}
});

export interface IndicatorProps
extends ComponentPropsWithoutRef<"div">,
extends ComponentProps<'div'>,
VariantProps<typeof indicator> {
label?: string;
children?: ReactNode;
"aria-label"?: string;
'aria-label'?: string;
}

export const Indicator = ({
className,
variant,
label,
children,
"aria-label": ariaLabel,
...props
export const Indicator = ({
className,
variant,
label,
children,
'aria-label': ariaLabel,
...props
}: IndicatorProps) => {
const accessibilityLabel = ariaLabel || label || `${variant} indicator`;

return (
<div className={styles.wrapper} {...props}>
{children}
<div
<div
className={indicator({ variant, className })}
role="status"
role='status'
aria-label={accessibilityLabel}
>
{label ? (
<span
className={styles.label}
data-length={label.length.toString()}
>
<span className={styles.label} data-length={label.length.toString()}>
{label}
</span>
) : (
<span
className={styles.dot}
aria-hidden="true"
/>
<span className={styles.dot} aria-hidden='true' />
)}
</div>
</div>
Expand Down
227 changes: 108 additions & 119 deletions packages/raystack/components/input-field/input-field.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,7 @@

import { InfoCircledIcon } from '@radix-ui/react-icons';
import { cva, cx, type VariantProps } from 'class-variance-authority';
import {
ComponentPropsWithoutRef,
forwardRef,
ReactNode,
RefObject
} from 'react';
import { ComponentProps, ReactNode, RefObject } from 'react';
import { Chip } from '../chip';
import { Tooltip } from '../tooltip';
import styles from './input-field.module.css';
Expand All @@ -32,7 +27,7 @@ const inputWrapper = cva(styles.inputWrapper, {
});

export interface InputFieldProps
extends Omit<ComponentPropsWithoutRef<'input'>, 'error' | 'size'>,
extends Omit<ComponentProps<'input'>, 'error' | 'size'>,
VariantProps<typeof inputWrapper> {
label?: string;
helperText?: string;
Expand All @@ -51,124 +46,118 @@ export interface InputFieldProps
containerRef?: RefObject<HTMLDivElement | null>;
}

export const InputField = forwardRef<HTMLInputElement, InputFieldProps>(
(
{
className,
disabled,
label,
helperText,
placeholder,
error,
leadingIcon,
trailingIcon,
optional,
prefix,
suffix,
width,
chips,
maxChipsVisible = 2,
size,
infoTooltip,
variant = 'default',
containerRef,
...props
},
ref
) => {
return (
<div className={styles.container} style={{ width: width || '100%' }}>
{label && (
<div className={styles.labelContainer}>
<label
className={cx(styles.label, disabled && styles['label-disabled'])}
>
{label}
{optional && <span className={styles.optional}>(optional)</span>}
</label>
{infoTooltip && (
<Tooltip>
<Tooltip.Trigger
render={
<span className={styles.helpIcon}>
<InfoCircledIcon />
</span>
}
/>
<Tooltip.Content side='right'>{infoTooltip}</Tooltip.Content>
</Tooltip>
)}
</div>
)}
<div
className={cx(
inputWrapper({ size, variant, className }),
error && styles['input-error-wrapper'],
disabled && styles['input-disabled-wrapper'],
chips?.length && styles['has-chips']
)}
ref={containerRef}
>
{leadingIcon && (
<div className={styles['leading-icon']}>{leadingIcon}</div>
export function InputField({
className,
disabled,
label,
helperText,
placeholder,
error,
leadingIcon,
trailingIcon,
optional,
prefix,
suffix,
width,
chips,
maxChipsVisible = 2,
size,
infoTooltip,
variant = 'default',
containerRef,
...props
}: InputFieldProps) {
return (
<div className={styles.container} style={{ width: width || '100%' }}>
{label && (
<div className={styles.labelContainer}>
<label
className={cx(styles.label, disabled && styles['label-disabled'])}
>
{label}
{optional && <span className={styles.optional}>(optional)</span>}
</label>
{infoTooltip && (
<Tooltip>
<Tooltip.Trigger
render={
<span className={styles.helpIcon}>
<InfoCircledIcon />
</span>
}
/>
<Tooltip.Content side='right'>{infoTooltip}</Tooltip.Content>
</Tooltip>
)}
{prefix && <div className={styles.prefix}>{prefix}</div>}

<div className={styles['chip-input-container']}>
{chips?.slice(0, maxChipsVisible).map((chip, index) => (
<Chip
key={index}
variant='outline'
isDismissible={!!chip.onRemove}
onDismiss={chip.onRemove}
className={styles.chip}
>
{chip.label}
</Chip>
))}
{chips && chips.length > maxChipsVisible && (
<span className={styles['chip-overflow']}>
+{chips.length - maxChipsVisible}
</span>
)}
<input
ref={ref}
className={cx(
styles['input-field'],
leadingIcon && styles['has-leading-icon'],
trailingIcon && styles['has-trailing-icon'],
prefix && styles['has-prefix'],
suffix && styles['has-suffix'],
error && styles['input-error'],
disabled && styles['input-disabled'],
className
)}
aria-invalid={!!error}
placeholder={placeholder}
disabled={disabled}
{...props}
/>
</div>
</div>
)}
<div
className={cx(
inputWrapper({ size, variant, className }),
error && styles['input-error-wrapper'],
disabled && styles['input-disabled-wrapper'],
chips?.length && styles['has-chips']
)}
ref={containerRef}
>
{leadingIcon && (
<div className={styles['leading-icon']}>{leadingIcon}</div>
)}
{prefix && <div className={styles.prefix}>{prefix}</div>}

{suffix && <div className={styles.suffix}>{suffix}</div>}
{trailingIcon && (
<div className={styles['trailing-icon']}>{trailingIcon}</div>
<div className={styles['chip-input-container']}>
{chips?.slice(0, maxChipsVisible).map((chip, index) => (
<Chip
key={index}
variant='outline'
isDismissible={!!chip.onRemove}
onDismiss={chip.onRemove}
className={styles.chip}
>
{chip.label}
</Chip>
))}
{chips && chips.length > maxChipsVisible && (
<span className={styles['chip-overflow']}>
+{chips.length - maxChipsVisible}
</span>
)}
</div>
{(error || helperText) && (
<span
<input
className={cx(
styles['helper-text'],
error && styles['helper-text-error'],
disabled && styles['helper-text-disabled']
styles['input-field'],
leadingIcon && styles['has-leading-icon'],
trailingIcon && styles['has-trailing-icon'],
prefix && styles['has-prefix'],
suffix && styles['has-suffix'],
error && styles['input-error'],
disabled && styles['input-disabled'],
className
)}
>
{error || helperText}
</span>
aria-invalid={!!error}
placeholder={placeholder}
disabled={disabled}
{...props}
/>
</div>

{suffix && <div className={styles.suffix}>{suffix}</div>}
{trailingIcon && (
<div className={styles['trailing-icon']}>{trailingIcon}</div>
)}
</div>
);
}
);
{(error || helperText) && (
<span
className={cx(
styles['helper-text'],
error && styles['helper-text-error'],
disabled && styles['helper-text-disabled']
)}
>
{error || helperText}
</span>
)}
</div>
);
}

InputField.displayName = 'InputField';
Loading
Loading