Skip to content

Commit fb07e4c

Browse files
author
Ricardo Lüders
committed
feat(theme): adding theme prop to components
1 parent ffe5480 commit fb07e4c

File tree

23 files changed

+312
-161
lines changed

23 files changed

+312
-161
lines changed

src/lib/components/Accordion/AccordionTitle.tsx

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,7 @@ import { useAccordionContext } from './AccordionPanelContext';
99
export interface FlowbiteAccordionTitleTheme {
1010
arrow: {
1111
base: string;
12-
open: {
13-
off: string;
14-
on: string;
15-
};
12+
open: FlowbiteBoolean;
1613
};
1714
base: string;
1815
flush: FlowbiteBoolean;

src/lib/components/Avatar/Avatar.tsx

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import classNames from 'classnames';
22
import type { ComponentProps, FC, PropsWithChildren, ReactElement } from 'react';
33
import { DeepPartial } from '..';
44
import { mergeDeep } from '../../helpers/mergeDeep';
5-
import type { FlowbiteColors, FlowbitePositions, FlowbiteSizes } from '../Flowbite/FlowbiteTheme';
5+
import type { FlowbiteBoolean, FlowbiteColors, FlowbitePositions, FlowbiteSizes } from '../Flowbite/FlowbiteTheme';
66
import { useTheme } from '../Flowbite/ThemeContext';
77
import AvatarGroup from './AvatarGroup';
88
import AvatarGroupCounter from './AvatarGroupCounter';
@@ -24,9 +24,7 @@ export interface FlowbiteAvatarRootTheme {
2424
statusPosition: FlowbitePositions;
2525
}
2626

27-
export interface FlowbiteAvatarImageTheme {
28-
off: string;
29-
on: string;
27+
export interface FlowbiteAvatarImageTheme extends FlowbiteBoolean {
3028
placeholder: string;
3129
}
3230

src/lib/components/Badge/Badge.tsx

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import classNames from 'classnames';
22
import type { ComponentProps, FC, PropsWithChildren } from 'react';
33
import { DeepPartial } from '..';
44
import { mergeDeep } from '../../helpers/mergeDeep';
5-
import type { FlowbiteColors, FlowbiteSizes } from '../Flowbite/FlowbiteTheme';
5+
import type { FlowbiteBoolean, FlowbiteColors, FlowbiteSizes } from '../Flowbite/FlowbiteTheme';
66
import { useTheme } from '../Flowbite/ThemeContext';
77

88
export interface FlowbiteBadgeTheme {
@@ -17,9 +17,7 @@ export interface FlowbiteBadgeRootTheme {
1717
size: BadgeSizes;
1818
}
1919

20-
export interface FlowbiteBadgeIconTheme {
21-
off: string;
22-
on: string;
20+
export interface FlowbiteBadgeIconTheme extends FlowbiteBoolean {
2321
size: BadgeSizes;
2422
}
2523

src/lib/components/Breadcrumb/BreadcrumbItem.tsx

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,13 @@ import { ComponentProps, FC, forwardRef, PropsWithChildren } from 'react';
33
import { HiOutlineChevronRight } from 'react-icons/hi';
44
import { DeepPartial } from '..';
55
import { mergeDeep } from '../../helpers/mergeDeep';
6+
import { FlowbiteBoolean } from '../Flowbite/FlowbiteTheme';
67
import { useTheme } from '../Flowbite/ThemeContext';
78

89
export interface FlowbiteBreadcrumbItemTheme {
910
base: string;
1011
chevron: string;
11-
href: {
12-
off: string;
13-
on: string;
14-
};
12+
href: FlowbiteBoolean;
1513
icon: string;
1614
}
1715

src/lib/components/Button/Button.tsx

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import classNames from 'classnames';
22
import { forwardRef, type ComponentProps, type ReactNode } from 'react';
3+
import { mergeDeep } from '../../helpers/mergeDeep';
34
import type {
45
FlowbiteBoolean,
56
FlowbiteColors,
@@ -18,20 +19,24 @@ export interface FlowbiteButtonTheme {
1819
disabled: string;
1920
gradient: ButtonGradientColors;
2021
gradientDuoTone: ButtonGradientDuoToneColors;
21-
inner: {
22-
base: string;
23-
position: PositionInButtonGroup;
24-
outline: string;
25-
};
22+
inner: FlowbiteButtonInnerTheme;
2623
label: string;
27-
outline: FlowbiteBoolean & {
28-
color: ButtonOutlineColors;
29-
pill: FlowbiteBoolean;
30-
};
24+
outline: FlowbiteButtonOutlineTheme;
3125
pill: FlowbiteBoolean;
3226
size: ButtonSizes;
3327
}
3428

29+
export interface FlowbiteButtonInnerTheme {
30+
base: string;
31+
position: PositionInButtonGroup;
32+
outline: string;
33+
}
34+
35+
export interface FlowbiteButtonOutlineTheme extends FlowbiteBoolean {
36+
color: ButtonOutlineColors;
37+
pill: FlowbiteBoolean;
38+
}
39+
3540
export interface ButtonColors
3641
extends Pick<FlowbiteColors, 'dark' | 'failure' | 'gray' | 'info' | 'light' | 'purple' | 'success' | 'warning'> {
3742
[key: string]: string;
@@ -64,6 +69,7 @@ export interface ButtonProps extends Omit<ComponentProps<'button'>, 'color' | 'r
6469
pill?: boolean;
6570
positionInGroup?: keyof PositionInButtonGroup;
6671
size?: keyof ButtonSizes;
72+
theme?: FlowbiteButtonTheme;
6773
}
6874

6975
const ButtonComponent = forwardRef<HTMLButtonElement | HTMLAnchorElement, ButtonProps>(
@@ -82,14 +88,14 @@ const ButtonComponent = forwardRef<HTMLButtonElement | HTMLAnchorElement, Button
8288
positionInGroup = 'none',
8389
size = 'md',
8490
className,
91+
theme: customTheme = {},
8592
...props
8693
},
8794
ref,
8895
) => {
89-
const isLink = typeof href !== 'undefined';
90-
91-
const { buttonGroup: groupTheme, button: theme } = useTheme().theme;
96+
const { buttonGroup: groupTheme, button: theme } = mergeDeep(useTheme().theme, customTheme);
9297

98+
const isLink = typeof href !== 'undefined';
9399
const Component = isLink ? 'a' : 'button';
94100
const theirProps = props as object;
95101

src/lib/components/Card/Card.tsx

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import classNames from 'classnames';
22
import type { ComponentProps, FC, PropsWithChildren } from 'react';
33
import { DeepPartial } from '..';
44
import { mergeDeep } from '../../helpers/mergeDeep';
5+
import { FlowbiteBoolean } from '../Flowbite/FlowbiteTheme';
56
import { useTheme } from '../Flowbite/ThemeContext';
67

78
export interface FlowbiteCardTheme {
@@ -12,19 +13,13 @@ export interface FlowbiteCardTheme {
1213
export interface FlowbiteCardRootTheme {
1314
base: string;
1415
children: string;
15-
horizontal: {
16-
off: string;
17-
on: string;
18-
};
16+
horizontal: FlowbiteBoolean;
1917
href: string;
2018
}
2119

2220
export interface FlowbiteCardImageTheme {
2321
base: string;
24-
horizontal: {
25-
off: string;
26-
on: string;
27-
};
22+
horizontal: FlowbiteBoolean;
2823
}
2924

3025
export interface CardProps extends PropsWithChildren<ComponentProps<'div'>> {

src/lib/components/Carousel/Carousel.tsx

Lines changed: 38 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -3,33 +3,44 @@ import type { ComponentProps, FC, PropsWithChildren, ReactElement, ReactNode } f
33
import { Children, cloneElement, useCallback, useEffect, useMemo, useRef, useState } from 'react';
44
import { HiOutlineChevronLeft, HiOutlineChevronRight } from 'react-icons/hi';
55
import ScrollContainer from 'react-indiana-drag-scroll';
6+
import { mergeDeep } from '../../helpers/mergeDeep';
67
import windowExists from '../../helpers/window-exists';
8+
import { FlowbiteBoolean } from '../Flowbite/FlowbiteTheme';
79
import { useTheme } from '../Flowbite/ThemeContext';
810

911
export interface FlowbiteCarouselTheme {
12+
root: FlowbiteCarouselRootTheme;
13+
indicators: FlowbiteCarouselIndicatorsTheme;
14+
item: FlowbiteCarouselItemTheme;
15+
control: FlowbiteCarouselControlTheme;
16+
scrollContainer: FlowbiteCarouselScrollContainer;
17+
}
18+
19+
export interface FlowbiteCarouselRootTheme {
1020
base: string;
11-
indicators: {
12-
active: {
13-
off: string;
14-
on: string;
15-
};
16-
base: string;
17-
wrapper: string;
18-
};
19-
item: {
20-
base: string;
21-
wrapper: string;
22-
};
23-
control: {
24-
base: string;
25-
icon: string;
26-
};
2721
leftControl: string;
2822
rightControl: string;
29-
scrollContainer: {
30-
base: string;
31-
snap: string;
32-
};
23+
}
24+
25+
export interface FlowbiteCarouselIndicatorsTheme {
26+
active: FlowbiteBoolean;
27+
base: string;
28+
wrapper: string;
29+
}
30+
31+
export interface FlowbiteCarouselItemTheme {
32+
base: string;
33+
wrapper: string;
34+
}
35+
36+
export interface FlowbiteCarouselControlTheme {
37+
base: string;
38+
icon: string;
39+
}
40+
41+
export interface FlowbiteCarouselScrollContainer {
42+
base: string;
43+
snap: string;
3344
}
3445

3546
export interface CarouselProps extends PropsWithChildren<ComponentProps<'div'>> {
@@ -38,6 +49,7 @@ export interface CarouselProps extends PropsWithChildren<ComponentProps<'div'>>
3849
rightControl?: ReactNode;
3950
slide?: boolean;
4051
slideInterval?: number;
52+
theme?: FlowbiteCarouselTheme;
4153
}
4254

4355
export const Carousel: FC<CarouselProps> = ({
@@ -48,14 +60,15 @@ export const Carousel: FC<CarouselProps> = ({
4860
slide = true,
4961
slideInterval,
5062
className,
63+
theme: customTheme = {},
5164
...props
5265
}): JSX.Element => {
53-
const isDeviceMobile = windowExists() && navigator.userAgent.indexOf('IEMobile') !== -1;
66+
const theme = mergeDeep(useTheme().theme.carousel, customTheme);
5467

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

6073
const items = useMemo(
6174
() =>
@@ -96,7 +109,7 @@ export const Carousel: FC<CarouselProps> = ({
96109
const handleDragging = (dragging: boolean) => () => setIsDragging(dragging);
97110

98111
return (
99-
<div className={classNames(theme.base, className)} data-testid="carousel" {...props}>
112+
<div className={classNames(theme.root.base, className)} data-testid="carousel" {...props}>
100113
<ScrollContainer
101114
className={classNames(
102115
theme.scrollContainer.base,
@@ -141,7 +154,7 @@ export const Carousel: FC<CarouselProps> = ({
141154

142155
{items && (
143156
<>
144-
<div className={theme.leftControl}>
157+
<div className={theme.root.leftControl}>
145158
<button
146159
className="group"
147160
data-testid="carousel-left-control"
@@ -151,7 +164,7 @@ export const Carousel: FC<CarouselProps> = ({
151164
{leftControl ? leftControl : <DefaultLeftControl />}
152165
</button>
153166
</div>
154-
<div className={theme.rightControl}>
167+
<div className={theme.root.rightControl}>
155168
<button
156169
className="group"
157170
data-testid="carousel-right-control"

src/lib/components/DarkThemeToggle/DarkThemeToggle.tsx

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,32 +2,41 @@ import classNames from 'classnames';
22
import type { ComponentProps, FC } from 'react';
33
import { useContext } from 'react';
44
import { HiMoon, HiSun } from 'react-icons/hi';
5+
import { DeepPartial } from '..';
6+
import { mergeDeep } from '../../helpers/mergeDeep';
57
import { ThemeContext, useTheme } from '../Flowbite/ThemeContext';
68

79
export interface FlowbiteDarkThemeToggleTheme {
10+
root: FlowbiteDarkThemeToggleRootTheme;
11+
}
12+
13+
export interface FlowbiteDarkThemeToggleRootTheme {
814
base: string;
915
icon: string;
1016
}
1117

12-
export type DarkThemeToggleProps = ComponentProps<'button'>;
18+
export interface DarkThemeToggleProps extends ComponentProps<'button'> {
19+
theme?: DeepPartial<FlowbiteDarkThemeToggleTheme>;
20+
}
21+
22+
export const DarkThemeToggle: FC<DarkThemeToggleProps> = ({ className, theme: customTheme = {}, ...props }) => {
23+
const theme = mergeDeep(useTheme().theme.darkThemeToggle, customTheme);
1324

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

1827
return (
1928
<button
20-
className={classNames(theme.base, className)}
29+
className={classNames(theme.root.base, className)}
2130
data-testid="dark-theme-toggle"
2231
onClick={toggleMode}
2332
type="button"
2433
aria-label="Toggle dark mode"
2534
{...props}
2635
>
2736
{mode === 'dark' ? (
28-
<HiSun aria-label="Currently dark mode" className={theme.icon} />
37+
<HiSun aria-label="Currently dark mode" className={theme.root.icon} />
2938
) : (
30-
<HiMoon aria-label="Currently light mode" className={theme.icon} />
39+
<HiMoon aria-label="Currently light mode" className={theme.root.icon} />
3140
)}
3241
</button>
3342
);

src/lib/components/FileInput/FileInput.tsx

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,23 @@ import { HelperText } from '../HelperText';
88
import type { TextInputColors, TextInputSizes } from '../TextInput';
99

1010
export interface FlowbiteFileInputTheme {
11+
root: FlowbiteFileInputRootTheme;
12+
field: FlowbiteFileInputFieldTheme;
13+
}
14+
15+
export interface FlowbiteFileInputRootTheme {
16+
base: string;
17+
}
18+
19+
export interface FlowbiteFileInputFieldTheme {
20+
base: string;
21+
input: FlowbiteFileInputFieldInputTheme;
22+
}
23+
24+
export interface FlowbiteFileInputFieldInputTheme {
1125
base: string;
12-
field: {
13-
base: string;
14-
input: {
15-
base: string;
16-
sizes: TextInputSizes;
17-
colors: TextInputColors;
18-
};
19-
};
26+
sizes: TextInputSizes;
27+
colors: TextInputColors;
2028
}
2129

2230
export interface FileInputProps extends Omit<ComponentProps<'input'>, 'type' | 'ref' | 'color'> {
@@ -27,12 +35,12 @@ export interface FileInputProps extends Omit<ComponentProps<'input'>, 'type' | '
2735
}
2836

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

3341
return (
3442
<>
35-
<div className={classNames(theme.base, className)}>
43+
<div className={classNames(theme.root.base, className)}>
3644
<div className={theme.field.base}>
3745
<input
3846
className={classNames(

0 commit comments

Comments
 (0)