ESLINT is holy crap

This commit is contained in:
2024-02-01 01:58:19 +04:00
parent 7cdc259fb3
commit 26584d5482
151 changed files with 26811 additions and 47 deletions

View File

@@ -0,0 +1,37 @@
import { BadgeProps } from './badges.types';
import { bool, number, string } from 'prop-types';
import React, { forwardRef } from 'react';
const Badge = forwardRef<SVGSVGElement, BadgeProps>(function Badge(
{ disableValue = false, ...props },
ref,
) {
const digitLength = props.children
? 16 + (props.children.length - 1) * 6
: 6,
disableValueClassName =
disableValue || (!props.children ?? true) ? 'disable-value' : '';
return (
<svg
{...props}
className={`m3 m3-badge ${'' ?? props.className}${disableValueClassName}`.trimEnd()}
ref={ref}
width={`${digitLength}px`}
>
{props.children && (
<text x={'50%'} y={'50%'}>
{props.children}
</text>
)}
</svg>
);
});
Badge.propTypes = {
children: number,
className: string,
disableValue: bool,
};
export { Badge };

View File

@@ -0,0 +1,5 @@
import { PropsWithChildren } from 'react';
export interface BadgeProps extends PropsWithChildren<any> {
disableValue?: boolean;
}

View File

@@ -0,0 +1,48 @@
'use client';
import { RippleArea } from '../ripple/ripple-area';
import { IRippleProps } from '../ripple/ripple.types';
import useRippleEffect from '../ripple/hooks/useRippleEffect';
import React, {
forwardRef,
PropsWithChildren,
useId,
useRef,
useState,
} from 'react';
const ButtonLayout = forwardRef<
HTMLButtonElement,
PropsWithChildren<any> & IRippleProps
>(function ButtonBase({ centralRipple = false, ...props }, ref) {
const [isActive, setIsActive] = useState<boolean>(false),
ripplesRef = useRef(null),
buttonId = useId(),
events = useRippleEffect(ripplesRef, setIsActive);
const { variant, disabled, className } = props;
const classes = className
? `m3 ${className} ${variant}${isActive ? ' is-active' : ''}`
: `m3 ${variant}${isActive ? ' is-active' : ''}`;
return (
<button
{...props}
{...events}
className={classes}
disabled={disabled}
id={buttonId}
ref={ref}
>
{props.children}
<RippleArea
callback={setIsActive}
central={centralRipple}
ref={ripplesRef}
/>
</button>
);
});
export { ButtonLayout };

View File

@@ -0,0 +1,25 @@
import { PropsWithChildren } from 'react';
type ToggleButtonType = {
selected: string;
unselected: string;
};
export interface ButtonMainProps extends PropsWithChildren<any> {
disabled?: boolean;
variant?: 'filled' | 'outlined' | 'elevated' | 'tonal' | 'text';
}
export interface FABMainProps extends PropsWithChildren<any> {
icon: string;
disabled?: boolean;
size?: 'small' | 'default' | 'large' | 'extended';
variant?: 'surface' | 'primary' | 'secondary' | 'tertiary';
}
export interface IconButtonMainProps extends PropsWithChildren<any> {
icon: string;
toggled?: false | ToggleButtonType;
disabled?: boolean;
variant?: 'default' | 'filled' | 'tonal' | 'outlined';
}

View File

@@ -0,0 +1,33 @@
'use client';
import { forwardRef } from 'react';
import { Icon } from '../material-you-components';
import { IRippleProps } from '../ripple/ripple.types';
import { ButtonLayout } from '../button-layout/button-layout';
import { ButtonMainProps } from '../button-layout/button.types';
/**
* Button component
** description
*/
export const Button = forwardRef<
HTMLButtonElement,
ButtonMainProps & IRippleProps
>(
(
{ centralRipple = false, variant, disabled = false, icon, ...props },
ref,
) => (
<ButtonLayout
{...props}
centralRipple={centralRipple}
disabled={disabled}
ref={ref}
variant={variant ? variant : 'filled'}
>
{icon ? <Icon iconSize={20}>{icon}</Icon> : <></>}
<span className={'label-large'}>{props.children}</span>
</ButtonLayout>
),
);

View File

