Skip to content

Commit

Permalink
Merge pull request #903 from VocaDB/react-bootstrap
Browse files Browse the repository at this point in the history
Create components for Bootstrap and jQuery UI
  • Loading branch information
ycanardeau authored Jul 8, 2021
2 parents c6c0f12 + de24153 commit 0c8c36a
Show file tree
Hide file tree
Showing 37 changed files with 2,037 additions and 0 deletions.
74 changes: 74 additions & 0 deletions VocaDbWeb/Scripts/Bootstrap/AbstractNav.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
// Code from: https://github.com/react-bootstrap/react-bootstrap/blob/3d4c57374646949e6fedfef00236c99f4d1b4e71/src/AbstractNav.tsx
import useForceUpdate from '@restart/hooks/useForceUpdate';
import * as React from 'react';
import { useContext } from 'react';

import NavContext from './NavContext';
import SelectableContext, { makeEventKey } from './SelectableContext';
import TabContext from './TabContext';
import { BsPrefixRefForwardingComponent, SelectCallback } from './helpers';
import { EventKey } from './types';

// eslint-disable-next-line @typescript-eslint/no-empty-function
const noop = (): void => {};

interface AbstractNavProps
extends Omit<React.HTMLAttributes<HTMLElement>, 'onSelect'> {
activeKey?: EventKey;
as?: React.ElementType;
onSelect?: SelectCallback;
parentOnSelect?: SelectCallback;
}

const AbstractNav: BsPrefixRefForwardingComponent<
'ul',
AbstractNavProps
> = React.forwardRef<HTMLElement, AbstractNavProps>(
(
{
// Need to define the default "as" during prop destructuring to be compatible with styled-components github.com/react-bootstrap/react-bootstrap/issues/3595
as: Component = 'ul',
onSelect,
activeKey,
role,
onKeyDown,
...props
},
ref,
) => {
const parentOnSelect = useContext(SelectableContext);
const tabContext = useContext(TabContext);

let getControlledId, getControllerId;

if (tabContext) {
role = role || 'tablist';
activeKey = tabContext.activeKey;
getControlledId = tabContext.getControlledId;
getControllerId = tabContext.getControllerId;
}

const handleSelect = (key: any, event: any): void => {
if (key == null) return;
onSelect?.(key, event);
parentOnSelect?.(key, event);
};

return (
<SelectableContext.Provider value={handleSelect}>
<NavContext.Provider
value={{
role, // used by NavLink to determine it's role
activeKey: makeEventKey(activeKey),
getControlledId: getControlledId || noop,
getControllerId: getControllerId || noop,
}}
>
<Component {...props} role={role} />
</NavContext.Provider>
</SelectableContext.Provider>
);
},
);

export default AbstractNav;
87 changes: 87 additions & 0 deletions VocaDbWeb/Scripts/Bootstrap/AbstractNavItem.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
// Code from: https://github.com/react-bootstrap/react-bootstrap/blob/62609973722e5769b968eb62913b4f5708df00fc/src/AbstractNavItem.tsx
import useEventCallback from '@restart/hooks/useEventCallback';
import classNames from 'classnames';
import * as React from 'react';
import { useContext } from 'react';
import warning from 'warning';

import NavContext from './NavContext';
import SelectableContext, { makeEventKey } from './SelectableContext';
import { BsPrefixRefForwardingComponent } from './helpers';
import { EventKey } from './types';

export interface AbstractNavItemProps
extends Omit<React.HTMLAttributes<HTMLElement>, 'onSelect'> {
active?: boolean;
as: React.ElementType;
disabled?: boolean;
eventKey?: EventKey;
href?: string;
tabIndex?: number;
onSelect?: (navKey: string, e: any) => void;
}

