mirror of
https://github.com/overleaf/overleaf.git
synced 2024-11-21 20:47:08 -05:00
Merge pull request #19366 from overleaf/ii-bs5-projects-list-search
[web] BS5 projects list search GitOrigin-RevId: e2545f43ac3a50e58f7e97a2038e5b768c909e4f
This commit is contained in:
parent
f54b257022
commit
0a23c55c93
15 changed files with 455 additions and 191 deletions
|
@ -102,7 +102,7 @@ export default function CloneProjectModalContent({
|
|||
{clonedProjectTags.length > 0 && (
|
||||
<OLFormGroup
|
||||
controlId="clone-project-tags-list"
|
||||
className="clone-project-tag mb-3"
|
||||
className="clone-project-tag"
|
||||
>
|
||||
<OLFormLabel>{t('tags')}: </OLFormLabel>
|
||||
<div role="listbox" id="clone-project-tags-list">
|
||||
|
|
|
@ -97,7 +97,6 @@ function ProjectListPageContent() {
|
|||
filter={filter}
|
||||
selectedTag={selectedTag}
|
||||
className="overflow-hidden"
|
||||
formGroupProps={{ className: 'mb-0' }}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,36 +1,38 @@
|
|||
import { useTranslation } from 'react-i18next'
|
||||
import {
|
||||
Form,
|
||||
FormGroup,
|
||||
FormGroupProps,
|
||||
Col,
|
||||
FormControl,
|
||||
} from 'react-bootstrap'
|
||||
import { FormControl } from 'react-bootstrap'
|
||||
import Icon from '../../../shared/components/icon'
|
||||
import * as eventTracking from '../../../infrastructure/event-tracking'
|
||||
import classnames from 'classnames'
|
||||
import { Tag } from '../../../../../app/src/Features/Tags/types'
|
||||
import { MergeAndOverride } from '../../../../../types/utils'
|
||||
import { Filter } from '../context/project-list-context'
|
||||
import { isSmallDevice } from '../../../infrastructure/event-tracking'
|
||||
import OLForm from '@/features/ui/components/ol/ol-form'
|
||||
import OLFormGroup from '@/features/ui/components/ol/ol-form-group'
|
||||
import OLCol from '@/features/ui/components/ol/ol-col'
|
||||
import OLFormControl from '@/features/ui/components/ol/ol-form-control'
|
||||
import MaterialIcon from '@/shared/components/material-icon'
|
||||
import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher'
|
||||
import { bsVersion } from '@/features/utils/bootstrap-5'
|
||||
|
||||
type SearchFormOwnProps = {
|
||||
inputValue: string
|
||||
setInputValue: (input: string) => void
|
||||
filter: Filter
|
||||
selectedTag: Tag | undefined
|
||||
formGroupProps?: FormGroupProps &
|
||||
Omit<React.ComponentProps<'div'>, keyof FormGroupProps>
|
||||
}
|
||||
|
||||
type SearchFormProps = SearchFormOwnProps &
|
||||
Omit<React.ComponentProps<typeof Form>, keyof SearchFormOwnProps>
|
||||
type SearchFormProps = MergeAndOverride<
|
||||
React.ComponentProps<typeof OLForm>,
|
||||
SearchFormOwnProps
|
||||
>
|
||||
|
||||
function SearchForm({
|
||||
inputValue,
|
||||
setInputValue,
|
||||
filter,
|
||||
selectedTag,
|
||||
formGroupProps,
|
||||
className,
|
||||
...props
|
||||
}: SearchFormProps) {
|
||||
const { t } = useTranslation()
|
||||
|
@ -57,8 +59,6 @@ function SearchForm({
|
|||
}
|
||||
}
|
||||
const placeholder = `${placeholderMessage}…`
|
||||
const { className: formGroupClassName, ...restFormGroupProps } =
|
||||
formGroupProps || {}
|
||||
|
||||
const handleChange = (
|
||||
e: React.ChangeEvent<
|
||||
|
@ -75,44 +75,49 @@ function SearchForm({
|
|||
const handleClear = () => setInputValue('')
|
||||
|
||||
return (
|
||||
<Form
|
||||
horizontal
|
||||
className="project-search"
|
||||
<OLForm
|
||||
className={classnames('project-search', className)}
|
||||
role="search"
|
||||
onSubmit={e => e.preventDefault()}
|
||||
bs3Props={{ horizontal: true }}
|
||||
{...props}
|
||||
>
|
||||
<FormGroup
|
||||
className={classnames(
|
||||
'has-feedback has-feedback-left',
|
||||
formGroupClassName
|
||||
)}
|
||||
{...restFormGroupProps}
|
||||
<OLFormGroup
|
||||
className={bsVersion({ bs3: 'has-feedback has-feedback-left' })}
|
||||
>
|
||||
<Col xs={12}>
|
||||
<FormControl
|
||||
<OLCol>
|
||||
<OLFormControl
|
||||
type="text"
|
||||
value={inputValue}
|
||||
onChange={handleChange}
|
||||
placeholder={placeholder}
|
||||
aria-label={placeholder}
|
||||
prepend={BootstrapVersionSwitcher({
|
||||
bs3: <Icon type="search" />,
|
||||
bs5: <MaterialIcon type="search" />,
|
||||
})}
|
||||
append={
|
||||
inputValue.length > 0 && (
|
||||
<button
|
||||
type="button"
|
||||
className={bsVersion({
|
||||
bs3: 'project-search-clear-btn btn-link',
|
||||
bs5: 'project-search-clear-btn',
|
||||
})}
|
||||
aria-label={t('clear_search')}
|
||||
onClick={handleClear}
|
||||
>
|
||||
<BootstrapVersionSwitcher
|
||||
bs3={<Icon type="times" />}
|
||||
bs5={<MaterialIcon type="clear" />}
|
||||
/>
|
||||
</button>
|
||||
)
|
||||
}
|
||||
/>
|
||||
<Icon type="search" className="form-control-feedback-left" />
|
||||
{inputValue.length ? (
|
||||
<div className="form-control-feedback">
|
||||
<button
|
||||
type="button"
|
||||
className="project-search-clear-btn btn-link"
|
||||
aria-label={t('clear_search')}
|
||||
onClick={handleClear}
|
||||
>
|
||||
<Icon type="times" />
|
||||
</button>
|
||||
</div>
|
||||
) : null}
|
||||
</Col>
|
||||
</FormGroup>
|
||||
</Form>
|
||||
</OLCol>
|
||||
</OLFormGroup>
|
||||
</OLForm>
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
import {
|
||||
FormControl as BS3FormControl,
|
||||
FormControlProps as BS3FormControlProps,
|
||||
} from 'react-bootstrap'
|
||||
|
||||
type FormControlProps = BS3FormControlProps & {
|
||||
prepend?: React.ReactNode
|
||||
append?: React.ReactNode
|
||||
}
|
||||
|
||||
function FormControl({
|
||||
prepend,
|
||||
append,
|
||||
className,
|
||||
...props
|
||||
}: FormControlProps) {
|
||||
return (
|
||||
<>
|
||||
{prepend && <div className="form-control-feedback-left">{prepend}</div>}
|
||||
<BS3FormControl {...props} />
|
||||
{append && <div className="form-control-feedback">{append}</div>}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default FormControl
|
|
@ -0,0 +1,44 @@
|
|||
import { forwardRef } from 'react'
|
||||
import { Form, FormControlProps } from 'react-bootstrap-5'
|
||||
import classnames from 'classnames'
|
||||
|
||||
type OLFormControlProps = FormControlProps & {
|
||||
prepend?: React.ReactNode
|
||||
append?: React.ReactNode
|
||||
}
|
||||
|
||||
const FormControl = forwardRef<HTMLInputElement, OLFormControlProps>(
|
||||
({ prepend, append, className, ...props }, ref) => {
|
||||
if (prepend || append) {
|
||||
const wrapperClassNames = classnames('form-control-wrapper', {
|
||||
'form-control-wrapper-sm': props.size === 'sm',
|
||||
'form-control-wrapper-lg': props.size === 'lg',
|
||||
'form-control-wrapper-disabled': props.disabled,
|
||||
})
|
||||
|
||||
const formControlClassNames = classnames(className, {
|
||||
'form-control-offset-start': prepend,
|
||||
'form-control-offset-end': append,
|
||||
})
|
||||
|
||||
return (
|
||||
<div className={wrapperClassNames}>
|
||||
{prepend && (
|
||||
<span className="form-control-start-icon">{prepend}</span>
|
||||
)}
|
||||
<Form.Control
|
||||
{...props}
|
||||
className={formControlClassNames}
|
||||
ref={ref}
|
||||
/>
|
||||
{append && <span className="form-control-end-icon">{append}</span>}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
return <Form.Control {...props} />
|
||||
}
|
||||
)
|
||||
FormControl.displayName = 'FormControl'
|
||||
|
||||
export default FormControl
|
|
@ -0,0 +1,14 @@
|
|||
import { forwardRef } from 'react'
|
||||
import { FormGroup as BS5FormGroup, FormGroupProps } from 'react-bootstrap-5'
|
||||
import classnames from 'classnames'
|
||||
|
||||
const FormGroup = forwardRef<typeof BS5FormGroup, FormGroupProps>(
|
||||
({ className, ...props }, ref) => {
|
||||
const classNames = classnames('form-group', className)
|
||||
|
||||
return <BS5FormGroup className={classNames} {...props} ref={ref} />
|
||||
}
|
||||
)
|
||||
FormGroup.displayName = 'FormGroup'
|
||||
|
||||
export default FormGroup
|
|
@ -1,11 +1,12 @@
|
|||
import { forwardRef } from 'react'
|
||||
import { Form } from 'react-bootstrap-5'
|
||||
import { FormControl as BS3FormControl } from 'react-bootstrap'
|
||||
import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher'
|
||||
import { getAriaAndDataProps } from '@/features/utils/bootstrap-5'
|
||||
import BS3FormControl from '@/features/ui/components/bootstrap-3/form/form-control'
|
||||
import FormControl from '@/features/ui/components/bootstrap-5/form/form-control'
|
||||
import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher'
|
||||
|
||||
type OLFormControlProps = React.ComponentProps<(typeof Form)['Control']> & {
|
||||
type OLFormControlProps = React.ComponentProps<typeof FormControl> & {
|
||||
bs3Props?: Record<string, unknown>
|
||||
'data-ol-dirty'?: unknown
|
||||
}
|
||||
|
||||
const OLFormControl = forwardRef<HTMLInputElement, OLFormControlProps>(
|
||||
|
@ -37,6 +38,8 @@ const OLFormControl = forwardRef<HTMLInputElement, OLFormControlProps>(
|
|||
ref.current = inputElement
|
||||
}
|
||||
},
|
||||
prepend: rest.prepend,
|
||||
append: rest.append,
|
||||
...bs3Props,
|
||||
}
|
||||
|
||||
|
@ -49,7 +52,7 @@ const OLFormControl = forwardRef<HTMLInputElement, OLFormControlProps>(
|
|||
return (
|
||||
<BootstrapVersionSwitcher
|
||||
bs3={<BS3FormControl {...bs3FormControlProps} />}
|
||||
bs5={<Form.Control ref={ref} {...rest} />}
|
||||
bs5={<FormControl ref={ref} {...rest} />}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -1,27 +1,26 @@
|
|||
import { Form } from 'react-bootstrap-5'
|
||||
import { FormGroupProps } from 'react-bootstrap-5'
|
||||
import { FormGroup as BS3FormGroup } from 'react-bootstrap'
|
||||
import FormGroup from '@/features/ui/components/bootstrap-5/form/form-group'
|
||||
import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher'
|
||||
|
||||
type OLFormGroupProps = React.ComponentProps<(typeof Form)['Group']> & {
|
||||
type OLFormGroupProps = FormGroupProps & {
|
||||
bs3Props?: Record<string, unknown>
|
||||
}
|
||||
|
||||
function OLFormGroup(props: OLFormGroupProps) {
|
||||
const { bs3Props, className, ...rest } = props
|
||||
|
||||
const classNames = className ?? 'mb-3'
|
||||
const { bs3Props, ...rest } = props
|
||||
|
||||
const bs3FormGroupProps: React.ComponentProps<typeof BS3FormGroup> = {
|
||||
children: rest.children,
|
||||
controlId: rest.controlId,
|
||||
className,
|
||||
className: rest.className,
|
||||
...bs3Props,
|
||||
}
|
||||
|
||||
return (
|
||||
<BootstrapVersionSwitcher
|
||||
bs3={<BS3FormGroup {...bs3FormGroupProps} />}
|
||||
bs5={<Form.Group className={classNames} {...rest} />}
|
||||
bs5={<FormGroup {...rest} />}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -11,10 +11,11 @@ function OLForm(props: OLFormProps) {
|
|||
|
||||
const bs3FormProps: React.ComponentProps<typeof BS3Form> = {
|
||||
componentClass: rest.as,
|
||||
bsClass: rest.className,
|
||||
children: rest.children,
|
||||
id: rest.id,
|
||||
onSubmit: rest.onSubmit as React.FormEventHandler<BS3Form> | undefined,
|
||||
className: rest.className,
|
||||
role: rest.role,
|
||||
...bs3Props,
|
||||
}
|
||||
|
||||
|
|
|
@ -1,39 +1,42 @@
|
|||
import { Form } from 'react-bootstrap-5'
|
||||
import type { Meta, StoryObj } from '@storybook/react'
|
||||
import FormGroup from '@/features/ui/components/bootstrap-5/form/form-group'
|
||||
import FormText from '@/features/ui/components/bootstrap-5/form/form-text'
|
||||
import FormControl from '@/features/ui/components/bootstrap-5/form/form-control'
|
||||
import MaterialIcon from '@/shared/components/material-icon'
|
||||
|
||||
const meta: Meta<(typeof Form)['Control']> = {
|
||||
const meta: Meta<React.ComponentProps<typeof FormControl>> = {
|
||||
title: 'Shared / Components / Bootstrap 5 / Form / Input',
|
||||
component: Form.Control,
|
||||
component: FormControl,
|
||||
parameters: {
|
||||
bootstrap5: true,
|
||||
},
|
||||
}
|
||||
export default meta
|
||||
|
||||
type Story = StoryObj<(typeof Form)['Control']>
|
||||
type Story = StoryObj<React.ComponentProps<typeof FormControl>>
|
||||
|
||||
export const Default: Story = {
|
||||
render: args => {
|
||||
return (
|
||||
<>
|
||||
<Form.Group controlId="id-1">
|
||||
<FormGroup controlId="id-1">
|
||||
<Form.Label>Label</Form.Label>
|
||||
<Form.Control defaultValue="Large input" size="lg" {...args} />
|
||||
<FormControl defaultValue="Large input" size="lg" {...args} />
|
||||
<FormText>Helper</FormText>
|
||||
</Form.Group>
|
||||
</FormGroup>
|
||||
<hr />
|
||||
<Form.Group controlId="id-2">
|
||||
<FormGroup controlId="id-2">
|
||||
<Form.Label>Label</Form.Label>
|
||||
<Form.Control defaultValue="Regular input" {...args} />
|
||||
<FormControl defaultValue="Regular input" {...args} />
|
||||
<FormText>Helper</FormText>
|
||||
</Form.Group>
|
||||
</FormGroup>
|
||||
<hr />
|
||||
<Form.Group controlId="id-3">
|
||||
<FormGroup controlId="id-3">
|
||||
<Form.Label>Label</Form.Label>
|
||||
<Form.Control defaultValue="Small input" size="sm" {...args} />
|
||||
<FormControl defaultValue="Small input" size="sm" {...args} />
|
||||
<FormText>Helper</FormText>
|
||||
</Form.Group>
|
||||
</FormGroup>
|
||||
</>
|
||||
)
|
||||
},
|
||||
|
@ -46,37 +49,37 @@ export const Info: Story = {
|
|||
render: args => {
|
||||
return (
|
||||
<>
|
||||
<Form.Group controlId="id-1">
|
||||
<FormGroup controlId="id-1">
|
||||
<Form.Label>Label</Form.Label>
|
||||
<Form.Control
|
||||
<FormControl
|
||||
placeholder="Placeholder"
|
||||
defaultValue="Large input"
|
||||
size="lg"
|
||||
{...args}
|
||||
/>
|
||||
<FormText isInfo>Info</FormText>
|
||||
</Form.Group>
|
||||
</FormGroup>
|
||||
<hr />
|
||||
<Form.Group controlId="id-2">
|
||||
<FormGroup controlId="id-2">
|
||||
<Form.Label>Label</Form.Label>
|
||||
<Form.Control
|
||||
<FormControl
|
||||
placeholder="Placeholder"
|
||||
defaultValue="Regular input"
|
||||
{...args}
|
||||
/>
|
||||
<FormText isInfo>Info</FormText>
|
||||
</Form.Group>
|
||||
</FormGroup>
|
||||
<hr />
|
||||
<Form.Group controlId="id-3">
|
||||
<FormGroup controlId="id-3">
|
||||
<Form.Label>Label</Form.Label>
|
||||
<Form.Control
|
||||
<FormControl
|
||||
placeholder="Placeholder"
|
||||
defaultValue="Small input"
|
||||
size="sm"
|
||||
{...args}
|
||||
/>
|
||||
<FormText isInfo>Info</FormText>
|
||||
</Form.Group>
|
||||
</FormGroup>
|
||||
</>
|
||||
)
|
||||
},
|
||||
|
@ -86,9 +89,9 @@ export const Error: Story = {
|
|||
render: args => {
|
||||
return (
|
||||
<>
|
||||
<Form.Group controlId="id-1">
|
||||
<FormGroup controlId="id-1">
|
||||
<Form.Label>Label</Form.Label>
|
||||
<Form.Control
|
||||
<FormControl
|
||||
placeholder="Placeholder"
|
||||
defaultValue="Large input"
|
||||
size="lg"
|
||||
|
@ -96,22 +99,22 @@ export const Error: Story = {
|
|||
{...args}
|
||||
/>
|
||||
<FormText isError>Error</FormText>
|
||||
</Form.Group>
|
||||
</FormGroup>
|
||||
<hr />
|
||||
<Form.Group controlId="id-2">
|
||||
<FormGroup controlId="id-2">
|
||||
<Form.Label>Label</Form.Label>
|
||||
<Form.Control
|
||||
<FormControl
|
||||
placeholder="Placeholder"
|
||||
defaultValue="Regular input"
|
||||
isInvalid
|
||||
{...args}
|
||||
/>
|
||||
<FormText isError>Error</FormText>
|
||||
</Form.Group>
|
||||
</FormGroup>
|
||||
<hr />
|
||||
<Form.Group controlId="id-3">
|
||||
<FormGroup controlId="id-3">
|
||||
<Form.Label>Label</Form.Label>
|
||||
<Form.Control
|
||||
<FormControl
|
||||
placeholder="Placeholder"
|
||||
defaultValue="Small input"
|
||||
size="sm"
|
||||
|
@ -119,7 +122,7 @@ export const Error: Story = {
|
|||
{...args}
|
||||
/>
|
||||
<FormText isError>Error</FormText>
|
||||
</Form.Group>
|
||||
</FormGroup>
|
||||
</>
|
||||
)
|
||||
},
|
||||
|
@ -129,37 +132,37 @@ export const Warning: Story = {
|
|||
render: args => {
|
||||
return (
|
||||
<>
|
||||
<Form.Group controlId="id-1">
|
||||
<FormGroup controlId="id-1">
|
||||
<Form.Label>Label</Form.Label>
|
||||
<Form.Control
|
||||
<FormControl
|
||||
placeholder="Placeholder"
|
||||
defaultValue="Large input"
|
||||
size="lg"
|
||||
{...args}
|
||||
/>
|
||||
<FormText isWarning>Warning</FormText>
|
||||
</Form.Group>
|
||||
</FormGroup>
|
||||
<hr />
|
||||
<Form.Group controlId="id-2">
|
||||
<FormGroup controlId="id-2">
|
||||
<Form.Label>Label</Form.Label>
|
||||
<Form.Control
|
||||
<FormControl
|
||||
placeholder="Placeholder"
|
||||
defaultValue="Regular input"
|
||||
{...args}
|
||||
/>
|
||||
<FormText isWarning>Warning</FormText>
|
||||
</Form.Group>
|
||||
</FormGroup>
|
||||
<hr />
|
||||
<Form.Group controlId="id-3">
|
||||
<FormGroup controlId="id-3">
|
||||
<Form.Label>Label</Form.Label>
|
||||
<Form.Control
|
||||
<FormControl
|
||||
placeholder="Placeholder"
|
||||
defaultValue="Small input"
|
||||
size="sm"
|
||||
{...args}
|
||||
/>
|
||||
<FormText isWarning>Warning</FormText>
|
||||
</Form.Group>
|
||||
</FormGroup>
|
||||
</>
|
||||
)
|
||||
},
|
||||
|
@ -169,37 +172,130 @@ export const Success: Story = {
|
|||
render: args => {
|
||||
return (
|
||||
<>
|
||||
<Form.Group controlId="id-1">
|
||||
<FormGroup controlId="id-1">
|
||||
<Form.Label>Label</Form.Label>
|
||||
<Form.Control
|
||||
<FormControl
|
||||
placeholder="Placeholder"
|
||||
defaultValue="Large input"
|
||||
size="lg"
|
||||
{...args}
|
||||
/>
|
||||
<FormText isSuccess>Success</FormText>
|
||||
</Form.Group>
|
||||
</FormGroup>
|
||||
<hr />
|
||||
<Form.Group controlId="id-2">
|
||||
<FormGroup controlId="id-2">
|
||||
<Form.Label>Label</Form.Label>
|
||||
<Form.Control
|
||||
<FormControl
|
||||
placeholder="Placeholder"
|
||||
defaultValue="Regular input"
|
||||
{...args}
|
||||
/>
|
||||
<FormText isSuccess>Success</FormText>
|
||||
</Form.Group>
|
||||
</FormGroup>
|
||||
<hr />
|
||||
<Form.Group controlId="id-3">
|
||||
<FormGroup controlId="id-3">
|
||||
<Form.Label>Label</Form.Label>
|
||||
<Form.Control
|
||||
<FormControl
|
||||
placeholder="Placeholder"
|
||||
defaultValue="Small input"
|
||||
size="sm"
|
||||
{...args}
|
||||
/>
|
||||
<FormText isSuccess>Success</FormText>
|
||||
</Form.Group>
|
||||
</FormGroup>
|
||||
</>
|
||||
)
|
||||
},
|
||||
}
|
||||
|
||||
export const WithIcons: Story = {
|
||||
render: args => {
|
||||
const handleClear = () => {
|
||||
alert('Clicked clear button')
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<FormGroup controlId="id-1">
|
||||
<Form.Label>Label</Form.Label>
|
||||
<FormControl
|
||||
type="text"
|
||||
placeholder="Search"
|
||||
prepend={<MaterialIcon type="search" />}
|
||||
append={
|
||||
<button
|
||||
type="button"
|
||||
className="project-search-clear-btn"
|
||||
onClick={handleClear}
|
||||
>
|
||||
<MaterialIcon type="clear" />
|
||||
</button>
|
||||
}
|
||||
size="lg"
|
||||
{...args}
|
||||
/>
|
||||
</FormGroup>
|
||||
<hr />
|
||||
<FormGroup controlId="id-2">
|
||||
<Form.Label>Label</Form.Label>
|
||||
<FormControl
|
||||
type="text"
|
||||
placeholder="Search"
|
||||
prepend={<MaterialIcon type="search" />}
|
||||
append={
|
||||
<button
|
||||
type="button"
|
||||
className="project-search-clear-btn"
|
||||
onClick={handleClear}
|
||||
>
|
||||
<MaterialIcon type="clear" />
|
||||
</button>
|
||||
}
|
||||
{...args}
|
||||
/>
|
||||
</FormGroup>
|
||||
<hr />
|
||||
<FormGroup controlId="id-3">
|
||||
<Form.Label>Label</Form.Label>
|
||||
<FormControl
|
||||
type="text"
|
||||
placeholder="Search"
|
||||
prepend={<MaterialIcon type="search" />}
|
||||
append={
|
||||
<button
|
||||
type="button"
|
||||
className="project-search-clear-btn"
|
||||
onClick={handleClear}
|
||||
>
|
||||
<MaterialIcon type="clear" />
|
||||
</button>
|
||||
}
|
||||
size="sm"
|
||||
{...args}
|
||||
/>
|
||||
</FormGroup>
|
||||
<br />
|
||||
<hr />
|
||||
<FormGroup controlId="id-3">
|
||||
<Form.Label>Disabled state</Form.Label>
|
||||
<FormControl
|
||||
type="text"
|
||||
placeholder="Search"
|
||||
prepend={<MaterialIcon type="search" />}
|
||||
append={
|
||||
<button
|
||||
type="button"
|
||||
className="project-search-clear-btn"
|
||||
onClick={handleClear}
|
||||
disabled
|
||||
>
|
||||
<MaterialIcon type="clear" />
|
||||
</button>
|
||||
}
|
||||
disabled
|
||||
{...args}
|
||||
/>
|
||||
</FormGroup>
|
||||
</>
|
||||
)
|
||||
},
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
import { Form } from 'react-bootstrap-5'
|
||||
import { Form, FormSelectProps } from 'react-bootstrap-5'
|
||||
import type { Meta, StoryObj } from '@storybook/react'
|
||||
import FormGroup from '@/features/ui/components/bootstrap-5/form/form-group'
|
||||
import FormText from '@/features/ui/components/bootstrap-5/form/form-text'
|
||||
|
||||
const meta: Meta<(typeof Form)['Select']> = {
|
||||
const meta: Meta<FormSelectProps> = {
|
||||
title: 'Shared / Components / Bootstrap 5 / Form / Select',
|
||||
component: Form.Select,
|
||||
parameters: {
|
||||
|
@ -11,13 +12,13 @@ const meta: Meta<(typeof Form)['Select']> = {
|
|||
}
|
||||
export default meta
|
||||
|
||||
type Story = StoryObj<(typeof Form)['Select']>
|
||||
type Story = StoryObj<FormSelectProps>
|
||||
|
||||
export const Default: Story = {
|
||||
render: args => {
|
||||
return (
|
||||
<>
|
||||
<Form.Group controlId="id-1">
|
||||
<FormGroup controlId="id-1">
|
||||
<Form.Label>Label</Form.Label>
|
||||
<Form.Select size="lg" {...args}>
|
||||
<option>Large select</option>
|
||||
|
@ -26,9 +27,9 @@ export const Default: Story = {
|
|||
<option value="3">Three</option>
|
||||
</Form.Select>
|
||||
<FormText>Helper</FormText>
|
||||
</Form.Group>
|
||||
</FormGroup>
|
||||
<hr />
|
||||
<Form.Group controlId="id-2">
|
||||
<FormGroup controlId="id-2">
|
||||
<Form.Label>Label</Form.Label>
|
||||
<Form.Select {...args}>
|
||||
<option>Regular select</option>
|
||||
|
@ -37,9 +38,9 @@ export const Default: Story = {
|
|||
<option value="3">Three</option>
|
||||
</Form.Select>
|
||||
<FormText>Helper</FormText>
|
||||
</Form.Group>
|
||||
</FormGroup>
|
||||
<hr />
|
||||
<Form.Group controlId="id-3">
|
||||
<FormGroup controlId="id-3">
|
||||
<Form.Label>Label</Form.Label>
|
||||
<Form.Select size="sm" {...args}>
|
||||
<option>Small select</option>
|
||||
|
@ -48,7 +49,7 @@ export const Default: Story = {
|
|||
<option value="3">Three</option>
|
||||
</Form.Select>
|
||||
<FormText>Helper</FormText>
|
||||
</Form.Group>
|
||||
</FormGroup>
|
||||
</>
|
||||
)
|
||||
},
|
||||
|
@ -61,7 +62,7 @@ export const Info: Story = {
|
|||
render: args => {
|
||||
return (
|
||||
<>
|
||||
<Form.Group controlId="id-1">
|
||||
<FormGroup controlId="id-1">
|
||||
<Form.Label>Label</Form.Label>
|
||||
<Form.Select size="lg" {...args}>
|
||||
<option>Large select</option>
|
||||
|
@ -70,9 +71,9 @@ export const Info: Story = {
|
|||
<option value="3">Three</option>
|
||||
</Form.Select>
|
||||
<FormText isInfo>Info</FormText>
|
||||
</Form.Group>
|
||||
</FormGroup>
|
||||
<hr />
|
||||
<Form.Group controlId="id-2">
|
||||
<FormGroup controlId="id-2">
|
||||
<Form.Label>Label</Form.Label>
|
||||
<Form.Select {...args}>
|
||||
<option>Regular select</option>
|
||||
|
@ -81,9 +82,9 @@ export const Info: Story = {
|
|||
<option value="3">Three</option>
|
||||
</Form.Select>
|
||||
<FormText isInfo>Info</FormText>
|
||||
</Form.Group>
|
||||
</FormGroup>
|
||||
<hr />
|
||||
<Form.Group controlId="id-3">
|
||||
<FormGroup controlId="id-3">
|
||||
<Form.Label>Label</Form.Label>
|
||||
<Form.Select size="sm" {...args}>
|
||||
<option>Small select</option>
|
||||
|
@ -92,7 +93,7 @@ export const Info: Story = {
|
|||
<option value="3">Three</option>
|
||||
</Form.Select>
|
||||
<FormText isInfo>Info</FormText>
|
||||
</Form.Group>
|
||||
</FormGroup>
|
||||
</>
|
||||
)
|
||||
},
|
||||
|
@ -102,7 +103,7 @@ export const Error: Story = {
|
|||
render: args => {
|
||||
return (
|
||||
<>
|
||||
<Form.Group controlId="id-1">
|
||||
<FormGroup controlId="id-1">
|
||||
<Form.Label>Label</Form.Label>
|
||||
<Form.Select size="lg" isInvalid {...args}>
|
||||
<option>Large select</option>
|
||||
|
@ -111,9 +112,9 @@ export const Error: Story = {
|
|||
<option value="3">Three</option>
|
||||
</Form.Select>
|
||||
<FormText isError>Error</FormText>
|
||||
</Form.Group>
|
||||
</FormGroup>
|
||||
<hr />
|
||||
<Form.Group controlId="id-2">
|
||||
<FormGroup controlId="id-2">
|
||||
<Form.Label>Label</Form.Label>
|
||||
<Form.Select isInvalid {...args}>
|
||||
<option>Regular select</option>
|
||||
|
@ -122,9 +123,9 @@ export const Error: Story = {
|
|||
<option value="3">Three</option>
|
||||
</Form.Select>
|
||||
<FormText isError>Error</FormText>
|
||||
</Form.Group>
|
||||
</FormGroup>
|
||||
<hr />
|
||||
<Form.Group controlId="id-3">
|
||||
<FormGroup controlId="id-3">
|
||||
<Form.Label>Label</Form.Label>
|
||||
<Form.Select size="sm" isInvalid {...args}>
|
||||
<option>Small select</option>
|
||||
|
@ -133,7 +134,7 @@ export const Error: Story = {
|
|||
<option value="3">Three</option>
|
||||
</Form.Select>
|
||||
<FormText isError>Error</FormText>
|
||||
</Form.Group>
|
||||
</FormGroup>
|
||||
</>
|
||||
)
|
||||
},
|
||||
|
@ -143,7 +144,7 @@ export const Warning: Story = {
|
|||
render: args => {
|
||||
return (
|
||||
<>
|
||||
<Form.Group controlId="id-1">
|
||||
<FormGroup controlId="id-1">
|
||||
<Form.Label>Label</Form.Label>
|
||||
<Form.Select size="lg" {...args}>
|
||||
<option>Large select</option>
|
||||
|
@ -152,9 +153,9 @@ export const Warning: Story = {
|
|||
<option value="3">Three</option>
|
||||
</Form.Select>
|
||||
<FormText isWarning>Warning</FormText>
|
||||
</Form.Group>
|
||||
</FormGroup>
|
||||
<hr />
|
||||
<Form.Group controlId="id-2">
|
||||
<FormGroup controlId="id-2">
|
||||
<Form.Label>Label</Form.Label>
|
||||
<Form.Select {...args}>
|
||||
<option>Regular select</option>
|
||||
|
@ -163,9 +164,9 @@ export const Warning: Story = {
|
|||
<option value="3">Three</option>
|
||||
</Form.Select>
|
||||
<FormText isWarning>Warning</FormText>
|
||||
</Form.Group>
|
||||
</FormGroup>
|
||||
<hr />
|
||||
<Form.Group controlId="id-3">
|
||||
<FormGroup controlId="id-3">
|
||||
<Form.Label>Label</Form.Label>
|
||||
<Form.Select size="sm" {...args}>
|
||||
<option>Small select</option>
|
||||
|
@ -174,7 +175,7 @@ export const Warning: Story = {
|
|||
<option value="3">Three</option>
|
||||
</Form.Select>
|
||||
<FormText isWarning>Warning</FormText>
|
||||
</Form.Group>
|
||||
</FormGroup>
|
||||
</>
|
||||
)
|
||||
},
|
||||
|
@ -184,38 +185,38 @@ export const Success: Story = {
|
|||
render: args => {
|
||||
return (
|
||||
<>
|
||||
<Form.Group controlId="id-1">
|
||||
<FormGroup controlId="id-1">
|
||||
<Form.Label>Label</Form.Label>
|
||||
<Form.Select size="lg" isSuccess {...args}>
|
||||
<Form.Select size="lg" {...args}>
|
||||
<option>Large select</option>
|
||||
<option value="1">One</option>
|
||||
<option value="2">Two</option>
|
||||
<option value="3">Three</option>
|
||||
</Form.Select>
|
||||
<FormText isSuccess>Success</FormText>
|
||||
</Form.Group>
|
||||
</FormGroup>
|
||||
<hr />
|
||||
<Form.Group controlId="id-2">
|
||||
<FormGroup controlId="id-2">
|
||||
<Form.Label>Label</Form.Label>
|
||||
<Form.Select isSuccess {...args}>
|
||||
<Form.Select {...args}>
|
||||
<option>Regular select</option>
|
||||
<option value="1">One</option>
|
||||
<option value="2">Two</option>
|
||||
<option value="3">Three</option>
|
||||
</Form.Select>
|
||||
<FormText isSuccess>Success</FormText>
|
||||
</Form.Group>
|
||||
</FormGroup>
|
||||
<hr />
|
||||
<Form.Group controlId="id-3">
|
||||
<FormGroup controlId="id-3">
|
||||
<Form.Label>Label</Form.Label>
|
||||
<Form.Select size="sm" isSuccess {...args}>
|
||||
<Form.Select size="sm" {...args}>
|
||||
<option>Small select</option>
|
||||
<option value="1">One</option>
|
||||
<option value="2">Two</option>
|
||||
<option value="3">Three</option>
|
||||
</Form.Select>
|
||||
<FormText isSuccess>Success</FormText>
|
||||
</Form.Group>
|
||||
</FormGroup>
|
||||
</>
|
||||
)
|
||||
},
|
||||
|
|
|
@ -1,49 +1,51 @@
|
|||
import { Form } from 'react-bootstrap-5'
|
||||
import type { Meta, StoryObj } from '@storybook/react'
|
||||
import FormGroup from '@/features/ui/components/bootstrap-5/form/form-group'
|
||||
import FormText from '@/features/ui/components/bootstrap-5/form/form-text'
|
||||
import FormControl from '@/features/ui/components/bootstrap-5/form/form-control'
|
||||
|
||||
const meta: Meta<(typeof Form)['Control']> = {
|
||||
const meta: Meta<React.ComponentProps<typeof FormControl>> = {
|
||||
title: 'Shared / Components / Bootstrap 5 / Form / Textarea',
|
||||
component: Form.Control,
|
||||
component: FormControl,
|
||||
parameters: {
|
||||
bootstrap5: true,
|
||||
},
|
||||
}
|
||||
export default meta
|
||||
|
||||
type Story = StoryObj<(typeof Form)['Control']>
|
||||
type Story = StoryObj<React.ComponentProps<typeof FormControl>>
|
||||
|
||||
export const Default: Story = {
|
||||
render: args => {
|
||||
return (
|
||||
<>
|
||||
<Form.Group controlId="id-1">
|
||||
<FormGroup controlId="id-1">
|
||||
<Form.Label>Label</Form.Label>
|
||||
<Form.Control
|
||||
<FormControl
|
||||
as="textarea"
|
||||
defaultValue="Large input"
|
||||
size="lg"
|
||||
{...args}
|
||||
/>
|
||||
<FormText>Helper</FormText>
|
||||
</Form.Group>
|
||||
</FormGroup>
|
||||
<hr />
|
||||
<Form.Group controlId="id-2">
|
||||
<FormGroup controlId="id-2">
|
||||
<Form.Label>Label</Form.Label>
|
||||
<Form.Control as="textarea" defaultValue="Regular input" {...args} />
|
||||
<FormControl as="textarea" defaultValue="Regular input" {...args} />
|
||||
<FormText>Helper</FormText>
|
||||
</Form.Group>
|
||||
</FormGroup>
|
||||
<hr />
|
||||
<Form.Group controlId="id-3">
|
||||
<FormGroup controlId="id-3">
|
||||
<Form.Label>Label</Form.Label>
|
||||
<Form.Control
|
||||
<FormControl
|
||||
as="textarea"
|
||||
defaultValue="Small input"
|
||||
size="sm"
|
||||
{...args}
|
||||
/>
|
||||
<FormText>Helper</FormText>
|
||||
</Form.Group>
|
||||
</FormGroup>
|
||||
</>
|
||||
)
|
||||
},
|
||||
|
@ -56,9 +58,9 @@ export const Info: Story = {
|
|||
render: args => {
|
||||
return (
|
||||
<>
|
||||
<Form.Group controlId="id-1">
|
||||
<FormGroup controlId="id-1">
|
||||
<Form.Label>Label</Form.Label>
|
||||
<Form.Control
|
||||
<FormControl
|
||||
as="textarea"
|
||||
placeholder="Placeholder"
|
||||
defaultValue="Large input"
|
||||
|
@ -66,22 +68,22 @@ export const Info: Story = {
|
|||
{...args}
|
||||
/>
|
||||
<FormText isInfo>Info</FormText>
|
||||
</Form.Group>
|
||||
</FormGroup>
|
||||
<hr />
|
||||
<Form.Group controlId="id-2">
|
||||
<FormGroup controlId="id-2">
|
||||
<Form.Label>Label</Form.Label>
|
||||
<Form.Control
|
||||
<FormControl
|
||||
as="textarea"
|
||||
placeholder="Placeholder"
|
||||
defaultValue="Regular input"
|
||||
{...args}
|
||||
/>
|
||||
<FormText isInfo>Info</FormText>
|
||||
</Form.Group>
|
||||
</FormGroup>
|
||||
<hr />
|
||||
<Form.Group controlId="id-3">
|
||||
<FormGroup controlId="id-3">
|
||||
<Form.Label>Label</Form.Label>
|
||||
<Form.Control
|
||||
<FormControl
|
||||
as="textarea"
|
||||
placeholder="Placeholder"
|
||||
defaultValue="Small input"
|
||||
|
@ -89,7 +91,7 @@ export const Info: Story = {
|
|||
{...args}
|
||||
/>
|
||||
<FormText isInfo>Info</FormText>
|
||||
</Form.Group>
|
||||
</FormGroup>
|
||||
</>
|
||||
)
|
||||
},
|
||||
|
@ -99,9 +101,9 @@ export const Error: Story = {
|
|||
render: args => {
|
||||
return (
|
||||
<>
|
||||
<Form.Group controlId="id-1">
|
||||
<FormGroup controlId="id-1">
|
||||
<Form.Label>Label</Form.Label>
|
||||
<Form.Control
|
||||
<FormControl
|
||||
as="textarea"
|
||||
placeholder="Placeholder"
|
||||
defaultValue="Large input"
|
||||
|
@ -110,11 +112,11 @@ export const Error: Story = {
|
|||
{...args}
|
||||
/>
|
||||
<FormText isError>Error</FormText>
|
||||
</Form.Group>
|
||||
</FormGroup>
|
||||
<hr />
|
||||
<Form.Group controlId="id-2">
|
||||
<FormGroup controlId="id-2">
|
||||
<Form.Label>Label</Form.Label>
|
||||
<Form.Control
|
||||
<FormControl
|
||||
as="textarea"
|
||||
placeholder="Placeholder"
|
||||
defaultValue="Regular input"
|
||||
|
@ -122,11 +124,11 @@ export const Error: Story = {
|
|||
{...args}
|
||||
/>
|
||||
<FormText isError>Error</FormText>
|
||||
</Form.Group>
|
||||
</FormGroup>
|
||||
<hr />
|
||||
<Form.Group controlId="id-3">
|
||||
<FormGroup controlId="id-3">
|
||||
<Form.Label>Label</Form.Label>
|
||||
<Form.Control
|
||||
<FormControl
|
||||
as="textarea"
|
||||
placeholder="Placeholder"
|
||||
defaultValue="Small input"
|
||||
|
@ -135,7 +137,7 @@ export const Error: Story = {
|
|||
{...args}
|
||||
/>
|
||||
<FormText isError>Error</FormText>
|
||||
</Form.Group>
|
||||
</FormGroup>
|
||||
</>
|
||||
)
|
||||
},
|
||||
|
@ -145,9 +147,9 @@ export const Warning: Story = {
|
|||
render: args => {
|
||||
return (
|
||||
<>
|
||||
<Form.Group controlId="id-1">
|
||||
<FormGroup controlId="id-1">
|
||||
<Form.Label>Label</Form.Label>
|
||||
<Form.Control
|
||||
<FormControl
|
||||
as="textarea"
|
||||
placeholder="Placeholder"
|
||||
defaultValue="Large input"
|
||||
|
@ -155,22 +157,22 @@ export const Warning: Story = {
|
|||
{...args}
|
||||
/>
|
||||
<FormText isWarning>Warning</FormText>
|
||||
</Form.Group>
|
||||
</FormGroup>
|
||||
<hr />
|
||||
<Form.Group controlId="id-2">
|
||||
<FormGroup controlId="id-2">
|
||||
<Form.Label>Label</Form.Label>
|
||||
<Form.Control
|
||||
<FormControl
|
||||
as="textarea"
|
||||
placeholder="Placeholder"
|
||||
defaultValue="Regular input"
|
||||
{...args}
|
||||
/>
|
||||
<FormText isWarning>Warning</FormText>
|
||||
</Form.Group>
|
||||
</FormGroup>
|
||||
<hr />
|
||||
<Form.Group controlId="id-3">
|
||||
<FormGroup controlId="id-3">
|
||||
<Form.Label>Label</Form.Label>
|
||||
<Form.Control
|
||||
<FormControl
|
||||
as="textarea"
|
||||
placeholder="Placeholder"
|
||||
defaultValue="Small input"
|
||||
|
@ -178,7 +180,7 @@ export const Warning: Story = {
|
|||
{...args}
|
||||
/>
|
||||
<FormText isWarning>Warning</FormText>
|
||||
</Form.Group>
|
||||
</FormGroup>
|
||||
</>
|
||||
)
|
||||
},
|
||||
|
@ -188,9 +190,9 @@ export const Success: Story = {
|
|||
render: args => {
|
||||
return (
|
||||
<>
|
||||
<Form.Group controlId="id-1">
|
||||
<FormGroup controlId="id-1">
|
||||
<Form.Label>Label</Form.Label>
|
||||
<Form.Control
|
||||
<FormControl
|
||||
as="textarea"
|
||||
placeholder="Placeholder"
|
||||
defaultValue="Large input"
|
||||
|
@ -198,22 +200,22 @@ export const Success: Story = {
|
|||
{...args}
|
||||
/>
|
||||
<FormText isSuccess>Success</FormText>
|
||||
</Form.Group>
|
||||
</FormGroup>
|
||||
<hr />
|
||||
<Form.Group controlId="id-2">
|
||||
<FormGroup controlId="id-2">
|
||||
<Form.Label>Label</Form.Label>
|
||||
<Form.Control
|
||||
<FormControl
|
||||
as="textarea"
|
||||
placeholder="Placeholder"
|
||||
defaultValue="Regular input"
|
||||
{...args}
|
||||
/>
|
||||
<FormText isSuccess>Success</FormText>
|
||||
</Form.Group>
|
||||
</FormGroup>
|
||||
<hr />
|
||||
<Form.Group controlId="id-3">
|
||||
<FormGroup controlId="id-3">
|
||||
<Form.Label>Label</Form.Label>
|
||||
<Form.Control
|
||||
<FormControl
|
||||
as="textarea"
|
||||
placeholder="Placeholder"
|
||||
defaultValue="Small input"
|
||||
|
@ -221,7 +223,7 @@ export const Success: Story = {
|
|||
{...args}
|
||||
/>
|
||||
<FormText isSuccess>Success</FormText>
|
||||
</Form.Group>
|
||||
</FormGroup>
|
||||
</>
|
||||
)
|
||||
},
|
||||
|
|
|
@ -386,9 +386,7 @@ ul.folders-menu {
|
|||
|
||||
form.project-search {
|
||||
.form-group {
|
||||
@media (min-width: @screen-md) {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -84,3 +84,69 @@
|
|||
.form-group {
|
||||
margin-bottom: var(--spacing-06);
|
||||
}
|
||||
|
||||
.form-control-wrapper {
|
||||
position: relative;
|
||||
|
||||
&.form-control-wrapper-disabled {
|
||||
.form-control-start-icon,
|
||||
.form-control-end-icon {
|
||||
& > * {
|
||||
color: var(--content-disabled);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.form-control-start-icon,
|
||||
.form-control-end-icon {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-size: 0;
|
||||
}
|
||||
|
||||
.form-control-start-icon {
|
||||
left: 0;
|
||||
}
|
||||
.form-control-end-icon {
|
||||
right: 0;
|
||||
}
|
||||
|
||||
--icon-width: 20px;
|
||||
--form-control-padding-x: var(--spacing-04);
|
||||
--form-control-icon-offset-y: var(--spacing-04);
|
||||
|
||||
&.form-control-wrapper-sm {
|
||||
--form-control-padding-x: var(--spacing-03);
|
||||
--form-control-icon-offset-y: var(--spacing-02);
|
||||
}
|
||||
|
||||
&.form-control-wrapper-lg {
|
||||
--form-control-padding-x: var(--spacing-05);
|
||||
--form-control-icon-offset-y: var(--spacing-05);
|
||||
}
|
||||
|
||||
.form-control-start-icon {
|
||||
padding-left: calc(var(--form-control-padding-x) + var(--bs-border-width));
|
||||
}
|
||||
|
||||
.form-control-end-icon {
|
||||
padding-right: calc(var(--form-control-padding-x) + var(--bs-border-width));
|
||||
}
|
||||
|
||||
.form-control-offset-start {
|
||||
padding-left: calc(
|
||||
var(--form-control-padding-x) + var(--form-control-icon-offset-y) +
|
||||
var(--icon-width)
|
||||
);
|
||||
}
|
||||
|
||||
.form-control-offset-end {
|
||||
padding-right: calc(
|
||||
var(--form-control-padding-x) + var(--form-control-icon-offset-y) +
|
||||
var(--icon-width)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -464,3 +464,13 @@
|
|||
.project-list-load-more-button {
|
||||
margin-bottom: var(--spacing-05);
|
||||
}
|
||||
|
||||
form.project-search {
|
||||
.form-group {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.project-search-clear-btn {
|
||||
@include reset-button;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue