redesign the homepage
Build & Deploy / Build & Push Docker Image (push) Failing after 47s
Build & Deploy / Deploy to VPS (push) Has been skipped
Test / API Unit Tests (push) Failing after 5m4s
Test / Marketplace Unit Tests (push) Failing after 4m55s
Test / Admin Unit Tests (push) Successful in 9m37s
Test / Dashboard Unit Tests (push) Successful in 9m37s
Test / API Integration Tests (push) Successful in 9m54s
Build & Deploy / Build & Push Docker Image (push) Failing after 47s
Build & Deploy / Deploy to VPS (push) Has been skipped
Test / API Unit Tests (push) Failing after 5m4s
Test / Marketplace Unit Tests (push) Failing after 4m55s
Test / Admin Unit Tests (push) Successful in 9m37s
Test / Dashboard Unit Tests (push) Successful in 9m37s
Test / API Integration Tests (push) Successful in 9m54s
This commit is contained in:
@@ -0,0 +1,93 @@
|
||||
import { BidiText } from '@/components/foundation/BidiText';
|
||||
import { classNames } from '@/lib/components/classNames';
|
||||
import {
|
||||
forwardRef,
|
||||
type InputHTMLAttributes,
|
||||
type SelectHTMLAttributes,
|
||||
type TextareaHTMLAttributes,
|
||||
} from 'react';
|
||||
import styles from './TextInput.module.css';
|
||||
|
||||
export type TextInputType = 'text' | 'email' | 'tel' | 'url' | 'search';
|
||||
|
||||
interface TextInputProps extends Omit<InputHTMLAttributes<HTMLInputElement>, 'type'> {
|
||||
type?: TextInputType;
|
||||
invalid?: boolean;
|
||||
describedBy?: string | undefined;
|
||||
bidiValue?: boolean;
|
||||
}
|
||||
|
||||
export const TextInput = forwardRef<HTMLInputElement, TextInputProps>(function TextInput(
|
||||
{ type = 'text', invalid = false, describedBy, bidiValue = false, className, ...props },
|
||||
ref,
|
||||
) {
|
||||
const dir = bidiValue || type === 'email' || type === 'tel' || type === 'url' ? 'ltr' : undefined;
|
||||
return (
|
||||
<input
|
||||
ref={ref}
|
||||
type={type}
|
||||
dir={dir}
|
||||
className={classNames(styles.control, className)}
|
||||
aria-invalid={invalid || undefined}
|
||||
aria-describedby={describedBy}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
interface TextAreaProps extends TextareaHTMLAttributes<HTMLTextAreaElement> {
|
||||
invalid?: boolean;
|
||||
describedBy?: string | undefined;
|
||||
characterCount?: { current: number; max: number; label: string };
|
||||
}
|
||||
|
||||
export function TextArea({
|
||||
invalid = false,
|
||||
describedBy,
|
||||
characterCount,
|
||||
className,
|
||||
...props
|
||||
}: TextAreaProps) {
|
||||
const countId = characterCount && props.id ? `${props.id}-count` : undefined;
|
||||
const ids = [describedBy, countId].filter(Boolean).join(' ') || undefined;
|
||||
return (
|
||||
<div className={styles.textareaGroup}>
|
||||
<textarea
|
||||
className={classNames(styles.control, styles.textarea, className)}
|
||||
aria-invalid={invalid || undefined}
|
||||
aria-describedby={ids}
|
||||
{...props}
|
||||
/>
|
||||
{characterCount ? (
|
||||
<p id={countId} className={styles.count} aria-live="polite">
|
||||
<BidiText>{`${characterCount.current}/${characterCount.max}`}</BidiText>{' '}
|
||||
{characterCount.label}
|
||||
</p>
|
||||
) : null}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
interface SelectProps extends SelectHTMLAttributes<HTMLSelectElement> {
|
||||
invalid?: boolean;
|
||||
describedBy?: string | undefined;
|
||||
}
|
||||
|
||||
export function Select({
|
||||
invalid = false,
|
||||
describedBy,
|
||||
className,
|
||||
children,
|
||||
...props
|
||||
}: SelectProps) {
|
||||
return (
|
||||
<select
|
||||
className={classNames(styles.control, styles.select, className)}
|
||||
aria-invalid={invalid || undefined}
|
||||
aria-describedby={describedBy}
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
</select>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user