@@ -0,0 +1,38 @@
'use client';
import React, {
forwardRef,
useEffect,
useImperativeHandle,
useRef,
} from 'react';
import { CheckboxLayoutProps } from './checkbox-layout.types';
export const CheckBoxLayout = forwardRef(function CheckBoxBase(
{ indeterminate, typeInput, type, ...props }: CheckboxLayoutProps,
ref,
): JSX.Element {
const checkboxRef = useRef<any>(null);
useEffect(() => {
checkboxRef.current.indeterminate = indeterminate === true;
}, []);
useImperativeHandle(ref, () => checkboxRef.current);
const classesType = typeInput || type;
const classes =
props.className !== undefined
? `m3 m3-${type} ${props.className}`
: `m3 m3-${classesType}`;
return (
<input
ref={checkboxRef}
{...props}
className={classes.trimEnd()}
type={type}
/>
);
});

View File

@@ -0,0 +1,7 @@
import { PropsWithChildren } from 'react';
export interface CheckboxLayoutProps extends PropsWithChildren<any> {
indeterminate?: boolean;
typeInput?: string;
type?: string;
}

View File

@@ -0,0 +1,59 @@
'use client';
import { RippleArea } from '../ripple/ripple-area';
import { IRippleProps } from '../ripple/ripple.types';
import useRippleEffect from '../ripple/hooks/useRippleEffect';
import { CheckBoxLayout } from '../checkbox-layout/check-box-layout';
import {
forwardRef,
PropsWithChildren,
useEffect,
useImperativeHandle,
useRef,
useState,
} from 'react';
/**
* Checkbox component
** description
*/
export const Checkbox = forwardRef<
HTMLInputElement,
PropsWithChildren<any> & IRippleProps
>(({ centralRipple, ...props }, ref) => {
const [isActive, setIsActive] = useState<boolean>(false),
[checked, setChecked] = useState<boolean>(props.checked ?? false),
ripplesRef = useRef(null),
checkboxRef = useRef(null),
events = useRippleEffect(ripplesRef, setIsActive);
const classes =
`m3 m3-checkbox-label ${isActive === true ? 'visible' : ''}`.trimEnd();
const indeterminate = (props.indeterminate === true).toString();
useImperativeHandle(ref, () => checkboxRef.current);
useEffect(() => {
setChecked(!checked);
}, [checkboxRef.current?.checked]);
return (
<label {...events} className={classes}>
<CheckBoxLayout
{...props}
indeterminate={indeterminate}
ref={checkboxRef}
type={'checkbox'}
/>
<span className={'m3 m3-checkbox-state-layer'} />
<RippleArea
callback={setIsActive}
central={centralRipple}
className={'m3-checkbox-ripple-layer'}
ref={ripplesRef}
/>
{props.children}
</label>
);
});

View File

@@ -0,0 +1,18 @@
import React, { forwardRef, PropsWithChildren } from 'react';
interface DividerProps extends PropsWithChildren<any> {
orientation?: 'vertical' | 'horizontal';
variant?: 'full-width' | 'inset' | 'middle-inset';
}
const Divider = forwardRef<HTMLHRElement, DividerProps>(
({ orientation, variant, ...props }, ref) => (
<hr
{...props}
className={`m3 m3-divider ${orientation ?? 'horizontal'} ${variant ?? 'full-width'}`.trimEnd()}
ref={ref}
/>
),
);
export { Divider };

View File

@@ -0,0 +1,52 @@
'use client';
import { forwardRef } from 'react';
import { Icon } from '../material-you-components';
import { IRippleProps } from '../ripple/ripple.types';
import { FABMainProps } from '../button-layout/button.types';
import { ButtonLayout } from '../button-layout/button-layout';
/**
* FABs component
** description
*/
const sizes = {
small: 24,
default: 24,
large: 36,
extended: 24,
};
export const FAB = forwardRef<HTMLButtonElement, FABMainProps & IRippleProps>(
(
{
variant,
disabled,
icon,
centralRipple = false,
size = 'default',
elevated,
...props
},
ref,
) => (
<ButtonLayout
{...props}
centralRipple={centralRipple}
className={`m3-fab m3-${size}-fab ${!(elevated ?? false) && 'without-elevation'}`}
disabled={disabled}
ref={ref}
variant={variant ? variant : 'surface'}
>
<Icon iconSize={sizes[size]} svgSize={sizes[size]}>
{icon}
</Icon>
{size === 'extended' ? (
<span className={'label-large'}>{props.children}</span>
) : (
<></>
)}
</ButtonLayout>
),
);

View File

