Skip to content
Open
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
2 changes: 1 addition & 1 deletion src/5_shared/assets/icons/actions/tick.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
71 changes: 71 additions & 0 deletions src/5_shared/ui/CustomCheckbox/CustomCheckbox.module.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
@import '@styles/colors.scss';

.visuallyHidden {
position: absolute;
width: 1px;
height: 1px;
margin: -1px;
padding: 0;
border: 0;
clip: rect(0 0 0 0);
overflow: hidden;
}

.checkbox {
position: relative;
display: flex;
align-items: center;
padding: 0;
cursor: pointer;

&--right {
justify-content: space-between;
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Не совсем поняла, почему при тексте слева или справа элемент себя совсем по-разному ведет. Почему нельзя сделать промежуток между чекбоксом и текстом с помощью gap? Тогда и марджин не нужен. Сейчас элемент растягивается на весь контейнер, чекбокс улетает далеко от текста, если выбрать isPositionRight, и нужно задавать макс ширину дополнительно

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

К сожалению, не нашла в макете пример с правым чекбоксом. Исходила из следующих соображений.

  1. Если задать gap, когда текст слева, то все иконки будут находиться на разном уровне, т.к. длина текста в разных label не будет одинаковой. Насколько я поняла, текст и иконка должны быть разнесены по разным сторонам контейнера (как на скриншоте разнесены дата и значок календаря). Тут нужно понимать, какой ожидается результат: одинаковое расстояние между текстом и иконкой во всех чекбоксах или разнесение текста и иконки по краям? Возможно, такой вариант чекбокса будет использоваться в мобильной версии.

  2. Чекбоксы не будут находиться на странице сами по себе. Они в любом случае будут в каком-то контейнере (например, в форме, как на скрине). Тогда ширина чекбокса с левым текстом и правой иконкой будет зависеть от ширины этого контейнера, т.е. задавать макс. ширину нет смысла и может даже навредить, т.к. мы не знаем, какой длины текст будет находиться в label. Если же такой вариант чекбокса предполагается использовать в мобильной версии, то ширина будет ограничена либо шириной экрана, либо контейнером.

checkbox

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Выбор даты это совсем другой элемент, но логика ясна.
Стили можно переопределять при вызове этого компонента, но лучше конечно изначально задать оптимальные

Copy link
Copy Markdown
Collaborator Author

@ElveeC ElveeC Jan 20, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Выбор даты я привела в качестве чисто визуального примера, т.к. не нашла в макете пример с таким чекбоксом. Поэтому вопрос в том, как предполагается использовать чекбокс такого типа. Если он должен выглядеть так, как элемент с выбором даты, то это как раз достигается с помощью space-between. Если он должен выглядеть по-другому (т.е. важно именно расстояние между текстом и иконкой), то использовать gap. Т.е. это разные задачи, которые решаются разными способами. Изменить на gap или оставить, как есть, до появления в макете такого элемента?

}
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Весь элемент кликабельный, не хватает cursor: pointer

}

.icon {
display: flex;
margin-right: 10px;
justify-content: center;
align-items: center;
width: 24px;
height: 24px;
box-sizing: border-box;
border: 1px solid $neutral-text-light-color;
border-radius: 6px;
color: rgb(255, 255, 255, 0);

&--right {
margin-right: 0;
}

&--error {
border: 1px solid $danger-bright-color;
}
}

label:hover .icon {
border-color: $primary-background-color;
}

input:checked ~ .icon {
background-color: $primary-button-active-color;
border: 1px solid $primary-button-active-color;
color: $neutral-background-main-color;
}

input:disabled ~ .icon {
background-color: $neutral-background-second-color;
border: 1px solid $neutral-line-color;
}

input:checked:disabled ~ .icon {
background-color: $neutral-background-second-color;
border: 1px solid $neutral-text-light-color;
color: $neutral-text-light-color;
}

.label {
font-size: 14px;
line-height: 16px;
}
71 changes: 71 additions & 0 deletions src/5_shared/ui/CustomCheckbox/CustomCheckbox.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import cx from 'classnames';
import { ChangeEvent } from 'react';

import SvgIconTick from '@assets/icons/actions/tick.svg?react';

import styles from './CustomCheckbox.module.scss';

