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';