CHANGED: style and components directories, removed redundant imports from styles

ADDED: container and card component, card-subcomponents WIP
This commit is contained in:
2024-02-03 01:34:54 +04:00
committed by doryan
parent 0ae3a6d980
commit df1d0c2599
75 changed files with 2509 additions and 2012 deletions

View File

@@ -0,0 +1,43 @@
'use client';
import React, {
forwardRef,
useEffect,
useImperativeHandle,
useRef,
} from 'react';
import { bool, string } from 'prop-types';
import { CheckboxLayoutProps } from './checkbox-layout.types';
export const CheckBoxLayout = forwardRef<HTMLInputElement, CheckboxLayoutProps>(
({ indeterminate, typeInput, type, ...props }, ref) => {
const checkboxRef = useRef<HTMLInputElement>(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}
/>
);
},
);
CheckBoxLayout.propTypes = {
typeInput: string,
indeterminate: bool,
};

View File

@@ -0,0 +1,12 @@
import { InputHTMLAttributes } from 'react';
export interface CheckboxLayoutProps
extends InputHTMLAttributes<HTMLInputElement> {
indeterminate?: boolean;
typeInput?: string;
type?: string;
}
export interface LabelPlacement {
labelPlacement?: 'left' | 'right';
}

View File

@@ -0,0 +1,63 @@
'use client';
import { bool } from 'prop-types';
import { CheckboxProps } from './checkbox.types';
import { RippleArea } from '../../ripple/ripple-area';
import useRippleEffect from '../../ripple/hooks/useRippleEffect';
import { CheckBoxLayout } from '../checkbox-layout/check-box-layout';
import {
forwardRef,
useEffect,
useImperativeHandle,
useRef,
useState,
} from 'react';
/**
* Checkbox component
** description
*/
export const Checkbox = forwardRef<HTMLInputElement, CheckboxProps>(
({ 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();
useImperativeHandle(ref, () => checkboxRef.current);
useEffect(() => {
setChecked(!checked);
}, [checkboxRef.current?.checked]);
return (
<label {...events} className={classes}>
<CheckBoxLayout
{...props}
indeterminate={props.indeterminate}
ref={checkboxRef}
type={'checkbox'}
/>
<span className={'m3 m3-checkbox-state'} />
<span className={'m3 m3-checkbox-state-layer'} />
<RippleArea
callback={setIsActive}
central={centralRipple}
className={'m3-checkbox-ripple-layer'}
ref={ripplesRef}
/>
{props.children}
</label>
);
},
);
Checkbox.propTypes = {
indeterminate: bool,
centralRipple: bool,
};

View File

@@ -0,0 +1,7 @@
import { InputHTMLAttributes } from 'react';
import { RipplePropsForComponents } from '../../ripple/ripple.types';
export type CheckboxProps = InputHTMLAttributes<HTMLInputElement> &
RipplePropsForComponents<HTMLInputElement> & {
indeterminate?: boolean;
};

View File

@@ -0,0 +1,54 @@
'use client';
import { bool, string } from 'prop-types';
import { RadioProps } from './radio.types';
import { RippleArea } from '../../ripple/ripple-area';
import { forwardRef, useRef, useState } from 'react';
import useRippleEffect from '../../ripple/hooks/useRippleEffect';
import { CheckBoxLayout } from '../checkbox-layout/check-box-layout';
/**
* Radio component
** description
*/
export const Radio = forwardRef<HTMLInputElement, RadioProps>(
({ centralRipple, ...props }, ref) => {
const [isActive, setIsActive] = useState<boolean>(false),
ripplesRef = useRef(null),
events = useRippleEffect(ripplesRef, setIsActive);
const classes =
`m3 m3-radio ${isActive === true ? 'visible' : ''}`.trimEnd();
return (
<div {...events} className={classes}>
<CheckBoxLayout {...props} ref={ref} type={'radio'} />
<span className={'m3 m3-radio-state-layer'} />
<svg height={'20px'} viewBox={'0 0 20 20'} width={'20px'}>
<circle
className={'m3-radio-outline'}
cx={'50%'}
cy={'50%'}
/>
<circle
className={'m3-radio-state'}
cx={'50%'}
cy={'50%'}
/>
</svg>
<RippleArea
callback={setIsActive}
central={centralRipple}
className={'m3-checkbox-ripple-layer'}
ref={ripplesRef}
/>
</div>
);
},
);
Radio.propTypes = {
children: string,
centralRipple: bool,
};

View File

@@ -0,0 +1,8 @@
import { InputHTMLAttributes } from 'react';
import { RipplePropsForComponents } from '../../ripple/ripple.types';
export type RadioProps = InputHTMLAttributes<HTMLInputElement> &
RipplePropsForComponents<HTMLInputElement> & {
children?: string;
centralRipple?: boolean;
};

View File

@@ -0,0 +1,42 @@
'use client';
import { bool } from 'prop-types';
import React, { forwardRef } from 'react';
import { SwitchMainProps } from './switch.types';
import { CheckBoxLayout } from '../checkbox-layout/check-box-layout';
import { LabelPlacement } from '../checkbox-layout/checkbox-layout.types';
/**
* Switch component
** description
*/
export const Switch = forwardRef<
HTMLInputElement,
SwitchMainProps & LabelPlacement
>(({ icon, selected = false, ...props }, ref) => (
<div className={'m3 m3-switch'}>
<CheckBoxLayout
{...props}
className={`m3 ${props.className ?? ''}`.trimEnd()}
ref={ref}
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>
));
Switch.propTypes = {
icon: bool,
selected: bool,
};

View File

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

View File

@@ -0,0 +1,99 @@
'use client';
import { bool, oneOf, string } from 'prop-types';
import { TextFieldInterface } from './text-field.types';
import React, { FocusEvent, forwardRef, useState } from 'react';
export const TextField = forwardRef<HTMLInputElement, TextFieldInterface>(
(
{
variant = 'filled',
withAfterIcon,
withBeforeIcon,
supportingText,
...props
},
ref,
) => {
const [raised, setRaised] = useState<boolean>(!!props.placeholder);
const callback = (e: FocusEvent<HTMLInputElement>): 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,
withAfterIcon: bool,
withBeforeIcon: bool,
supportingText: string,
variant: oneOf(['filled', 'outlined']),
};

View File

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