Skip to content

Commit

Permalink
feat(theme): adding theme prop to components
Browse files Browse the repository at this point in the history
  • Loading branch information
Ricardo Lüders committed Jan 26, 2023
1 parent ffe5480 commit 8cbb0ae
Show file tree
Hide file tree
Showing 13 changed files with 135 additions and 88 deletions.
5 changes: 1 addition & 4 deletions src/lib/components/Accordion/AccordionTitle.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,7 @@ import { useAccordionContext } from './AccordionPanelContext';
export interface FlowbiteAccordionTitleTheme {
arrow: {
base: string;
open: {
off: string;
on: string;
};
open: FlowbiteBoolean;
};
base: string;
flush: FlowbiteBoolean;
Expand Down
6 changes: 2 additions & 4 deletions src/lib/components/Avatar/Avatar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import classNames from 'classnames';
import type { ComponentProps, FC, PropsWithChildren, ReactElement } from 'react';
import { DeepPartial } from '..';
import { mergeDeep } from '../../helpers/mergeDeep';
import type { FlowbiteColors, FlowbitePositions, FlowbiteSizes } from '../Flowbite/FlowbiteTheme';
import type { FlowbiteBoolean, FlowbiteColors, FlowbitePositions, FlowbiteSizes } from '../Flowbite/FlowbiteTheme';
import { useTheme } from '../Flowbite/ThemeContext';
import AvatarGroup from './AvatarGroup';
import AvatarGroupCounter from './AvatarGroupCounter';
Expand All @@ -24,9 +24,7 @@ export interface FlowbiteAvatarRootTheme {
statusPosition: FlowbitePositions;
}

export interface FlowbiteAvatarImageTheme {
off: string;
on: string;
export interface FlowbiteAvatarImageTheme extends FlowbiteBoolean {
placeholder: string;
}

Expand Down
6 changes: 2 additions & 4 deletions src/lib/components/Badge/Badge.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import classNames from 'classnames';
import type { ComponentProps, FC, PropsWithChildren } from 'react';
import { DeepPartial } from '..';
import { mergeDeep } from '../../helpers/mergeDeep';
import type { FlowbiteColors, FlowbiteSizes } from '../Flowbite/FlowbiteTheme';
import type { FlowbiteBoolean, FlowbiteColors, FlowbiteSizes } from '../Flowbite/FlowbiteTheme';
import { useTheme } from '../Flowbite/ThemeContext';

export interface FlowbiteBadgeTheme {
Expand All @@ -17,9 +17,7 @@ export interface FlowbiteBadgeRootTheme {
size: BadgeSizes;
}

export interface FlowbiteBadgeIconTheme {
off: string;
on: string;
export interface FlowbiteBadgeIconTheme extends FlowbiteBoolean {
size: BadgeSizes;
}

Expand Down
6 changes: 2 additions & 4 deletions src/lib/components/Breadcrumb/BreadcrumbItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,13 @@ import { ComponentProps, FC, forwardRef, PropsWithChildren } from 'react';
import { HiOutlineChevronRight } from 'react-icons/hi';
import { DeepPartial } from '..';
import { mergeDeep } from '../../helpers/mergeDeep';
import { FlowbiteBoolean } from '../Flowbite/FlowbiteTheme';
import { useTheme } from '../Flowbite/ThemeContext';

export interface FlowbiteBreadcrumbItemTheme {
base: string;
chevron: string;
href: {
off: string;
on: string;
};
href: FlowbiteBoolean;
icon: string;
}

Expand Down
30 changes: 18 additions & 12 deletions src/lib/components/Button/Button.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import classNames from 'classnames';
import { forwardRef, type ComponentProps, type ReactNode } from 'react';
import { mergeDeep } from '../../helpers/mergeDeep';
import type {
FlowbiteBoolean,
FlowbiteColors,
Expand All @@ -18,20 +19,24 @@ export interface FlowbiteButtonTheme {
disabled: string;
gradient: ButtonGradientColors;
gradientDuoTone: ButtonGradientDuoToneColors;
inner: {
base: string;
position: PositionInButtonGroup;
outline: string;
};
inner: FlowbiteButtonInnerTheme;
label: string;
outline: FlowbiteBoolean & {
color: ButtonOutlineColors;
pill: FlowbiteBoolean;
};
outline: FlowbiteButtonOutlineTheme;
pill: FlowbiteBoolean;
size: ButtonSizes;
}

export interface FlowbiteButtonInnerTheme {
base: string;
position: PositionInButtonGroup;
outline: string;
}

export interface FlowbiteButtonOutlineTheme extends FlowbiteBoolean {
color: ButtonOutlineColors;
pill: FlowbiteBoolean;
}

export interface ButtonColors
extends Pick<FlowbiteColors, 'dark' | 'failure' | 'gray' | 'info' | 'light' | 'purple' | 'success' | 'warning'> {
[key: string]: string;
Expand Down Expand Up @@ -64,6 +69,7 @@ export interface ButtonProps extends Omit<ComponentProps<'button'>, 'color' | 'r
pill?: boolean;
positionInGroup?: keyof PositionInButtonGroup;
size?: keyof ButtonSizes;
theme?: FlowbiteButtonTheme;
}

const ButtonComponent = forwardRef<HTMLButtonElement | HTMLAnchorElement, ButtonProps>(
Expand All @@ -82,14 +88,14 @@ const ButtonComponent = forwardRef<HTMLButtonElement | HTMLAnchorElement, Button
positionInGroup = 'none',
size = 'md',
className,
theme: customTheme = {},
...props
},
ref,
) => {
const isLink = typeof href !== 'undefined';

const { buttonGroup: groupTheme, button: theme } = useTheme().theme;
const { buttonGroup: groupTheme, button: theme } = mergeDeep(useTheme().theme, customTheme);

const isLink = typeof href !== 'undefined';
const Component = isLink ? 'a' : 'button';
const theirProps = props as object;

Expand Down
11 changes: 3 additions & 8 deletions src/lib/components/Card/Card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import classNames from 'classnames';
import type { ComponentProps, FC, PropsWithChildren } from 'react';
import { DeepPartial } from '..';
import { mergeDeep } from '../../helpers/mergeDeep';
import { FlowbiteBoolean } from '../Flowbite/FlowbiteTheme';
import { useTheme } from '../Flowbite/ThemeContext';

export interface FlowbiteCardTheme {
Expand All @@ -12,19 +13,13 @@ export interface FlowbiteCardTheme {
export interface FlowbiteCardRootTheme {
base: string;
children: string;
horizontal: {
off: string;
on: string;
};
horizontal: FlowbiteBoolean;
href: string;
}

export interface FlowbiteCardImageTheme {
base: string;
horizontal: {
off: string;
on: string;
};
horizontal: FlowbiteBoolean;
}

export interface CardProps extends PropsWithChildren<ComponentProps<'div'>> {
Expand Down
63 changes: 38 additions & 25 deletions src/lib/components/Carousel/Carousel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,33 +3,44 @@ import type { ComponentProps, FC, PropsWithChildren, ReactElement, ReactNode } f
import { Children, cloneElement, useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { HiOutlineChevronLeft, HiOutlineChevronRight } from 'react-icons/hi';
import ScrollContainer from 'react-indiana-drag-scroll';
import { mergeDeep } from '../../helpers/mergeDeep';
import windowExists from '../../helpers/window-exists';
import { FlowbiteBoolean } from '../Flowbite/FlowbiteTheme';
import { useTheme } from '../Flowbite/ThemeContext';

export interface FlowbiteCarouselTheme {
root: FlowbiteCarouselRootTheme;
indicators: FlowbiteCarouselIndicatorsTheme;
item: FlowbiteCarouselItemTheme;
control: FlowbiteCarouselControlTheme;
scrollContainer: FlowbiteCarouselScrollContainer;
}

export interface FlowbiteCarouselRootTheme {
base: string;
indicators: {
active: {
off: string;
on: string;
};
base: string;
wrapper: string;
};
item: {
base: string;
wrapper: string;
};
control: {
base: string;
icon: string;
};
leftControl: string;
rightControl: string;
scrollContainer: {
base: string;
snap: string;
};
}

export interface FlowbiteCarouselIndicatorsTheme {
active: FlowbiteBoolean;
base: string;
wrapper: string;
}

export interface FlowbiteCarouselItemTheme {
base: string;
wrapper: string;
}

export interface FlowbiteCarouselControlTheme {
base: string;
icon: string;
}

export interface FlowbiteCarouselScrollContainer {
base: string;
snap: string;
}

export interface CarouselProps extends PropsWithChildren<ComponentProps<'div'>> {
Expand All @@ -38,6 +49,7 @@ export interface CarouselProps extends PropsWithChildren<ComponentProps<'div'>>
rightControl?: ReactNode;
slide?: boolean;
slideInterval?: number;
theme?: FlowbiteCarouselTheme;
}

export const Carousel: FC<CarouselProps> = ({
Expand All @@ -48,14 +60,15 @@ export const Carousel: FC<CarouselProps> = ({
slide = true,
slideInterval,
className,
theme: customTheme = {},
...props
}): JSX.Element => {
const isDeviceMobile = windowExists() && navigator.userAgent.indexOf('IEMobile') !== -1;
const theme = mergeDeep(useTheme().theme.carousel, customTheme);

const isDeviceMobile = windowExists() && navigator.userAgent.indexOf('IEMobile') !== -1;
const carouselContainer = useRef<HTMLDivElement>(null);
const [activeItem, setActiveItem] = useState(0);
const [isDragging, setIsDragging] = useState(false);
const theme = useTheme().theme.carousel;

const items = useMemo(
() =>
Expand Down Expand Up @@ -96,7 +109,7 @@ export const Carousel: FC<CarouselProps> = ({
const handleDragging = (dragging: boolean) => () => setIsDragging(dragging);

return (
<div className={classNames(theme.base, className)} data-testid="carousel" {...props}>
<div className={classNames(theme.root.base, className)} data-testid="carousel" {...props}>
<ScrollContainer
className={classNames(
theme.scrollContainer.base,
Expand Down Expand Up @@ -141,7 +154,7 @@ export const Carousel: FC<CarouselProps> = ({

{items && (
<>
<div className={theme.leftControl}>
<div className={theme.root.leftControl}>
<button
className="group"
data-testid="carousel-left-control"
Expand All @@ -151,7 +164,7 @@ export const Carousel: FC<CarouselProps> = ({
{leftControl ? leftControl : <DefaultLeftControl />}
</button>
</div>
<div className={theme.rightControl}>
<div className={theme.root.rightControl}>
<button
className="group"
data-testid="carousel-right-control"
Expand Down
21 changes: 15 additions & 6 deletions src/lib/components/DarkThemeToggle/DarkThemeToggle.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,32 +2,41 @@ import classNames from 'classnames';
import type { ComponentProps, FC } from 'react';
import { useContext } from 'react';
import { HiMoon, HiSun } from 'react-icons/hi';
import { DeepPartial } from '..';
import { mergeDeep } from '../../helpers/mergeDeep';
import { ThemeContext, useTheme } from '../Flowbite/ThemeContext';

export interface FlowbiteDarkThemeToggleTheme {
root: FlowbiteDarkThemeToggleRootTheme;
}

export interface FlowbiteDarkThemeToggleRootTheme {
base: string;
icon: string;
}

export type DarkThemeToggleProps = ComponentProps<'button'>;
export interface DarkThemeToggleProps extends ComponentProps<'button'> {
theme?: DeepPartial<FlowbiteDarkThemeToggleTheme>;
}

export const DarkThemeToggle: FC<DarkThemeToggleProps> = ({ className, theme: customTheme = {}, ...props }) => {
const theme = mergeDeep(useTheme().theme.darkThemeToggle, customTheme);

export const DarkThemeToggle: FC<DarkThemeToggleProps> = ({ className, ...props }) => {
const theme = useTheme().theme.darkThemeToggle;
const { mode, toggleMode } = useContext(ThemeContext);

return (
<button
className={classNames(theme.base, className)}
className={classNames(theme.root.base, className)}
data-testid="dark-theme-toggle"
onClick={toggleMode}
type="button"
aria-label="Toggle dark mode"
{...props}
>
{mode === 'dark' ? (
<HiSun aria-label="Currently dark mode" className={theme.icon} />
<HiSun aria-label="Currently dark mode" className={theme.root.icon} />
) : (
<HiMoon aria-label="Currently light mode" className={theme.icon} />
<HiMoon aria-label="Currently light mode" className={theme.root.icon} />
)}
</button>
);
Expand Down
22 changes: 14 additions & 8 deletions src/lib/components/FileInput/FileInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,20 @@ import { HelperText } from '../HelperText';
import type { TextInputColors, TextInputSizes } from '../TextInput';

export interface FlowbiteFileInputTheme {
root: FlowbiteFileInputRootTheme;
field: FlowbiteFileInputFieldTheme;
}

export interface FlowbiteFileInputRootTheme {
base: string;
}

export interface FlowbiteFileInputFieldTheme {
base: string;
field: {
input: {
base: string;
input: {
base: string;
sizes: TextInputSizes;
colors: TextInputColors;
};
sizes: TextInputSizes;
colors: TextInputColors;
};
}

Expand All @@ -27,12 +33,12 @@ export interface FileInputProps extends Omit<ComponentProps<'input'>, 'type' | '
}

export const FileInput = forwardRef<HTMLInputElement, FileInputProps>(
({ theme: customTheme = {}, sizing = 'md', helperText, color = 'gray', className, ...props }, ref) => {
({ sizing = 'md', helperText, color = 'gray', className, theme: customTheme = {}, ...props }, ref) => {
const theme = mergeDeep(useTheme().theme.fileInput, customTheme);

return (
<>
<div className={classNames(theme.base, className)}>
<div className={classNames(theme.root.base, className)}>
<div className={theme.field.base}>
<input
className={classNames(
Expand Down
Loading

0 comments on commit 8cbb0ae

Please sign in to comment.