@@ -0,0 +1,86 @@
'use client';
import { Icon } from '../material-you-components';
import { toggleIconType } from './icon-button.types';
import { IRippleProps } from '../ripple/ripple.types';
import { ButtonLayout } from '../button-layout/button-layout';
import { IconButtonMainProps } from '../button-layout/button.types';
import {
forwardRef,
useCallback,
useImperativeHandle,
useRef,
useState,
} from 'react';
/**
* Icon button-layout component
** description
*/
export const IconButton = forwardRef<
HTMLButtonElement,
IconButtonMainProps & IRippleProps
>(
(
{
icon,
variant,
disabled,
selected = false,
toggled = false,
centralRipple,
...props
},
ref,
) => {
const [toggleIcon, setToggleIcon] = useState<toggleIconType>({
state: selected == true ? 'selected' : 'unselected',
icon: toggled ? toggled.unselected ?? 'add_circle' : 'add_circle',
});
const toggle = (classes: string, icon: string) => {
setToggleIcon(() => ({
state: classes,
icon: icon,
}));
};
const buttonRef = useRef<HTMLButtonElement>(null);
const callback = useCallback(() => {
if (toggled) {
if (toggleIcon.state === 'selected') {
toggle('', toggled.unselected ?? 'add_circle');
} else {
toggle('selected', toggled.selected ?? 'add_circle');
}
}
if (props.onClick) {
props.onClick();
}
}, [toggleIcon]);
useImperativeHandle(ref, () => buttonRef.current);
return (
<ButtonLayout
{...props}
centralRipple={centralRipple}
className={`m3-icon-button ${toggleIcon.state} ${toggled ? 'toggled' : ''}`.trimEnd()}
disabled={disabled}
onClick={callback}
ref={buttonRef}
variant={variant ? variant : 'default'}
>
<Icon
fill={toggleIcon.state === 'selected' ? 1 : 0}
iconSize={28}
svgSize={40}
>
{toggled ? toggleIcon.icon : icon ? icon : undefined}
</Icon>
</ButtonLayout>
);
},
);

View File

@@ -0,0 +1,4 @@
export type toggleIconType = {
state: string;
icon: string;
};

View File

@@ -0,0 +1,53 @@
import { IconProps } from './icon.types';
import { bool, number, string } from 'prop-types';
import React, { ForwardedRef, forwardRef } from 'react';
const Icon = forwardRef(function Icon(
{
grade = 0,
weight = 500,
svgSize = 20,
fill = false,
iconSize = 20,
opticalSize = 24,
type = 'outlined',
...props
}: IconProps,
ref: ForwardedRef<any>,
) {
const fontVariation = {
fontVariationSettings: `'FILL' ${fill ? 1 : 0}, 'wght' ${weight}, 'GRAD' ${grade}, 'optz' ${opticalSize}`,
};
return (
<svg
{...props}
className={`m3 m3-svg-icon ${props.className ?? ''}`.trim()}
height={svgSize}
ref={ref}
width={svgSize}
>
<text
className={`m3-${type[0].toUpperCase() + type.slice(1)} m3-size-${iconSize}px`}
style={fontVariation}
x={'50%'}
y={'50%'}
>
{props.children ?? 'add_circle'}
</text>
</svg>
);
});
Icon.propTypes = {
fill: bool,
type: string,
grade: number,
weight: number,
svgSize: number,
iconSize: number,
children: string,
opticalSize: number,
};
export { Icon };

View File

@@ -0,0 +1,11 @@
import { PropsWithChildren } from 'react';
export interface IconProps extends PropsWithChildren<any> {
fill?: boolean;
grade?: number;
svgSize?: number;
iconSize?: number;
opticalSize?: number;
type?: 'outlined' | 'rounded' | 'sharp';
weight?: 100 | 200 | 300 | 400 | 500 | 600 | 700;
}

View File

@@ -0,0 +1,13 @@
export { FAB } from './fab/fab';
export { Icon } from './icon/icon';
export { Radio } from './radio/radio';
export { Badge } from './badge/badge';
export { Switch } from './switch/switch';
export { Button } from './button/button';
export { Divider } from './divider/divider';
export { Checkbox } from './checkbox/checkbox';
export { RippleArea } from './ripple/ripple-area';
export { Ripples, Ripple } from './ripple/ripple';
export { TextField } from './text-field/text-field';
export { IconButton } from './icon-button/icon-button';
export { ButtonLayout } from './button-layout/button-layout';

View File

@@ -0,0 +1,38 @@
'use client';
import { RippleArea } from '../ripple/ripple-area';
import { IRippleProps } from '../ripple/ripple.types';
import useRippleEffect from '../ripple/hooks/useRippleEffect';
import { CheckBoxLayout } from '../checkbox-layout/check-box-layout';
import { forwardRef, PropsWithChildren, useRef, useState } from 'react';
/**
* Radio component
** description
*/
export const Radio = forwardRef<
HTMLInputElement,
PropsWithChildren<HTMLElement> & IRippleProps
>(({ centralRipple, ...props }, ref) => {
const [isActive, setIsActive] = useState<boolean>(false),
ripplesRef = useRef(null),
events = useRippleEffect(ripplesRef, setIsActive);
const classes =
`m3 m3-radio-label ${isActive === true ? 'visible' : ''}`.trimEnd();
return (
<label {...events} className={classes}>
<CheckBoxLayout {...props} ref={ref} type={'radio'} />
<span className={'m3 m3-radio-state-layer'} />
<RippleArea
callback={setIsActive}
central={centralRipple}
className={'m3-checkbox-ripple-layer'}
ref={ripplesRef}
/>
{props.children}
</label>
);
});

View File

@@ -0,0 +1,43 @@
import React, { useEffect, useState } from 'react';
interface RippleEventHandlers {
onBlur: React.FocusEventHandler;
onContextMenu: React.MouseEventHandler;
onDragLeave: React.DragEventHandler;
onMouseDown: React.MouseEventHandler;
onMouseLeave: React.MouseEventHandler;
onMouseUp: React.MouseEventHandler;
onTouchEnd: React.TouchEventHandler;
onTouchMove: React.TouchEventHandler;
onTouchStart: React.TouchEventHandler;
}
const UseRippleEffect = (ref, callback): undefined | RippleEventHandlers => {
const [mounted, setMounted] = useState<boolean>(false);
useEffect(() => {
if (!mounted) {
setMounted(true);
}
});
if (!mounted) {
return;
}
const { start, stop } = ref.current;
return {
onBlur: event => stop(event, callback),
onContextMenu: event => start(event, callback),
onDragLeave: event => stop(event, callback),
onMouseDown: event => start(event, callback),
onMouseLeave: event => stop(event, callback),
onMouseUp: event => stop(event, callback),
onTouchEnd: event => stop(event, callback),
onTouchMove: event => stop(event, callback),
onTouchStart: event => stop(event, callback),
};
};
export default UseRippleEffect;

View File

@@ -0,0 +1,130 @@
'use client';
import React, {
forwardRef,
useCallback,
useId,
useImperativeHandle,
useRef,
useState,
} from 'react';
import { Ripple } from './ripple';
import { Ripples } from './ripple';
import { RippleAreaProps } from './ripple.types';
const TIMEOUT: number = 550;
const rippleAreaContext = React.createContext(false);
const RippleArea = forwardRef(function RippleArea(
{ central = false, callback, ...props }: RippleAreaProps,
ref,
) {
const [ripples, setRipples] = useState<Array<JSX.Element>>([]),
rippleDomain = useRef<any>(null),
clicked = useRef<boolean>(false),
uniqueKey = useRef<number>(0),
uniqueId = useId();
const classes = props.className
? `m3 m3-ripple-domain ${props.className}`.trimEnd()
: 'm3 m3-ripple-domain';
const start = useCallback(
(event: any, cb: (state: boolean) => void): void => {
clicked.current = true;
cb(clicked.current);
const rippleDomainChar = rippleDomain.current
? rippleDomain.current.getBoundingClientRect()
: {
width: 0,
height: 0,
left: 0,
top: 0,
};
const rippleX: number = !central
? event.clientX - rippleDomainChar.left
: rippleDomainChar.width / 2,
rippleY: number = !central
? event.clientY - rippleDomainChar.top
: rippleDomainChar.height / 2,
rippleSizeX: number =
Math.max(
Math.abs(rippleDomainChar.width - rippleX),
rippleX,
) *
2 +
2,
rippleSizeY: number =
Math.max(
Math.abs(rippleDomainChar.height - rippleY),
rippleY,
) *
2 +
2,
rippleS: number = (rippleSizeX ** 2 + rippleSizeY ** 2) ** 0.5;
setRipples((prevRipples: Array<JSX.Element>) => {
if (prevRipples.length === 0) {
return [
<Ripple
key={uniqueKey.current}
lifetime={TIMEOUT}
rippleS={rippleS}
rippleX={rippleX}
rippleY={rippleY}
/>,
];
}
const old = [...prevRipples];
old.push(
<Ripple
key={uniqueKey.current}
lifetime={TIMEOUT}
rippleS={rippleS}
rippleX={rippleX}
rippleY={rippleY}
/>,
);
return old;
});
uniqueKey.current += 1;
},
[],
);
const stop = useCallback((_event: any, cb: (state: boolean) => void) => {
clicked.current = false;
cb(clicked.current);
setRipples((prevRipples: Array<JSX.Element>) => {
if (prevRipples.length > 0) {
const old = [...prevRipples];
old.shift();
return old;
}
return prevRipples;
});
}, []);
useImperativeHandle(
ref,
() => ({
start,
stop,
}),
[start, stop],
);
return (
<span className={classes} id={uniqueId} ref={rippleDomain}>
<rippleAreaContext.Provider value={clicked.current}>
<Ripples>{ripples}</Ripples>
</rippleAreaContext.Provider>
</span>
);
});
export { rippleAreaContext, RippleArea };