const AbstractNavItem: BsPrefixRefForwardingComponent<
'div',
AbstractNavItemProps
> = React.forwardRef<HTMLElement, AbstractNavItemProps>(
(
{ active, className, eventKey, onSelect, onClick, as: Component, ...props },
ref,
) => {
const navKey = makeEventKey(eventKey, props.href);
const parentOnSelect = useContext(SelectableContext);
const navContext = useContext(NavContext);

let isActive = active;
if (navContext) {
if (!props.role && navContext.role === 'tablist') props.role = 'tab';

const contextControllerId = navContext.getControllerId(navKey);
const contextControlledId = navContext.getControlledId(navKey);

warning(
!contextControllerId || !props.id,
`[react-bootstrap] The provided id '${props.id}' was overwritten by the current navContext with '${contextControllerId}'.`,
);
warning(
!contextControlledId || !props['aria-controls'],
`[react-bootstrap] The provided aria-controls value '${props['aria-controls']}' was overwritten by the current navContext with '${contextControlledId}'.`,
);

props.id = contextControllerId || props.id;
props['aria-controls'] = contextControlledId || props['aria-controls'];

isActive =
active == null && navKey != null
? navContext.activeKey === navKey
: active;
}

if (props.role === 'tab') {
if (props.disabled) {
props.tabIndex = -1;
props['aria-disabled'] = true;
}
props['aria-selected'] = isActive;
}

const handleOnclick = useEventCallback((e) => {
onClick?.(e);
if (navKey == null) return;
onSelect?.(navKey, e);
parentOnSelect?.(navKey, e);
});

return (
<Component
{...props}
ref={ref}
onClick={handleOnclick}
className={classNames(className, isActive && 'active')}
/>
);
},
);

export default AbstractNavItem;
49 changes: 49 additions & 0 deletions VocaDbWeb/Scripts/Bootstrap/Breadcrumb.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
// Code from: https://github.com/react-bootstrap/react-bootstrap/blob/3d4c57374646949e6fedfef00236c99f4d1b4e71/src/Breadcrumb.tsx
import classNames from 'classnames';
import * as React from 'react';

import BreadcrumbItem from './BreadcrumbItem';
import { useBootstrapPrefix } from './ThemeProvider';
import { BsPrefixProps, BsPrefixRefForwardingComponent } from './helpers';

export interface BreadcrumbProps
extends BsPrefixProps,
React.HTMLAttributes<HTMLElement> {
label?: string;
listProps?: React.OlHTMLAttributes<HTMLOListElement>;
}

const Breadcrumb: BsPrefixRefForwardingComponent<
'nav',
BreadcrumbProps
> = React.forwardRef<HTMLElement, BreadcrumbProps>(
(
{
bsPrefix,
className,
listProps,
children,
label,
// Need to define the default "as" during prop destructuring to be compatible with styled-components github.com/react-bootstrap/react-bootstrap/issues/3595
as: Component = 'nav',
...props
},
ref,
) => {
const prefix = useBootstrapPrefix(bsPrefix, 'breadcrumb');

return (
<Component aria-label={label} className={className} ref={ref} {...props}>
<ol {...listProps} className={classNames(prefix, listProps?.className)}>
{children}
</ol>
</Component>
);
},
);

Breadcrumb.displayName = 'Breadcrumb';

export default Object.assign(Breadcrumb, {
Item: BreadcrumbItem,
});
72 changes: 72 additions & 0 deletions VocaDbWeb/Scripts/Bootstrap/BreadcrumbItem.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
// Code from: https://github.com/react-bootstrap/react-bootstrap/blob/c11bc67ab3105e7a1839c0dcaacc5f1099885f02/src/BreadcrumbItem.tsx
import classNames from 'classnames';
import * as React from 'react';

import SafeAnchor from './SafeAnchor';
import { useBootstrapPrefix } from './ThemeProvider';
import { BsPrefixProps, BsPrefixRefForwardingComponent } from './helpers';

export interface BreadcrumbItemProps
extends BsPrefixProps,
Omit<React.HTMLAttributes<HTMLElement>, 'title'> {
active?: boolean;
href?: string;
linkAs?: React.ElementType;
target?: string;
title?: React.ReactNode;
linkProps?: Record<string, any>; // the generic is to much work here
divider?: boolean;
}

const BreadcrumbItem: BsPrefixRefForwardingComponent<
'li',
BreadcrumbItemProps
> = React.forwardRef<HTMLElement, BreadcrumbItemProps>(
(
{
bsPrefix,
active,
children,
className,
// Need to define the default "as" during prop destructuring to be compatible with styled-components github.com/react-bootstrap/react-bootstrap/issues/3595
as: Component = 'li',
linkAs: LinkComponent = SafeAnchor,
linkProps,
href,
title,
target,
divider,
...props
},
ref,
) => {
const prefix = useBootstrapPrefix(bsPrefix, 'breadcrumb-item');

return (
<Component
ref={ref}
{...props}
className={classNames(prefix, className, { active })}
aria-current={active ? 'page' : undefined}
>
{active ? (
children
) : (
<LinkComponent
{...linkProps}
href={href}
title={title}
target={target}
>
{children}
</LinkComponent>
)}
{divider && <span className="divider">/</span>}
</Component>
);
},
);

BreadcrumbItem.displayName = 'BreadcrumbItem';

export default BreadcrumbItem;
54 changes: 54 additions & 0 deletions VocaDbWeb/Scripts/Bootstrap/Button.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
// Code from: https://github.com/react-bootstrap/react-bootstrap/blob/8a7e095e8032fdeac4fd1fdb41e6dfb452ae4494/src/Button.tsx
import classNames from 'classnames';
import * as React from 'react';

import SafeAnchor from './SafeAnchor';
import { useBootstrapPrefix } from './ThemeProvider';
import { BsPrefixProps, BsPrefixRefForwardingComponent } from './helpers';
import { ButtonVariant } from './types';

export type ButtonType = 'button' | 'reset' | 'submit' | string;

export interface ButtonProps
extends React.HTMLAttributes<HTMLElement>,
BsPrefixProps {
variant?: ButtonVariant;
type?: ButtonType;
href?: string;
disabled?: boolean;
}

const Button: BsPrefixRefForwardingComponent<
'button',
ButtonProps
> = React.forwardRef<HTMLButtonElement, ButtonProps>(
({ bsPrefix, variant, className, type, as, ...props }, ref) => {
const prefix = useBootstrapPrefix(bsPrefix, 'btn');

const classes = classNames(
className,
prefix,
variant && `${prefix}-${variant}`,
);

if (props.href) {
return (
<SafeAnchor
{...props}
as={as}
ref={ref}
className={classNames(classes, props.disabled && 'disabled')}
/>
);
}

if (!type && !as) {
type = 'button';
}

const Component = as || 'button';
return <Component {...props} ref={ref} type={type} className={classes} />;
},
);

export default Button;
52 changes: 52 additions & 0 deletions VocaDbWeb/Scripts/Bootstrap/ButtonGroup.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// Code from: https://github.com/react-bootstrap/react-bootstrap/blob/3d4c57374646949e6fedfef00236c99f4d1b4e71/src/ButtonGroup.tsx
import classNames from 'classnames';
import * as React from 'react';

import { useBootstrapPrefix } from './ThemeProvider';
import { BsPrefixProps, BsPrefixRefForwardingComponent } from './helpers';

export interface ButtonGroupProps
extends BsPrefixProps,
React.HTMLAttributes<HTMLElement> {
size?: 'sm' | 'lg';
vertical?: boolean;
}

const ButtonGroup: BsPrefixRefForwardingComponent<
'div',
ButtonGroupProps
> = React.forwardRef(
(
{
bsPrefix,
size,
vertical,
className,
// Need to define the default "as" during prop destructuring to be compatible with styled-components github.com/react-bootstrap/react-bootstrap/issues/3595
as: Component = 'div',
...rest
}: ButtonGroupProps,
ref,
) => {
const prefix = useBootstrapPrefix(bsPrefix, 'btn-group');
let baseClass = prefix;

if (vertical) baseClass = `${prefix}-vertical`;

return (
<Component
{...rest}
ref={ref}
className={classNames(
className,
baseClass,
size && `${prefix}-${size}`,
)}
/>
);
},
);

ButtonGroup.displayName = 'ButtonGroup';

export default ButtonGroup;
Loading

0 comments on commit 0c8c36a

Please sign in to comment.