interface CustomCheckboxProps {
name: string;
value?: string;
id?: string;
onChange?: (event: ChangeEvent<HTMLInputElement>) => void;
inputClassName?: string;
labelClassName?: string;
isDisabled?: boolean;
isChecked?: boolean;
isPositionRight?: boolean;
isError?: boolean;
children?: JSX.Element | string;
}

export const CustomCheckbox = ({
name,
value,
id,
onChange,
inputClassName,
labelClassName,
isDisabled,
isChecked,
isPositionRight,
isError,
children,
}: CustomCheckboxProps) => {
return (
<label
className={cx(styles.checkbox, labelClassName, {
[styles['checkbox--right']]: isPositionRight,
})}
>
<input
type="checkbox"
value={value}
name={name}
id={id}
className={cx(styles.visuallyHidden, inputClassName)}
onChange={onChange}
disabled={isDisabled}
checked={isChecked}
/>

{isPositionRight ? (
<>
<span className={styles.label}>{children}</span>
<span
className={cx(styles.icon, styles['icon--right'], { [styles['icon--error']]: isError })}
>
<SvgIconTick />
</span>
</>
) : (
<>
<span className={cx(styles.icon, { [styles['icon--error']]: isError })}>
<SvgIconTick />
</span>
<span className={styles.label}>{children}</span>
</>
)}
</label>
);
};
85 changes: 85 additions & 0 deletions src/5_shared/ui/CustomRadio/CustomRadio.module.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
@import '@styles/colors.scss';

.visuallyHidden {
position: absolute;
width: 1px;
height: 1px;
margin: -1px;
padding: 0;
border: 0;
clip: rect(0 0 0 0);
overflow: hidden;
}

.radio {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Также не хватает cursor: pointer

position: relative;
display: flex;
align-items: center;
padding: 0;
cursor: pointer;

&--right {
justify-content: space-between;
}
}

.icon {
display: flex;
margin-right: 10px;
justify-content: center;
align-items: center;
width: 24px;
height: 24px;
box-sizing: border-box;
background-color: $neutral-background-main-color;
border: 1px solid $neutral-text-light-color;
border-radius: 50%;

&--right {
margin-right: 0;
}

&--error {
border: 1px solid $danger-bright-color;
}
}

label:hover .icon {
border-color: $primary-background-color;
}

input:checked ~ .icon {
background-color: $primary-button-active-color;
border: 1px solid $primary-button-active-color;
}

input:checked ~ .icon::before {
content: '';
width: 8px;
height: 8px;
border-radius: 50%;
background-color: $neutral-background-main-color;
}

input:disabled ~ .icon {
background-color: $neutral-background-second-color;
border: 1px solid $neutral-line-color;
}

input:checked:disabled ~ .icon {
background-color: $neutral-background-main-color;
border: 1px solid $neutral-text-light-color;
}

input:checked:disabled ~ .icon::before {
content: '';
width: 8px;
height: 8px;
border-radius: 50%;
background-color: $neutral-text-light-color;
}

.label {
font-size: 14px;
line-height: 16px;
}
63 changes: 63 additions & 0 deletions src/5_shared/ui/CustomRadio/CustomRadio.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import cx from 'classnames';
import { ChangeEvent } from 'react';

import styles from './CustomRadio.module.scss';

interface CustomRadioProps {
name: string;
value: string;
id?: string;
onChange?: (event: ChangeEvent<HTMLInputElement>) => void;
inputClassName?: string;
labelClassName?: string;
labelText?: string;
isDisabled?: boolean;
isChecked?: boolean;
isPositionRight?: boolean;
isError?: boolean;
}

export const CustomRadio = ({
name,
value,
id,
onChange,
inputClassName,
labelClassName,
labelText,
isDisabled,
isChecked,
isPositionRight,
isError,
}: CustomRadioProps) => {
return (
<label
className={cx(styles.radio, labelClassName, { [styles['radio--right']]: isPositionRight })}
>
<input
type="radio"
name={name}
value={value}
id={id}
className={cx(styles.visuallyHidden, inputClassName)}
onChange={onChange}
disabled={isDisabled}
checked={isChecked}
/>

{isPositionRight ? (
<>
<span className={styles.label}>{labelText}</span>
<span
className={cx(styles.icon, styles['icon--right'], { [styles['icon--error']]: isError })}
></span>
</>
) : (
<>
<span className={cx(styles.icon, { [styles['icon--error']]: isError })}></span>
<span className={styles.label}>{labelText}</span>
</>
)}
</label>
);
};
Loading