Skip to content

Commit

Permalink
feat(project): add injectable wrapper to common components (#598)
Browse files Browse the repository at this point in the history
  • Loading branch information
royschut authored Sep 4, 2024
1 parent 3753a9c commit a6ad0d8
Show file tree
Hide file tree
Showing 9 changed files with 63 additions and 25 deletions.
11 changes: 7 additions & 4 deletions packages/ui-react/src/components/Button/Button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,17 @@ import classNames from 'classnames';
import { NavLink } from 'react-router-dom';

import Spinner from '../Spinner/Spinner';
import createInjectableComponent from '../../modules/createInjectableComponent';

import styles from './Button.module.scss';

export const ButtonIdentifier = Symbol(`BUTTON`);

type Color = 'default' | 'primary' | 'delete';

type Variant = 'contained' | 'outlined' | 'text' | 'danger' | 'delete';

type Props = {
export type ButtonProps = {
children?: React.ReactNode;
label: string;
active?: boolean;
Expand All @@ -31,7 +34,7 @@ type Props = {
activeClassname?: string;
} & React.AriaAttributes;

const Button: React.FC<Props> = ({
const Button: React.FC<ButtonProps> = ({
label,
children,
color = 'default',
Expand All @@ -48,7 +51,7 @@ const Button: React.FC<Props> = ({
className,
activeClassname = '',
...rest
}: Props) => {
}: ButtonProps) => {
const buttonClassName = (isActive: boolean) =>
classNames(styles.button, className, styles[color], styles[variant], {
[styles.active]: isActive,
Expand Down Expand Up @@ -82,4 +85,4 @@ const Button: React.FC<Props> = ({
</button>
);
};
export default Button;
export default createInjectableComponent(ButtonIdentifier, Button);
7 changes: 5 additions & 2 deletions packages/ui-react/src/components/Card/Card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,16 @@ import type { PosterAspectRatio } from '@jwp/ott-common/src/utils/collection';

import Image from '../Image/Image';
import Icon from '../Icon/Icon';
import createInjectableComponent from '../../modules/createInjectableComponent';

import styles from './Card.module.scss';

export const CardIdentifier = Symbol(`CARD`);

type ReplaceColon<T> = T extends `${infer Left}:${infer Right}` ? `${Left}${Right}` : T;
type PosterAspectRatioClass = ReplaceColon<PosterAspectRatio>;

type CardProps = {
export type CardProps = {
item: PlaylistItem;
onHover?: () => void;
progress?: number;
Expand Down Expand Up @@ -137,4 +140,4 @@ function Card({
);
}

export default memo(Card);
export default memo(createInjectableComponent(CardIdentifier, Card));
7 changes: 5 additions & 2 deletions packages/ui-react/src/components/CardGrid/CardGrid.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import useBreakpoint, { Breakpoint, type Breakpoints } from '@jwp/ott-ui-react/s
import Card from '../Card/Card';
import InfiniteScrollLoader from '../InfiniteScrollLoader/InfiniteScrollLoader';
import LayoutGrid from '../LayoutGrid/LayoutGrid';
import createInjectableComponent from '../../modules/createInjectableComponent';

import styles from './CardGrid.module.scss';

Expand All @@ -26,7 +27,9 @@ const defaultCols: Breakpoints = {
[Breakpoint.xl]: 5,
};

type CardGridProps = {
export const CardGridIdentifier = Symbol(`CARD_GRID`);

export type CardGridProps = {
playlist: Playlist;
watchHistory?: { [key: string]: number };
isLoading: boolean;
Expand Down Expand Up @@ -104,4 +107,4 @@ function CardGrid({
);
}

export default CardGrid;
export default createInjectableComponent(CardGridIdentifier, CardGrid);
13 changes: 9 additions & 4 deletions packages/ui-react/src/components/Header/Header.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,21 @@
import React, { type PropsWithChildren } from 'react';
import { type PropsWithChildren } from 'react';
import classNames from 'classnames';

import createInjectableComponent from '../../modules/createInjectableComponent';

import styles from './Header.module.scss';

export const HeaderIdentifier = Symbol(`HEADER`);

type TypeHeader = 'static' | 'fixed';

type Props = {
export type HeaderProps = {
headerType?: TypeHeader;
className?: string;
searchActive: boolean;
};

const Header = ({ children, className, headerType = 'static', searchActive }: PropsWithChildren<Props>) => {
const Header = ({ children, className, headerType = 'static', searchActive }: PropsWithChildren<HeaderProps>) => {
const headerClassName = classNames(styles.header, styles[headerType], className, {
[styles.searchActive]: searchActive,
});
Expand All @@ -22,4 +26,5 @@ const Header = ({ children, className, headerType = 'static', searchActive }: Pr
</header>
);
};
export default Header;

export default createInjectableComponent(HeaderIdentifier, Header);
21 changes: 18 additions & 3 deletions packages/ui-react/src/components/MenuButton/MenuButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,13 @@ import React from 'react';
import { NavLink } from 'react-router-dom';
import classNames from 'classnames';

import createInjectableComponent from '../../modules/createInjectableComponent';

import styles from './MenuButton.module.scss';

type Props = {
export const MenuButtonIdentifier = Symbol(`MENU_BUTTON`);

export type MenuButtonProps = {
label?: string;
to?: string;
onClick?: () => void;
Expand All @@ -16,7 +20,18 @@ type Props = {
small?: boolean;
} & React.AriaAttributes;

const MenuButton: React.FC<Props> = ({ label, to, onClick, onBlur, onFocus, tabIndex = 0, active = false, startIcon, small = false, ...rest }: Props) => {
const MenuButton: React.FC<MenuButtonProps> = ({
label,
to,
onClick,
onBlur,
onFocus,
tabIndex = 0,
active = false,
startIcon,
small = false,
...rest
}: MenuButtonProps) => {
const icon = startIcon ? <div className={styles.startIcon}>{startIcon}</div> : null;
const getClassName = (isActive: boolean) => classNames(styles.menuButton, { [styles.small]: small }, { [styles.active]: isActive });

Expand Down Expand Up @@ -45,4 +60,4 @@ const MenuButton: React.FC<Props> = ({ label, to, onClick, onBlur, onFocus, tabI
);
};

export default MenuButton;
export default createInjectableComponent(MenuButtonIdentifier, MenuButton);
5 changes: 4 additions & 1 deletion packages/ui-react/src/components/Shelf/Shelf.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import '@videodock/tile-slider/lib/style.css';

import Card from '../Card/Card';
import Icon from '../Icon/Icon';
import createInjectableComponent from '../../modules/createInjectableComponent';

import styles from './Shelf.module.scss';

Expand All @@ -34,6 +35,8 @@ export const featuredTileBreakpoints: Breakpoints = {
[Breakpoint.xl]: 1,
};

export const ShelfIdentifier = Symbol(`SHELF`);

export type ShelfProps = {
playlist: Playlist;
type: PlaylistType;
Expand Down Expand Up @@ -151,4 +154,4 @@ const Shelf = ({
);
};

export default Shelf;
export default createInjectableComponent(ShelfIdentifier, Shelf);
7 changes: 5 additions & 2 deletions packages/ui-react/src/components/Sidebar/Sidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,13 @@ import IconButton from '../IconButton/IconButton';
import Icon from '../Icon/Icon';
import Modal, { type AnimationProps } from '../Modal/Modal';
import Slide from '../Animation/Slide/Slide';
import createInjectableComponent from '../../modules/createInjectableComponent';

import styles from './Sidebar.module.scss';

type SidebarProps = {
export const SidebarIdentifier = Symbol(`SIDEBAR`);

export type SidebarProps = {
isOpen: boolean;
onClose: () => void;
children?: ReactNode;
Expand Down Expand Up @@ -40,4 +43,4 @@ const Sidebar: React.FC<SidebarProps> = ({ isOpen, onClose, children }) => {
);
};

export default Sidebar;
export default createInjectableComponent(SidebarIdentifier, Sidebar);
2 changes: 2 additions & 0 deletions packages/ui-react/src/modules/createInjectableComponent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import React, { type FC } from 'react';

import { container } from './container';

// This HOC is used to override a component top-level, using Inversify
// More info: platforms/web/src/modules/register.ts
const createInjectableComponent = <Props extends object>(identifier: symbol, DefaultComponent: FC<Props>) => {
return (props: Props) => {
const isOverridden = container.isBound(identifier);
Expand Down
15 changes: 8 additions & 7 deletions platforms/web/src/modules/register.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,17 +52,18 @@ container.bind<LogTransporter>(LogTransporter).toDynamicValue(() => new ConsoleT
*
* @example
* ```ts
* // Define in types.ts (from `ui-react` for example)
* const TAG_IDENTIFIER = 'TAG_IDENTIFIER';
* // Define an identifier from the component (from `ui-react` for example):
* export const CardIdentifier = Symbol('CARD');
*
* // Bind custom component
* container.bind(TAG_IDENTIFIER).toConstantValue(CustomTag);
* // Make sure the component is wrapped in the HOC:
* export default createInjectableComponent(CardIdentifier, Card);
*
* // Then wrap the component in a HOC, from the component file itself
* export default createInjectableComponent(TAG_IDENTIFIER, DefaultTag);
* // Override the component into the associated container, from register.ts:
* import { container as uiComponentContainer } from '@jwp/ott-ui-react/src/modules/container';
*
* uiComponentContainer.bind<React.FC<CardProps>>(CardIdentifier).toConstantValue(CustomCard);
* ```
*/

// Override ui-react component
// uiComponentContainer.bind<React.FC<TagProps>>(TAG_IDENTIFIER).toConstantValue(Tag);
// uiComponentContainer.bind<React.FC<CardProps>>(CardIdentifier).toConstantValue(CustomCard);

0 comments on commit a6ad0d8

Please sign in to comment.