D: Add documentation to react components pt1

This commit is contained in:
Ivan 2024-09-12 16:41:48 +03:00
parent ca077cb2f3
commit 16479d6299
16 changed files with 174 additions and 46 deletions

View File

@ -143,11 +143,10 @@ This readme file is used mostly to document project dependencies and conventions
## 📝 Commit conventions
- 🚀 F: major feature implementation
- 💄 D: UI design
- 🔥 B: bug fix
- 🚑 M: Minor fixes
- 🔧 R: refactoring and code improvement
- 📝 I: documentation
- 📝 D: documentation
## 🖥️ Local build (Windows 10+)

View File

@ -2,47 +2,112 @@
import { HTMLMotionProps } from 'framer-motion';
export namespace CProps {
export interface Titled {
title?: string;
titleHtml?: string;
hideTitle?: boolean;
}
export type Control = Titled & {
disabled?: boolean;
noBorder?: boolean;
noOutline?: boolean;
};
/**
* Represents an object that can have inline styles and CSS class names for styling.
*/
export interface Styling {
/** Optional inline styles for the component. */
style?: React.CSSProperties;
/** Optional CSS class name(s) for the component. */
className?: string;
}
export type Editor = Control & {
label?: string;
};
/**
* Represents an object that can have a color or set of colors.
*/
export interface Colors {
/** Optional color or set of colors applied via classNames. */
colors?: string;
}
/**
* Represents an object that can have a title with optional HTML rendering and a flag to hide the title.
*/
export interface Titled {
/** Tooltip: `plain text`. */
title?: string;
/** Tooltip: `HTML formatted`. */
titleHtml?: string;
/** Indicates whether the `title` should be hidden. */
hideTitle?: boolean;
}
/**
* Represents `control` component with optional title and configuration options.
*
* @remarks
* This type extends the {@link Titled} interface, adding properties to control the visual and interactive behavior of a component.
*/
export type Control = Titled & {
/** Indicates whether the control is disabled. */
disabled?: boolean;
/** Indicates whether the control should render without a border. */
noBorder?: boolean;
/** Indicates whether the control should render without an outline. */
noOutline?: boolean;
};
/**
* Represents `editor` component that includes a label, control features, and optional title properties.
*
* @remarks
* This type extends the {@link Control} type, inheriting title-related properties and additional configuration options, while also adding an optional label.
*/
export type Editor = Control & {
/** Text label. */
label?: string;
};
/**
* Represents `div` component with all standard HTML attributes and React-specific properties.
*/
export type Div = React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>;
/**
* Represents `button` component with optional title and HTML attributes.
*/
export type Button = Titled &
Omit<
React.DetailedHTMLProps<React.ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>,
'children' | 'type'
>;
/**
* Represents `label` component with HTML attributes.
*/
export type Label = Omit<
React.DetailedHTMLProps<React.LabelHTMLAttributes<HTMLLabelElement>, HTMLLabelElement>,
'children'
>;
/**
* Represents `textarea` component with optional title and HTML attributes.
*/
export type TextArea = Titled &
React.DetailedHTMLProps<React.TextareaHTMLAttributes<HTMLTextAreaElement>, HTMLTextAreaElement>;
/**
* Represents `input` component with optional title and HTML attributes.
*/
export type Input = Titled & React.DetailedHTMLProps<React.InputHTMLAttributes<HTMLInputElement>, HTMLInputElement>;
/**
* Represents `button` component with optional title and animation properties.
*/
export type AnimatedButton = Titled & Omit<HTMLMotionProps<'button'>, 'type'>;
/**
* Represents `div` component with animation properties.
*/
export type AnimatedDiv = HTMLMotionProps<'div'>;
/**
* Represents `mouse event` in React.
*/
export type EventMouse = React.MouseEvent<Element, MouseEvent>;
}

View File