View File

@@ -0,0 +1,86 @@
'use client';
import isEmpty from './utils/utils';
import { rippleProps } from './ripple.types';
import { rippleAreaContext } from './ripple-area';
import RippleEffectBuild from './utils/ripple-effect-builder';
import React, {
ForwardedRef,
forwardRef,
JSX,
useCallback,
useContext,
useEffect,
useRef,
useState,
useTransition,
} from 'react';
const Ripples = forwardRef(function Ripples(
props: any,
ref: ForwardedRef<any>,
) {
const [ripples, setRipples] = useState({});
const firstRender = useRef<boolean>(true);
const [pending, startTransition] = useTransition();
const LifetimeEnd = useCallback((child: JSX.Element) => {
if (child.props.endLifetime) {
child.props.endLifetime();
}
setRipples(state => {
const children = { ...state };
delete children[child.key];
return children;
});
}, []);
useEffect(() => {
if (props.children.length > 0) {
startTransition(() => {
if (firstRender.current || isEmpty(ripples)) {
setRipples(RippleEffectBuild(props.children, LifetimeEnd));
firstRender.current = false;
} else {
setRipples(
RippleEffectBuild(props.children, LifetimeEnd, ripples),
);
}
});
}
}, [props.children]);
return <>{Object.values(ripples)}</>;
});
const Ripple = forwardRef(function Ripple(
props: rippleProps,
ref: ForwardedRef<any>,
) {
const { rippleX, rippleY, rippleS, endLifetime, lifetime } = props;
const clicked = useContext<boolean>(rippleAreaContext);
const [classes, setClasses] = useState<string>('m3 ripple visible');
useEffect(() => {
if (endLifetime !== null && !clicked) {
setClasses('m3 ripple');
setTimeout(endLifetime, lifetime);
}
}, [clicked, endLifetime]);
return (
<span
className={classes}
style={{
left: -(rippleS / 2) + rippleX,
top: -(rippleS / 2) + rippleY,
width: rippleS,
aspectRatio: 1,
}}
/>
);
});
export { Ripple, Ripples };

View File

@@ -0,0 +1,21 @@
import { Dispatch, SetStateAction } from 'react';
export interface IRippleProps extends PropsWithChildren<any> {
centralRipple?: boolean;
}
export interface RippleAreaProps extends PropsWithChildren<any> {
callback: Dispatch<SetStateAction<boolean>>;
central?: boolean;
}
export type rippleProps = {
rippleX: number;
rippleY: number;
rippleS: number;
endLifetime?: () => void;
lifetime: number;
key?: number;
};
import { PropsWithChildren } from 'react';

View File

@@ -0,0 +1,15 @@
import { cloneElement, ReactElement } from 'react';
export default function ArrayConvertToObj(
obj: Object,
nextChildren: ReactElement[],
callback: (child: any) => void,
): void {
Object.values(nextChildren).forEach(
(child: JSX.Element) =>
(obj[child.key] = cloneElement(child, {
...child.props,
endLifetime: callback.bind(null, child),
})),
);
}

View File

