Merge pull request #17702 from overleaf/ii-bs5-to-bs3-classname-helper

[web] Bootstrap class name helper

GitOrigin-RevId: 9c2042aa2ea0e4d3828b32c321336e1c3a4a0ef8
This commit is contained in:
ilkin-overleaf 2024-04-03 14:01:56 +03:00 committed by Copybot
parent c22e6a5926
commit a9436039b6
7 changed files with 86 additions and 12 deletions

View file

@ -18,6 +18,7 @@ import { isValidEmail } from '../../../../shared/utils/email'
import getMeta from '../../../../utils/meta' import getMeta from '../../../../utils/meta'
import { ReCaptcha2 } from '../../../../shared/components/recaptcha-2' import { ReCaptcha2 } from '../../../../shared/components/recaptcha-2'
import { useRecaptcha } from '../../../../shared/hooks/use-recaptcha' import { useRecaptcha } from '../../../../shared/hooks/use-recaptcha'
import { bsClassName } from '@/features/utils/bootstrap-5'
function AddEmail() { function AddEmail() {
const { t } = useTranslation() const { t } = useTranslation()
@ -133,7 +134,10 @@ function AddEmail() {
const InputComponent = ( const InputComponent = (
<> <>
<label htmlFor="affiliations-email" className="sr-only"> <label
htmlFor="affiliations-email"
className={bsClassName({ bs5: 'visually-hidden', bs3: 'sr-only' })}
>
{t('email')} {t('email')}
</label> </label>
<Input <Input
@ -157,7 +161,12 @@ function AddEmail() {
</Cell> </Cell>
</Col> </Col>
<Col md={4}> <Col md={4}>
<Cell className="text-md-right"> <Cell
className={bsClassName({
bs5: 'text-md-end',
bs3: 'text-md-right',
})}
>
<AddNewEmailBtn email={newEmail} disabled /> <AddNewEmailBtn email={newEmail} disabled />
</Cell> </Cell>
</Col> </Col>
@ -197,7 +206,12 @@ function AddEmail() {
</Col> </Col>
{!isSsoAvailableForDomain ? ( {!isSsoAvailableForDomain ? (
<Col md={4}> <Col md={4}>
<Cell className="text-md-right"> <Cell
className={bsClassName({
bs5: 'text-md-end',
bs3: 'text-md-right',
})}
>
<AddNewEmailBtn <AddNewEmailBtn
email={newEmail} email={newEmail}
disabled={isLoading || state.isLoading} disabled={isLoading || state.isLoading}

View file

@ -3,6 +3,7 @@ import { useTranslation } from 'react-i18next'
import { useCombobox } from 'downshift' import { useCombobox } from 'downshift'
import classnames from 'classnames' import classnames from 'classnames'
import countries, { CountryCode } from '../../../data/countries-list' import countries, { CountryCode } from '../../../data/countries-list'
import { bsClassName } from '@/features/utils/bootstrap-5'
type CountryInputProps = { type CountryInputProps = {
setValue: React.Dispatch<React.SetStateAction<CountryCode | null>> setValue: React.Dispatch<React.SetStateAction<CountryCode | null>>
@ -55,7 +56,10 @@ function Downshift({ setValue, inputRef }: CountryInputProps) {
> >
<div {...getComboboxProps()} className="ui-select-toggle"> <div {...getComboboxProps()} className="ui-select-toggle">
{/* eslint-disable-next-line jsx-a11y/label-has-for */} {/* eslint-disable-next-line jsx-a11y/label-has-for */}
<label {...getLabelProps()} className="sr-only"> <label
{...getLabelProps()}
className={bsClassName({ bs5: 'visually-hidden', bs3: 'sr-only' })}
>
{t('country')} {t('country')}
</label> </label>
<input <input

View file

@ -2,6 +2,7 @@ import { useState, useEffect, forwardRef } from 'react'
import { useCombobox } from 'downshift' import { useCombobox } from 'downshift'
import classnames from 'classnames' import classnames from 'classnames'
import { escapeRegExp } from 'lodash' import { escapeRegExp } from 'lodash'
import { bsClassName } from '@/features/utils/bootstrap-5'
type DownshiftInputProps = { type DownshiftInputProps = {
highlightMatches?: boolean highlightMatches?: boolean
@ -86,7 +87,14 @@ function Downshift({
> >
<div {...getComboboxProps()}> <div {...getComboboxProps()}>
{/* eslint-disable-next-line jsx-a11y/label-has-for */} {/* eslint-disable-next-line jsx-a11y/label-has-for */}
<label {...getLabelProps()} className={showLabel ? '' : 'sr-only'}> <label
{...getLabelProps()}
className={
showLabel
? ''
: bsClassName({ bs5: 'visually-hidden', bs3: 'sr-only' })
}
>
{label} {label}
</label> </label>
<input <input

View file

@ -1,6 +1,8 @@
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import { Row, Col } from 'react-bootstrap' import { Row, Col } from 'react-bootstrap'
import EmailCell from './cell' import EmailCell from './cell'
import classnames from 'classnames'
import { bsClassName } from '@/features/utils/bootstrap-5'
function Header() { function Header() {
const { t } = useTranslation() const { t } = useTranslation()
@ -8,19 +10,41 @@ function Header() {
return ( return (
<> <>
<Row> <Row>
<Col md={4} className="hidden-xs"> <Col
md={4}
className={bsClassName({
bs5: 'd-none d-sm-block',
bs3: 'hidden-xs',
})}
>
<EmailCell> <EmailCell>
<strong>{t('email')}</strong> <strong>{t('email')}</strong>
</EmailCell> </EmailCell>
</Col> </Col>
<Col md={8} className="hidden-xs"> <Col
md={8}
className={bsClassName({
bs5: 'd-none d-sm-block',
bs3: 'hidden-xs',
})}
>
<EmailCell> <EmailCell>
<strong>{t('institution_and_role')}</strong> <strong>{t('institution_and_role')}</strong>
</EmailCell> </EmailCell>
</Col> </Col>
</Row> </Row>
<div className="hidden-xs horizontal-divider" /> <div
<div className="hidden-xs horizontal-divider" /> className={classnames(
bsClassName({ bs5: 'd-none d-sm-block', bs3: 'hidden-xs' }),
'horizontal-divider'
)}
/>
<div
className={classnames(
bsClassName({ bs5: 'd-none d-sm-block', bs3: 'hidden-xs' }),
'horizontal-divider'
)}
/>
</> </>
) )
} }

View file

@ -13,6 +13,7 @@ import { ExposedSettings } from '../../../../../../types/exposed-settings'
import { ssoAvailableForInstitution } from '../../utils/sso' import { ssoAvailableForInstitution } from '../../utils/sso'
import ReconfirmationInfo from './reconfirmation-info' import ReconfirmationInfo from './reconfirmation-info'
import { useLocation } from '../../../../shared/hooks/use-location' import { useLocation } from '../../../../shared/hooks/use-location'
import { bsClassName } from '@/features/utils/bootstrap-5'
type EmailsRowProps = { type EmailsRowProps = {
userEmailData: UserEmailData userEmailData: UserEmailData
@ -40,7 +41,12 @@ function EmailsRow({ userEmailData }: EmailsRowProps) {
)} )}
</Col> </Col>
<Col md={3}> <Col md={3}>
<EmailCell className="text-md-right"> <EmailCell
className={bsClassName({
bs5: 'text-md-end',
bs3: 'text-md-right',
})}
>
<Actions userEmailData={userEmailData} /> <Actions userEmailData={userEmailData} />
</EmailCell> </EmailCell>
</Col> </Col>
@ -144,7 +150,13 @@ function SSOAffiliationInfo({ userEmailData }: SSOAffiliationInfoProps) {
</p> </p>
</EmailCell> </EmailCell>
</Col> </Col>
<Col md={3} className="text-md-right"> <Col
md={3}
className={bsClassName({
bs5: 'text-md-end',
bs3: 'text-md-right',
})}
>
<EmailCell> <EmailCell>
<Button <Button
bsStyle="primary" bsStyle="primary"

View file

@ -0,0 +1,7 @@
import getMeta from '@/utils/meta'
export const isBootstrap5 = getMeta('ol-bootstrapVersion') === 5
export const bsClassName = ({ bs5, bs3 }: { bs5: string; bs3: string }) => {
return isBootstrap5 ? bs5 : bs3
}

View file

@ -1,4 +1,5 @@
import classNames from 'classnames' import classNames from 'classnames'
import { bsClassName } from '@/features/utils/bootstrap-5'
type IconOwnProps = { type IconOwnProps = {
type: string type: string
@ -35,7 +36,11 @@ function Icon({
<> <>
<i className={iconClassName} aria-hidden="true" {...rest} /> <i className={iconClassName} aria-hidden="true" {...rest} />
{accessibilityLabel && ( {accessibilityLabel && (
<span className="sr-only">{accessibilityLabel}</span> <span
className={bsClassName({ bs5: 'visually-hidden', bs3: 'sr-only' })}
>
{accessibilityLabel}
</span>
)} )}
</> </>
) )