@ -5,16 +5,25 @@ import { globals } from '@/utils/constants';
import { CProps } from '../props';
interface ButtonProps extends CProps.Control, CProps.Colors, CProps.Button {
text?: string;
/** Icon to display first. */
icon?: React.ReactNode;
/** Text to display second. */
text?: string;
/** Indicates whether to render the button in a dense style. */
dense?: boolean;
/** Indicates loading state to prevent interactions and change visual style. */
loading?: boolean;
}
/**
* Button component that provides a customizable `button` with text, icon, tooltips and various styles.
*/
function Button({
text,
icon,
text,
title,
titleHtml,
hideTitle,

View File

@ -7,13 +7,22 @@ import { CheckboxChecked } from '../Icons';
import { CProps } from '../props';
export interface CheckboxProps extends Omit<CProps.Button, 'value' | 'onClick'> {
/** Label to display next to the checkbox. */
label?: string;
/** Indicates whether the checkbox is disabled. */
disabled?: boolean;
/** Current value - `true` or `false`. */
value: boolean;
/** Callback to set the `value`. */
setValue?: (newValue: boolean) => void;
}
/**
* Checkbox component that allows users to toggle a boolean value.
*/
function Checkbox({
disabled,
label,

View File

@ -8,10 +8,16 @@ import { CProps } from '../props';
import { CheckboxProps } from './Checkbox';
export interface CheckboxTristateProps extends Omit<CheckboxProps, 'value' | 'setValue'> {
/** Current value - `null`, `true` or `false`. */
value: boolean | null;
/** Callback to set the `value`. */
setValue?: (newValue: boolean | null) => void;
}
/**
* CheckboxTristate component that allows toggling among three states: `true`, `false`, and `null`.
*/
function CheckboxTristate({
disabled,
label,

View File

@ -2,11 +2,17 @@ import clsx from 'clsx';
import { CProps } from '@/components/props';
interface DividerProps extends CProps.Styling {
export interface DividerProps extends CProps.Styling {
/** Indicates whether the divider is vertical. */
vertical?: boolean;
/** Margins to apply to the divider `classNames`. */
margins?: string;
}
/**
* Divider component that renders a horizontal or vertical divider with customizable margins and styling.
*/
function Divider({ vertical, margins = 'mx-2', className, ...restProps }: DividerProps) {
return (
<div

View File

@ -6,12 +6,22 @@ import { animateDropdown } from '@/styling/animations';
import { CProps } from '../props';
interface DropdownProps extends CProps.Styling {
/** Indicates whether the dropdown should stretch to the left. */
stretchLeft?: boolean;
/** Indicates whether the dropdown should stretch to the top. */
stretchTop?: boolean;
/** Indicates whether the dropdown is open. */
isOpen: boolean;
/** Children to render inside the component. */
children: React.ReactNode;
}
/**
* Dropdown animated component that displays a list of children with optional positioning and visibility control.
*/
function Dropdown({ isOpen, stretchLeft, stretchTop, className, children, ...restProps }: DropdownProps) {
return (
<div className='relative'>

View File

@ -7,15 +7,23 @@ import { globals } from '@/utils/constants';
import { CProps } from '../props';
interface DropdownButtonProps extends CProps.AnimatedButton {
text?: string;
/** Icon to display first (not used if children are provided). */
icon?: React.ReactNode;
/** Text to display second (not used if children are provided). */
text?: string;
/** Custom children to display. */
children?: React.ReactNode;
}
/**
* DropdownButton animated component that renders a `button` with optional text, icon, and click functionality.
* It supports optional children for custom content or the default text/icon display.
*/
function DropdownButton({
text,
icon,
text,
className,
title,
titleHtml,

View File

@ -3,21 +3,13 @@ import { motion } from 'framer-motion';
import { animateDropdownItem } from '@/styling/animations';
import Checkbox from './Checkbox';
import Checkbox, { CheckboxProps } from './Checkbox';
interface DropdownCheckboxProps {
value: boolean;
label?: string;
title?: string;
disabled?: boolean;
setValue?: (newValue: boolean) => void;
}
function DropdownCheckbox({ title, setValue, disabled, ...restProps }: DropdownCheckboxProps) {
/** DropdownCheckbox animated component that renders a {@link Checkbox} inside a {@link Dropdown} item. */
function DropdownCheckbox({ setValue, disabled, ...restProps }: CheckboxProps) {
return (
<motion.div
variants={animateDropdownItem}
title={title}
className={clsx(
'px-3 py-1',
'text-left overflow-ellipsis whitespace-nowrap',

View File

@ -1,15 +1,14 @@
import clsx from 'clsx';
import { motion } from 'framer-motion';
import { CProps } from '@/components/props';
import { animateDropdownItem } from '@/styling/animations';
interface DividerAnimatedProps extends CProps.Styling {
vertical?: boolean;
margins?: string;
}
import { DividerProps } from './Divider';
function DividerAnimated({ vertical, margins = 'mx-2', className, ...restProps }: DividerAnimatedProps) {
/**
* DropdownDivider component that renders {@link Divider} with animation inside {@link Dropdown}.
*/
function DropdownDivider({ vertical, margins = 'mx-2', className, ...restProps }: DividerProps) {
return (
<motion.div
variants={animateDropdownItem}
@ -26,4 +25,4 @@ function DividerAnimated({ vertical, margins = 'mx-2', className, ...restProps }
);
}
export default DividerAnimated;
export default DropdownDivider;

View File

@ -1,9 +1,17 @@
interface EmbedYoutubeProps {
/** Video ID to embed. */
videoID: string;
/** Display height in pixels. */
pxHeight: number;
/** Display width in pixels. */
pxWidth?: number;
}
/**
* EmbedYoutube component that embeds a YouTube video into the page using the given video ID and dimensions.
*/
function EmbedYoutube({ videoID, pxHeight, pxWidth }: EmbedYoutubeProps) {
if (!pxWidth) {
pxWidth = (pxHeight * 16) / 9;

View File

@ -9,12 +9,19 @@ import Button from './Button';
import Label from './Label';
interface FileInputProps extends Omit<CProps.Input, 'accept' | 'type'> {
/** Label to display in file upload button. */
label: string;
/** Filter: file types. */
acceptType?: string;
/** Callback to set the `value`. Value is transmitted as `event.target.files[0]`. */
onChange?: (event: React.ChangeEvent<HTMLInputElement>) => void;
}
/**
* FileInput component for selecting a `file`, displaying the selected file name.
*/
function FileInput({ id, label, acceptType, title, className, style, onChange, ...restProps }: FileInputProps) {
const inputRef = useRef<HTMLInputElement | null>(null);
const [fileName, setFileName] = useState('');

View File

@ -2,6 +2,10 @@ import clsx from 'clsx';
import { CProps } from '../props';
/**
* FlexColumn component that renders a `flex` column container.
* This component is useful for creating vertical layouts with flexbox.
*/
function FlexColumn({ className, children, ...restProps }: CProps.Div) {
return (
<div className={clsx('cc-column', className)} {...restProps}>

View File

@ -5,10 +5,16 @@ import { globals } from '@/utils/constants';
import { CProps } from '../props';
interface IndicatorProps extends CProps.Titled, CProps.Styling {
/** Icon to display. */
icon: React.ReactNode;
/** Indicates whether the indicator should have no padding. */
noPadding?: boolean;
}
/**
* Indicator component that displays a status `icon` with a tooltip.
*/
function Indicator({ icon, title, titleHtml, hideTitle, noPadding, className, ...restProps }: IndicatorProps) {
return (
<div

View File

@ -15,7 +15,7 @@ import {
IconShare
} from '@/components/Icons';
import Button from '@/components/ui/Button';
import DividerAnimated from '@/components/ui/DividerAnimated';
import DropdownDivider from '@/components/ui/DropdownDivider';
import Dropdown from '@/components/ui/Dropdown';
import DropdownButton from '@/components/ui/DropdownButton';
import { useAccessMode } from '@/context/AccessModeContext';
@ -96,7 +96,7 @@ function MenuOssTabs({ onDestroy }: MenuOssTabsProps) {
/>
) : null}
<DividerAnimated margins='mx-3 my-1' />
<DropdownDivider margins='mx-3 my-1' />
{user ? (
<DropdownButton

View File

@ -27,7 +27,7 @@ import {
IconUpload
} from '@/components/Icons';
import Button from '@/components/ui/Button';
import DividerAnimated from '@/components/ui/DividerAnimated';
import DropdownDivider from '@/components/ui/DropdownDivider';
import Dropdown from '@/components/ui/Dropdown';
import DropdownButton from '@/components/ui/DropdownButton';
import { useAccessMode } from '@/context/AccessModeContext';
@ -186,7 +186,7 @@ function MenuRSTabs({ onDestroy }: MenuRSTabsProps) {
/>
) : null}
<DividerAnimated margins='mx-3 my-1' />
<DropdownDivider margins='mx-3 my-1' />
{user ? (
<DropdownButton
@ -239,7 +239,7 @@ function MenuRSTabs({ onDestroy }: MenuRSTabsProps) {
onClick={handleInlineSynthesis}
/>
<DividerAnimated margins='mx-3 my-1' />
<DropdownDivider margins='mx-3 my-1' />
<DropdownButton
text='Упорядочить список'