diff --git a/src/components/common/CalendarModal.scss b/src/components/common/CalendarModal.scss
index 57df4ef90..95fdf3334 100644
--- a/src/components/common/CalendarModal.scss
+++ b/src/components/common/CalendarModal.scss
@@ -99,61 +99,19 @@
}
.day-button {
+ --button-text-color: var(--color-text);
+
position: relative;
-
- margin: 0.125rem 0.625rem;
- border-radius: 4rem;
-
font-weight: var(--font-weight-medium);
-
- outline: none !important;
-
- &::before {
- content: "";
- display: block;
- padding-top: 100%;
- }
+ font-variant-numeric: tabular-nums;
&.weekday {
height: 1rem;
margin-bottom: 0;
}
- &.clickable {
- cursor: var(--custom-cursor, pointer);
-
- &:hover {
- background-color: var(--color-interactive-element-hover);
- }
-
- &.selected {
- color: white;
- background-color: var(--color-primary);
- }
- }
-
- &.disabled {
- pointer-events: none;
- opacity: 0.25;
- }
-
- span {
- position: absolute;
- top: 0;
- left: 0;
-
- display: flex;
- align-items: center;
- justify-content: center;
-
- width: 100%;
- height: 100%;
-
- font-size: 0.875rem;
- }
-
- @media (max-width: 600px) {
- margin: 0.25rem 0.375rem;
+ &.selected {
+ --button-text-color: revert-layer;
}
}
@@ -163,12 +121,15 @@
justify-content: center;
min-height: 17rem;
- margin: 1.5rem -0.5rem 0.5rem;
+ margin: 0rem -0.5rem 1rem;
}
.calendar-grid {
display: grid;
+ grid-auto-rows: 1fr;
grid-template-columns: repeat(7, 1fr);
+ place-items: center;
+
width: 100%;
}
}
diff --git a/src/components/common/CalendarModal.tsx b/src/components/common/CalendarModal.tsx
index 59af3bc02..a2720ba7f 100644
--- a/src/components/common/CalendarModal.tsx
+++ b/src/components/common/CalendarModal.tsx
@@ -203,7 +203,7 @@ const CalendarModal = ({
message: lang('MessageScheduledRepeatPremium'),
action: {
action: 'openPremiumModal',
- payload: { },
+ payload: {},
},
actionText: lang('PremiumMore'),
});
@@ -399,6 +399,8 @@ const CalendarModal = ({
color="translucent"
iconName="previous"
disabled={shouldDisablePrevMonth}
+ noFastClick
+ noPreventDefault
onClick={shouldDisablePrevMonth ? undefined : handlePrevMonth}
/>
@@ -408,6 +410,8 @@ const CalendarModal = ({
color="translucent"
iconName="next"
disabled={shouldDisableNextMonth}
+ noFastClick
+ noPreventDefault
onClick={shouldDisableNextMonth ? undefined : handleNextMonth}
/>
@@ -417,35 +421,53 @@ const CalendarModal = ({
{WEEKDAY_LETTERS.map((day) => (
- {oldLang(day)}
+ {oldLang(day)}
))}
{prevMonthGrid.map((gridDate) => (
-
{gridDate}
- ))}
- {currentMonthGrid.map((gridDate) => (
-
handleDateSelect(gridDate)}
- className={buildClassName(
- 'day-button',
- 'div-button',
- isDisabledDay(
- currentYear, currentMonth, gridDate, minDate, maxDate,
- )
- ? 'disabled'
- : gridDate ? 'clickable' : '',
- selectedDay === formatDay(currentYear, currentMonth, gridDate) && 'selected',
- )}
+
+ {gridDate}
+
))}
+ {currentMonthGrid.map((gridDate) => {
+ const isSelected = selectedDay === formatDay(currentYear, currentMonth, gridDate);
+ return (
+
+ );
+ })}
{nextMonthGrid.map((gridDate) => (
-
{gridDate}
+
))}
diff --git a/src/components/middle/MiddleColumn.scss b/src/components/middle/MiddleColumn.scss
index 25dde4c42..87230de36 100644
--- a/src/components/middle/MiddleColumn.scss
+++ b/src/components/middle/MiddleColumn.scss
@@ -292,8 +292,7 @@
padding-bottom: 1.25rem;
.unpin-all-button {
- color: var(--color-primary);
- text-transform: capitalize;
+ --button-text-color: var(--color-primary);
.icon-unpin {
margin-inline-start: -0.4375rem;
@@ -304,27 +303,6 @@
transition: color 0.15s;
}
-
- @media (hover: hover) {
- &:hover {
- color: var(--color-white);
-
- .icon-unpin {
- color: var(--color-white);
- }
- }
- }
-
- @media (max-width: 600px) {
- &:active,
- &:focus {
- color: var(--color-white);
-
- .icon-unpin {
- color: var(--color-white);
- }
- }
- }
}
.composer-button {
@@ -339,20 +317,7 @@
}
.open-chat-button {
- color: var(--color-primary);
-
- @media (hover: hover) {
- &:hover {
- color: var(--color-white);
- }
- }
-
- @media (max-width: 600px) {
- &:active,
- &:focus {
- color: var(--color-white);
- }
- }
+ --button-text-color: var(--color-primary);
}
.mask-image-disabled &::before {
diff --git a/src/components/middle/MiddleColumn.tsx b/src/components/middle/MiddleColumn.tsx
index 53b80d057..37956c2c1 100644
--- a/src/components/middle/MiddleColumn.tsx
+++ b/src/components/middle/MiddleColumn.tsx
@@ -608,6 +608,7 @@ function MiddleColumn({
fluid
color="secondary"
className="composer-button unpin-all-button"
+ noForcedUpperCase
onClick={handleOpenUnpinModal}
iconName="unpin"
>
diff --git a/src/components/modals/poll/PollModal.tsx b/src/components/modals/poll/PollModal.tsx
index 2e8afefcf..c19c53685 100644
--- a/src/components/modals/poll/PollModal.tsx
+++ b/src/components/modals/poll/PollModal.tsx
@@ -154,7 +154,6 @@ const PollModal = ({
const lang = useLang();
- const questionInputRef = useRef();
const mainButtonRef = useRef();
const optionListRef = useRef();
const durationMenuRef = useRef();
@@ -206,14 +205,6 @@ const PollModal = ({
true,
);
- useEffect(() => {
- if (!isOpen) {
- return;
- }
-
- questionInputRef.current?.focus();
- }, [isOpen]);
-
useEffect(() => {
if (isChannel) {
setIsPublic(false);
@@ -578,11 +569,11 @@ const PollModal = ({
{lang('PollModalQuestionTitle')}
diff --git a/src/components/ui/Button.scss b/src/components/ui/Button.scss
index 2ddb87a5b..db0ebe1c3 100644
--- a/src/components/ui/Button.scss
+++ b/src/components/ui/Button.scss
@@ -27,6 +27,8 @@
@layer ui.button {
.Button {
--premium-gradient: linear-gradient(88.39deg, #6c93ff -2.56%, #976fff 51.27%, #df69d1 107.39%);
+ --button-text-color: white;
+ --button-background-color: transparent;
cursor: var(--custom-cursor, pointer);
@@ -46,11 +48,11 @@
font-weight: var(--font-weight-medium);
line-height: 1.2;
- color: white;
+ color: var(--button-text-color);
text-decoration: none !important;
text-transform: uppercase;
- background-color: transparent;
+ background-color: var(--button-background-color);
background-size: cover;
outline: none !important;
@@ -88,66 +90,71 @@
}
}
+ @include active-styles() {
+ color:
+ var(
+ --button-active-text-color,
+ var(--button-text-color)
+ );
+ background-color:
+ var(
+ --button-active-background-color,
+ var(--button-background-color)
+ );
+ }
+
+ @include no-ripple-styles() {
+ color:
+ var(
+ --button-no-ripple-text-color,
+ var(
+ --button-active-text-color,
+ var(--button-text-color)
+ )
+ );
+ background-color:
+ var(
+ --button-no-ripple-background-color,
+ var(
+ --button-active-background-color,
+ var(--button-background-color)
+ )
+ );
+ }
+
&.primary {
--ripple-color: rgba(0, 0, 0, 0.08);
-
- color: var(--color-white);
- background-color: var(--color-primary);
-
- @include active-styles() {
- background-color: rgba(var(--color-primary-shade-rgb), 0.9);
- }
-
- @include no-ripple-styles() {
- background-color: var(--color-primary-shade-darker);
- }
+ --button-text-color: var(--color-white);
+ --button-background-color: var(--color-primary);
+ --button-active-text-color: var(--color-white);
+ --button-active-background-color: rgba(var(--color-primary-shade-rgb), 0.9);
+ --button-no-ripple-background-color: var(--color-primary-shade-darker);
}
&.secondary {
--ripple-color: rgba(0, 0, 0, 0.08);
-
- color: rgba(var(--color-text-secondary-rgb), 0.75);
- background-color: var(--color-background);
-
- @include active-styles() {
- color: white;
- background-color: var(--color-primary);
- }
-
- @include no-ripple-styles() {
- background-color: var(--color-primary-shade);
- }
+ --button-text-color: rgba(var(--color-text-secondary-rgb), 0.75);
+ --button-background-color: var(--color-background);
+ --button-active-text-color: white;
+ --button-active-background-color: var(--color-primary);
+ --button-no-ripple-background-color: var(--color-primary-shade);
}
&.gray {
--ripple-color: rgba(0, 0, 0, 0.08);
-
- color: var(--color-text-secondary);
- background-color: var(--color-background);
-
- @include active-styles() {
- color: var(--color-primary);
- }
-
- @include no-ripple-styles() {
- background-color: var(--color-chat-hover);
- }
+ --button-text-color: var(--color-text-secondary);
+ --button-background-color: var(--color-background);
+ --button-active-text-color: var(--color-primary);
+ --button-no-ripple-background-color: var(--color-chat-hover);
}
&.danger {
--ripple-color: rgba(var(--color-error-rgb), 0.16);
-
- color: var(--color-error);
- background-color: var(--color-background);
-
- @include active-styles() {
- color: var(--color-white);
- background-color: var(--color-error);
- }
-
- @include no-ripple-styles() {
- background-color: var(--color-error-shade);
- }
+ --button-text-color: var(--color-error);
+ --button-background-color: var(--color-background);
+ --button-active-text-color: var(--color-white);
+ --button-active-background-color: var(--color-error);
+ --button-no-ripple-background-color: var(--color-error-shade);
}
&.faded {
@@ -165,154 +172,102 @@
&.translucent-primary,
&.translucent {
--ripple-color: var(--color-interactive-element-hover);
-
- color: var(--color-text-secondary);
- background-color: transparent;
-
- @include active-styles() {
- background-color: var(--color-interactive-element-hover);
- }
-
- @include no-ripple-styles() {
- background-color: rgba(var(--color-text-secondary-rgb), 0.16);
- }
+ --button-text-color: var(--color-text-secondary);
+ --button-background-color: transparent;
+ --button-active-background-color: var(--color-interactive-element-hover);
+ --button-no-ripple-background-color: rgba(var(--color-text-secondary-rgb), 0.16);
&.activated {
- color: var(--color-primary);
+ --button-active-text-color: var(--color-primary);
+
+ color: var(--button-active-text-color, var(--color-primary));
}
}
&.translucent-white {
--ripple-color: rgba(255, 255, 255, 0.08);
-
- color: rgba(255, 255, 255, 0.5);
- background-color: transparent;
-
- @include active-styles() {
- color: white;
- background-color: rgba(255, 255, 255, 0.08);
- }
-
- @include no-ripple-styles() {
- background-color: rgba(255, 255, 255, 0.16);
- }
+ --button-text-color: rgba(255, 255, 255, 0.5);
+ --button-background-color: transparent;
+ --button-active-text-color: white;
+ --button-active-background-color: rgba(255, 255, 255, 0.08);
+ --button-no-ripple-background-color: rgba(255, 255, 255, 0.16);
}
&.translucent-black {
--ripple-color: rgba(0, 0, 0, 0.08);
-
- color: rgba(0, 0, 0, 0.8);
- background-color: transparent;
-
- @include active-styles() {
- background-color: rgba(0, 0, 0, 0.08);
- }
-
- @include no-ripple-styles() {
- background-color: rgba(0, 0, 0, 0.16);
- }
+ --button-text-color: rgba(0, 0, 0, 0.8);
+ --button-background-color: transparent;
+ --button-active-background-color: rgba(0, 0, 0, 0.08);
+ --button-no-ripple-background-color: rgba(0, 0, 0, 0.16);
}
&.translucent-primary {
- color: var(--color-primary);
+ --button-text-color: var(--color-primary);
}
&.translucent-bordered {
--ripple-color: rgba(0, 0, 0, 0.08);
+ --button-text-color: var(--accent-color);
+ --button-background-color: transparent;
+ --button-active-text-color: var(--color-white);
+ --button-active-background-color: var(--accent-color);
+ --button-no-ripple-background-color: var(--active-color);
border: 1px solid var(--accent-color);
- color: var(--accent-color);
- background-color: transparent;
-
- @include active-styles() {
- color: var(--color-white);
- background-color: var(--accent-color);
- }
-
- @include no-ripple-styles() {
- background-color: var(--active-color);
- }
}
&.adaptive {
--ripple-color: var(--accent-background-active-color);
-
- color: var(--accent-color);
- background-color: var(--accent-background-color);
-
- @include active-styles() {
- background-color: var(--accent-background-active-color);
- }
-
- @include no-ripple-styles() {
- background-color: var(--accent-background-active-color);
- }
+ --button-text-color: var(--accent-color);
+ --button-background-color: var(--accent-background-color);
+ --button-active-background-color: var(--accent-background-active-color);
+ --button-no-ripple-background-color: var(--accent-background-active-color);
}
&.dark {
--ripple-color: rgba(255, 255, 255, 0.08);
-
- color: white;
- background-color: rgba(0, 0, 0, 0.75);
-
- @include active-styles() {
- color: white;
- background-color: rgba(0, 0, 0, 0.85);
- }
-
- @include no-ripple-styles() {
- background-color: rgba(0, 0, 0, 0.95);
- }
+ --button-text-color: white;
+ --button-background-color: rgba(0, 0, 0, 0.75);
+ --button-active-text-color: white;
+ --button-active-background-color: rgba(0, 0, 0, 0.85);
+ --button-no-ripple-background-color: rgba(0, 0, 0, 0.95);
}
&.green {
--ripple-color: rgba(0, 0, 0, 0.08);
-
- color: var(--color-white);
- background-color: var(--color-green);
-
- @include active-styles() {
- background-color: var(--color-green-darker);
- }
-
- @include no-ripple-styles() {
- background-color: var(--color-green);
- }
+ --button-text-color: var(--color-white);
+ --button-background-color: var(--color-green);
+ --button-active-text-color: var(--color-white);
+ --button-active-background-color: var(--color-green-darker);
+ --button-no-ripple-background-color: var(--color-green);
}
&.stars {
--ripple-color: rgba(0, 0, 0, 0.08);
-
- color: var(--color-white);
- background-color: #ffb727;
+ --button-text-color: var(--color-white);
+ --button-background-color: #ffb727;
+ --button-active-text-color: var(--color-white);
+ --button-active-background-color: #ffb727cc;
+ --button-no-ripple-background-color: #ffb727;
.theme-dark & {
- background-color: #cf8920;
- }
-
- @include active-styles() {
- background-color: #ffb727cc;
- }
-
- @include no-ripple-styles() {
- background-color: #ffb727;
+ --button-background-color: #cf8920;
}
}
&.bluredStarsBadge {
- color: var(--color-white);
+ --button-text-color: var(--color-white);
+
background: rgba(0, 0, 0, 0.2) !important;
backdrop-filter: blur(50px);
}
&.transparentBlured {
- color: white;
- background-color: rgba(255, 255, 255, 0.1);
- backdrop-filter: blur(0.5rem);
+ --button-text-color: white;
+ --button-background-color: rgba(255, 255, 255, 0.1);
+ --button-active-background-color: rgba(255, 255, 255, 0.2);
- &:hover {
- background-color: rgba(255, 255, 255, 0.2);
- }
+ backdrop-filter: blur(0.5rem);
}
&.smaller {
@@ -501,35 +456,23 @@
}
&.text {
- background-color: transparent;
+ --button-background-color: transparent;
&.primary {
- color: var(--color-primary);
- background-color: transparent;
-
- @include active-styles() {
- background-color: rgba(var(--color-primary-shade-rgb), 0.08);
- }
-
- @include no-ripple-styles() {
- background-color: rgba(var(--color-primary-shade-rgb), 0.16);
- }
+ --button-text-color: var(--color-primary);
+ --button-active-text-color: var(--color-primary);
+ --button-active-background-color: rgba(var(--color-primary-shade-rgb), 0.08);
+ --button-no-ripple-background-color: rgba(var(--color-primary-shade-rgb), 0.16);
}
&.secondary {
- color: var(--color-text-secondary);
- background-color: transparent;
+ --button-text-color: var(--color-text-secondary);
}
&.danger {
- @include active-styles() {
- color: var(--color-error);
- background-color: rgba(var(--color-error-rgb), 0.08);
- }
-
- @include no-ripple-styles() {
- background-color: rgba(var(--color-error-rgb), 0.16);
- }
+ --button-active-text-color: var(--color-error);
+ --button-active-background-color: rgba(var(--color-error-rgb), 0.08);
+ --button-no-ripple-background-color: rgba(var(--color-error-rgb), 0.16);
}
}
}
diff --git a/src/components/ui/Button.tsx b/src/components/ui/Button.tsx
index 3f6b2ad64..c3e473a24 100644
--- a/src/components/ui/Button.tsx
+++ b/src/components/ui/Button.tsx
@@ -40,6 +40,7 @@ export type OwnProps = {
isLoading?: boolean;
ariaLabel?: string;
ariaControls?: string;
+ ariaSelected?: boolean;
hasPopup?: boolean;
href?: string;
download?: string;
@@ -60,6 +61,7 @@ export type OwnProps = {
noForcedUpperCase?: boolean;
shouldStopPropagation?: boolean;
style?: string;
+ autoFocus?: boolean;
iconName?: IconName;
iconAlignment?: 'top' | 'bottom' | 'start' | 'end';
iconClassName?: string;
@@ -98,6 +100,7 @@ const Button = ({
noSparkleAnimation,
ariaLabel,
ariaControls,
+ ariaSelected,
hasPopup,
href,
download,
@@ -114,6 +117,7 @@ const Button = ({
shouldStopPropagation,
noForcedUpperCase,
style,
+ autoFocus,
iconName,
iconAlignment = 'start',
iconClassName,
@@ -241,6 +245,7 @@ const Button = ({
title={ariaLabel}
download={download}
tabIndex={tabIndex}
+ autoFocus={autoFocus}
dir={isRtl ? 'rtl' : undefined}
aria-label={ariaLabel}
aria-controls={ariaControls}
@@ -268,9 +273,12 @@ const Button = ({
onMouseLeave={onMouseLeave && !isNotInteractive ? onMouseLeave : undefined}
onTransitionEnd={onTransitionEnd}
onFocus={onFocus && !isNotInteractive ? onFocus : undefined}
+ disabled={disabled}
+ autoFocus={autoFocus}
aria-label={ariaLabel}
aria-controls={ariaControls}
aria-haspopup={hasPopup}
+ aria-selected={ariaSelected}
title={ariaLabel}
tabIndex={tabIndex}
dir={isRtl ? 'rtl' : undefined}
diff --git a/src/components/ui/ConfirmDialog.tsx b/src/components/ui/ConfirmDialog.tsx
index 172d5d7b3..93e1a606e 100644
--- a/src/components/ui/ConfirmDialog.tsx
+++ b/src/components/ui/ConfirmDialog.tsx
@@ -68,6 +68,7 @@ const ConfirmDialog: FC = ({
onClose={onClose}
isNativeDialog
onCloseAnimationEnd={onCloseAnimationEnd}
+ noTitleAutoFocus
>
{text && text.split('\\n').map((textPart) => (
{textPart}
@@ -85,10 +86,15 @@ const ConfirmDialog: FC = ({
onClick={confirmHandler}
color={confirmIsDestructive ? 'danger' : 'primary'}
disabled={isConfirmDisabled}
+ autoFocus={!confirmIsDestructive}
>
{confirmLabel || lang('GeneralConfirm')}
- {!isOnlyConfirm && }
+ {!isOnlyConfirm && (
+
+ )}
);
diff --git a/src/components/ui/InputText.tsx b/src/components/ui/InputText.tsx
index 1172be09f..97bfbd8fb 100644
--- a/src/components/ui/InputText.tsx
+++ b/src/components/ui/InputText.tsx
@@ -24,6 +24,7 @@ type OwnProps = {
maxLength?: number;
tabIndex?: number;
title?: string;
+ autoFocus?: boolean;
teactExperimentControlled?: boolean;
inputMode?: 'text' | 'none' | 'tel' | 'url' | 'email' | 'numeric' | 'decimal' | 'search';
onChange?: (e: ChangeEvent) => void;
@@ -51,6 +52,7 @@ const InputText = ({
maxLength,
tabIndex,
title,
+ autoFocus,
teactExperimentControlled,
onChange,
onInput,
@@ -99,6 +101,7 @@ const InputText = ({
title={title}
teactExperimentControlled={teactExperimentControlled}
onClick={onClick}
+ autoFocus={autoFocus}
/>
{labelText && (
diff --git a/src/components/ui/Modal.tsx b/src/components/ui/Modal.tsx
index 32acffd2d..b94b02c92 100644
--- a/src/components/ui/Modal.tsx
+++ b/src/components/ui/Modal.tsx
@@ -44,6 +44,7 @@ export type OwnProps = {
noBackdrop?: boolean;
noBackdropClose?: boolean;
isNativeDialog?: boolean;
+ noTitleAutoFocus?: boolean;
children: React.ReactNode;
style?: string;
dialogStyle?: string;
@@ -68,6 +69,7 @@ const Modal = (props: OwnProps) => {
noBackdropClose,
noFreezeOnClose,
isNativeDialog,
+ noTitleAutoFocus,
onClose,
onCloseAnimationEnd,
onEnter,
@@ -251,7 +253,7 @@ const Modal = (props: OwnProps) => {
return title ? (
{closeButton}
-
{title}
+
{title}
) : closeButton;
}
diff --git a/src/lib/teact/teact-dom.ts b/src/lib/teact/teact-dom.ts
index b4cc921dc..6138efff3 100644
--- a/src/lib/teact/teact-dom.ts
+++ b/src/lib/teact/teact-dom.ts
@@ -52,6 +52,7 @@ const MAPPED_ATTRIBUTES: Partial> = {
autoCorrect: 'autocorrect',
autoPlay: 'autoplay',
spellCheck: 'spellcheck',
+ autoFocus: 'autofocus',
};
const INDEX_KEY_PREFIX = '__indexKey#';
const SELECTION_STATE_ATTRIBUTE = '__teactSelectionState';