@@ -0,0 +1,34 @@
import ArrayConvertToObj from './array-convert-to-obj';
import { cloneElement, ReactElement } from 'react';
import isEmpty from './utils';
export default function RippleEffectBuild(
nextRipples: ReactElement[],
callback: (child: any) => void,
prevRipples?: any | null,
) {
const empty: boolean = isEmpty(prevRipples);
const preparedRipples: object = empty ? {} : prevRipples;
switch (empty) {
case true:
ArrayConvertToObj(preparedRipples, nextRipples, callback);
break;
case false:
// eslint-disable-next-line no-case-declarations
const next: object = {};
ArrayConvertToObj(next, nextRipples, callback);
for (const rippleKey of Object.keys(next)) {
if (preparedRipples[rippleKey] == undefined) {
preparedRipples[rippleKey] = cloneElement(next[rippleKey], {
...next[rippleKey].props,
endLifetime: callback.bind(null, next[rippleKey]),
});
}
}
break;
}
return preparedRipples;
}

View File

@@ -0,0 +1,6 @@
export default function isEmpty(obj: Object): boolean {
for (const _i in obj) {
return false;
}
return true;
}

View File

@@ -0,0 +1,36 @@
'use client';
import React, { forwardRef } from 'react';
import { SwitchMainProps } from './switch.types';
import { CheckBoxLayout } from '../checkbox-layout/check-box-layout';
/**
* Switch component
** description
*/
export const Switch = forwardRef<HTMLInputElement, SwitchMainProps>(
({ icon, disabled, selected = false, ...props }, ref) => (
<div className={'m3 m3-switch-exp'} ref={ref}>
<CheckBoxLayout
{...props}
className={`m3 ${props.className ?? ''}`.trimEnd()}
disabled={disabled}
type={'checkbox'}
/>
<svg>
<rect className={'m3 m3-switch-track'} />
<circle className={'m3 m3-switch-handler'} />
<circle className={'m3 m3-switch-handler-state-layer'} />
<g>
{icon && !selected && (
<text className={'m3 m3-icon-unchecked'}>close</text>
)}
{icon && (
<text className={'m3 m3-icon-checked'}>check</text>
)}
</g>
</svg>
</div>
),
);

View File

@@ -0,0 +1,7 @@
import { PropsWithChildren } from 'react';
export interface SwitchMainProps extends PropsWithChildren<any> {
disabled?: boolean;
icon?: boolean;
selected?: boolean;
}

View File

@@ -0,0 +1,103 @@
'use client';
import React, { forwardRef, useState } from 'react';
import { bool, string } from 'prop-types';
import { type TextFieldInterface } from './text-field.types';
export const TextField = forwardRef<HTMLInputElement, TextFieldInterface>(
(
{
variant = 'filled',
withAfterIcon,
withBeforeIcon,
supportingText,
...props
},
ref,
) => {
const [raised, setRaised] = useState<boolean>(
props.placeholder ?? false,
);
const callback = (e: any): void => {
if (
e.type === 'blur' &&
e.target.value.length === 0 &&
!props.placeholder
) {
setRaised(false);
} else if (e.type === 'focus') {
setRaised(true);
}
};
const iconStyles =
withBeforeIcon && withAfterIcon
? 'with-before-icon with-after-icon'
: withBeforeIcon
? 'with-before-icon'
: withAfterIcon
? 'with-after-icon'
: '';
return (
<span>
<div className={`m3 m3-text-field ${variant}`.trimEnd()}>
{variant === 'outlined' && (
<fieldset>
<legend className={raised && 'raised'}>
<span>Label</span>
</legend>
</fieldset>
)}
{withBeforeIcon && (
<span className={'m3-icon icon-before'}>
{withBeforeIcon && 'search'}
</span>
)}
<input
ref={ref}
{...props}
className={`${props.className ?? ''} ${iconStyles}`.trim()}
onBlur={event => {
callback(event);
if (props.onBlur) {
props.onBlur(event);
}
}}
onFocus={event => {
callback(event);
if (props.onFocus) {
props.onFocus(event);
}
}}
/>
<label className={raised ? 'raised' : ''}>
{props.children ?? 'Label'}
</label>
<span className={'m3-text-field-state-layer'} />
{withAfterIcon && (
<span className={'m3-icon'}>
{withAfterIcon && 'cancel'}
</span>
)}
</div>
{supportingText !== '' && (
<span className={'m3-text-field-supporting-text'}>
{supportingText}
</span>
)}
</span>
);
},
);
TextField.propTypes = {
children: string,
withBeforeIcon: bool,
withAfterIcon: bool,
className: string,
variant: string,
placeholder: string,
supportingText: string,
};

View File

@@ -0,0 +1,8 @@
import { PropsWithChildren } from 'react';
export interface TextFieldInterface extends PropsWithChildren<any> {
variant: 'filled' | 'outlined';
withAfterIcon?: boolean;
withBeforeIcon?: boolean;
supportingText?: string;
}