Skip to content

Commit

Permalink
feat: add theme prop (#488)
Browse files Browse the repository at this point in the history
  • Loading branch information
yurisldk authored Dec 15, 2022
1 parent 8f87019 commit fb34230
Show file tree
Hide file tree
Showing 11 changed files with 157 additions and 61 deletions.
17 changes: 12 additions & 5 deletions src/lib/components/Checkbox/Checkbox.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,24 @@
import classNames from 'classnames';
import type { ComponentProps } from 'react';
import { forwardRef } from 'react';
import { DeepPartial } from '..';
import { mergeDeep } from '../../helpers/mergeDeep';
import { useTheme } from '../Flowbite/ThemeContext';

export interface FlowbiteCheckboxTheme {
base: string;
}

export type CheckboxProps = Omit<ComponentProps<'input'>, 'type' | 'ref'>;
export interface CheckboxProps extends Omit<ComponentProps<'input'>, 'type' | 'ref'> {
theme?: DeepPartial<FlowbiteCheckboxTheme>;
}

export const Checkbox = forwardRef<HTMLInputElement, CheckboxProps>(
({ theme: customTheme = {}, className, ...props }, ref) => {
const theme = mergeDeep(useTheme().theme.checkbox, customTheme);

export const Checkbox = forwardRef<HTMLInputElement, CheckboxProps>(({ className, ...props }, ref) => {
const theme = useTheme().theme.checkbox;
return <input ref={ref} className={classNames(theme.base, className)} type="checkbox" {...props} />;
});
return <input ref={ref} className={classNames(theme.base, className)} type="checkbox" {...props} />;
},
);

Checkbox.displayName = 'Checkbox';
8 changes: 6 additions & 2 deletions src/lib/components/FileInput/FileInput.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import classNames from 'classnames';
import type { ComponentProps, ReactNode } from 'react';
import { forwardRef } from 'react';
import { DeepPartial } from '..';
import { mergeDeep } from '../../helpers/mergeDeep';
import { useTheme } from '../Flowbite/ThemeContext';
import { HelperText } from '../HelperText';
import type { TextInputColors, TextInputSizes } from '../TextInput';
Expand All @@ -21,11 +23,13 @@ export interface FileInputProps extends Omit<ComponentProps<'input'>, 'type' | '
sizing?: keyof TextInputSizes;
helperText?: ReactNode;
color?: keyof TextInputColors;
theme?: DeepPartial<FlowbiteFileInputTheme>;
}

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

return (
<>
<div className={classNames(theme.base, className)}>
Expand Down
37 changes: 17 additions & 20 deletions src/lib/components/Navbar/Navbar.tsx
Original file line number Diff line number Diff line change
@@ -1,44 +1,40 @@
import classNames from 'classnames';
import type { ComponentProps, FC, PropsWithChildren } from 'react';
import { useState } from 'react';
import { DeepPartial } from '..';
import { mergeDeep } from '../../helpers/mergeDeep';
import { FlowbiteBoolean } from '../Flowbite/FlowbiteTheme';
import { useTheme } from '../Flowbite/ThemeContext';
import { NavbarBrand } from './NavbarBrand';
import { NavbarCollapse } from './NavbarCollapse';
import { FlowbiteNavbarBrandTheme, NavbarBrand } from './NavbarBrand';
import { FlowbiteNavbarCollapseTheme, NavbarCollapse } from './NavbarCollapse';
import { NavbarContext } from './NavbarContext';
import { NavbarLink } from './NavbarLink';
import { NavbarToggle } from './NavbarToggle';
import { FlowbiteNavbarLinkTheme, NavbarLink } from './NavbarLink';
import { FlowbiteNavbarToggleTheme, NavbarToggle } from './NavbarToggle';

export interface FlowbiteNavbarTheme {
root: FlowbiteNavbarRootTheme;
brand: FlowbiteNavbarBrandTheme;
collapse: FlowbiteNavbarCollapseTheme;
link: FlowbiteNavbarLinkTheme;
toggle: FlowbiteNavbarToggleTheme;
}

export interface FlowbiteNavbarRootTheme {
base: string;
rounded: FlowbiteBoolean;
bordered: FlowbiteBoolean;
inner: {
base: string;
fluid: FlowbiteBoolean;
};
brand: string;
collapse: {
base: string;
list: string;
hidden: FlowbiteBoolean;
};
link: {
base: string;
active: FlowbiteBoolean;
disabled: FlowbiteBoolean;
};
toggle: {
base: string;
icon: string;
};
}

export interface NavbarComponentProps extends PropsWithChildren<ComponentProps<'nav'>> {
menuOpen?: boolean;
fluid?: boolean;
rounded?: boolean;
border?: boolean;
theme?: DeepPartial<FlowbiteNavbarRootTheme>;
}

const NavbarComponent: FC<NavbarComponentProps> = ({
Expand All @@ -48,11 +44,12 @@ const NavbarComponent: FC<NavbarComponentProps> = ({
rounded,
border,
className,
theme: customTheme = {},
...props
}) => {
const [isOpen, setIsOpen] = useState(menuOpen);

const theme = useTheme().theme.navbar;
const theme = mergeDeep(useTheme().theme.navbar.root, customTheme);

return (
<NavbarContext.Provider value={{ isOpen, setIsOpen }}>
Expand Down
17 changes: 13 additions & 4 deletions src/lib/components/Navbar/NavbarBrand.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,22 @@
import classNames from 'classnames';
import type { ComponentProps, FC, PropsWithChildren } from 'react';
import { DeepPartial } from '..';
import { mergeDeep } from '../../helpers/mergeDeep';
import { useTheme } from '../Flowbite/ThemeContext';

export type NavbarBrandProps = PropsWithChildren<ComponentProps<'a'>>;
export interface FlowbiteNavbarBrandTheme {
base: string;
}

export interface NavbarBrandProps extends PropsWithChildren<ComponentProps<'a'>> {
theme?: DeepPartial<FlowbiteNavbarBrandTheme>;
}

export const NavbarBrand: FC<NavbarBrandProps> = ({ theme: customTheme = {}, children, href, className, ...props }) => {
const theme = mergeDeep(useTheme().theme.navbar.brand, customTheme);

export const NavbarBrand: FC<NavbarBrandProps> = ({ children, href, className, ...props }) => {
const theme = useTheme().theme.navbar;
return (
<a href={href} className={classNames(theme.brand, className)} {...props}>
<a href={href} className={classNames(theme.base, className)} {...props}>
{children}
</a>
);
Expand Down
22 changes: 19 additions & 3 deletions src/lib/components/Navbar/NavbarCollapse.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,30 @@
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';
import { useNavbarContext } from './NavbarContext';

export type NavbarCollapseProps = PropsWithChildren<ComponentProps<'div'>>;
export interface FlowbiteNavbarCollapseTheme {
base: string;
list: string;
hidden: FlowbiteBoolean;
}

export const NavbarCollapse: FC<NavbarCollapseProps> = ({ children, className, ...props }): JSX.Element => {
export interface NavbarCollapseProps extends PropsWithChildren<ComponentProps<'div'>> {
theme?: DeepPartial<FlowbiteNavbarCollapseTheme>;
}

export const NavbarCollapse: FC<NavbarCollapseProps> = ({
theme: customTheme = {},
children,
className,
...props
}): JSX.Element => {
const { isOpen } = useNavbarContext();

const theme = useTheme().theme.navbar.collapse;
const theme = mergeDeep(useTheme().theme.navbar.collapse, customTheme);

return (
<div
Expand Down
22 changes: 20 additions & 2 deletions src/lib/components/Navbar/NavbarLink.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,33 @@
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 FlowbiteNavbarLinkTheme {
base: string;
active: FlowbiteBoolean;
disabled: FlowbiteBoolean;
}

export interface NavbarLinkProps extends PropsWithChildren<ComponentProps<'a'>> {
active?: boolean;
disabled?: boolean;
href?: string;
theme?: DeepPartial<FlowbiteNavbarLinkTheme>;
}

export const NavbarLink: FC<NavbarLinkProps> = ({ active, disabled, href, children, className, ...props }) => {
const theme = useTheme().theme.navbar.link;
export const NavbarLink: FC<NavbarLinkProps> = ({
active,
disabled,
href,
theme: customTheme = {},
children,
className,
...props
}) => {
const theme = mergeDeep(useTheme().theme.navbar.link, customTheme);

return (
<li>
Expand Down
17 changes: 15 additions & 2 deletions src/lib/components/Navbar/NavbarToggle.tsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,34 @@
import classNames from 'classnames';
import type { ComponentProps, FC } from 'react';
import { GoThreeBars } from 'react-icons/go';
import { DeepPartial } from '..';
import { mergeDeep } from '../../helpers/mergeDeep';
import { useTheme } from '../Flowbite/ThemeContext';
import { useNavbarContext } from './NavbarContext';

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

export interface NavbarToggleProps extends ComponentProps<'button'> {
barIcon?: FC<ComponentProps<'svg'>>;
theme?: DeepPartial<FlowbiteNavbarToggleTheme>;
}

export const NavbarToggle: FC<NavbarToggleProps> = ({ barIcon: BarIcon = GoThreeBars, className, ...props }) => {
export const NavbarToggle: FC<NavbarToggleProps> = ({
barIcon: BarIcon = GoThreeBars,
theme: customTheme = {},
className,
...props
}) => {
const { isOpen, setIsOpen } = useNavbarContext();

const handleClick = () => {
setIsOpen(!isOpen);
};

const theme = useTheme().theme.navbar.toggle;
const theme = mergeDeep(useTheme().theme.navbar.toggle, customTheme);

return (
<button
Expand Down
17 changes: 12 additions & 5 deletions src/lib/components/Radio/Radio.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,24 @@
import classNames from 'classnames';
import type { ComponentProps } from 'react';
import { forwardRef } from 'react';
import { DeepPartial } from '..';
import { mergeDeep } from '../../helpers/mergeDeep';
import { useTheme } from '../Flowbite/ThemeContext';

export interface FlowbiteRadioTheme {
base: string;
}

export type RadioProps = Omit<ComponentProps<'input'>, 'type' | 'ref'>;
export interface RadioProps extends Omit<ComponentProps<'input'>, 'type' | 'ref'> {
theme?: DeepPartial<FlowbiteRadioTheme>;
}

export const Radio = forwardRef<HTMLInputElement, RadioProps>(
({ theme: customTheme = {}, className, ...props }, ref) => {
const theme = mergeDeep(useTheme().theme.radio, customTheme);

export const Radio = forwardRef<HTMLInputElement, RadioProps>(({ className, ...props }, ref) => {
const theme = useTheme().theme.radio;
return <input ref={ref} className={classNames(theme.base, className)} type="radio" {...props} />;
});
return <input ref={ref} className={classNames(theme.base, className)} type="radio" {...props} />;
},
);

Radio.displayName = 'Radio';
21 changes: 19 additions & 2 deletions src/lib/components/TextInput/TextInput.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import classNames from 'classnames';
import type { ComponentProps, FC, ReactNode } from 'react';
import { forwardRef } from 'react';
import { DeepPartial } from '..';
import { mergeDeep } from '../../helpers/mergeDeep';
import type { FlowbiteBoolean, FlowbiteColors, FlowbiteSizes } from '../Flowbite/FlowbiteTheme';
import { useTheme } from '../Flowbite/ThemeContext';
import { HelperText } from '../HelperText';
Expand Down Expand Up @@ -40,11 +42,26 @@ export interface TextInputProps extends Omit<ComponentProps<'input'>, 'ref' | 'c
addon?: ReactNode;
icon?: FC<ComponentProps<'svg'>>;
color?: keyof TextInputColors;
theme?: DeepPartial<FlowbiteTextInputTheme>;
}

export const TextInput = forwardRef<HTMLInputElement, TextInputProps>(
({ sizing = 'md', shadow, helperText, addon, icon: Icon, color = 'gray', className, ...props }, ref) => {
const theme = useTheme().theme.textInput;
(
{
sizing = 'md',
shadow,
helperText,
addon,
icon: Icon,
color = 'gray',
className,
theme: customTheme = {},
...props
},
ref,
) => {
const theme = mergeDeep(useTheme().theme.textInput, customTheme);

return (
<>
<div className={classNames(theme.base, className)}>
Expand Down
6 changes: 5 additions & 1 deletion src/lib/components/ToggleSwitch/ToggleSwitch.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import classNames from 'classnames';
import type { ComponentProps, FC, KeyboardEvent, MouseEvent } from 'react';
import { useId } from 'react';
import { DeepPartial } from '..';
import { mergeDeep } from '../../helpers/mergeDeep';
import { FlowbiteBoolean, FlowbiteColors } from '../Flowbite/FlowbiteTheme';
import { useTheme } from '../Flowbite/ThemeContext';

Expand All @@ -21,6 +23,7 @@ export type ToggleSwitchProps = Omit<ComponentProps<'button'>, 'onChange'> & {
label: string;
color?: FlowbiteColors;
onChange: (checked: boolean) => void;
theme?: DeepPartial<FlowbiteToggleSwitchTheme>;
};

export const ToggleSwitch: FC<ToggleSwitchProps> = ({
Expand All @@ -31,9 +34,10 @@ export const ToggleSwitch: FC<ToggleSwitchProps> = ({
onChange,
className,
color = 'blue',
theme: customTheme = {},
...props
}) => {
const theme = useTheme().theme.toggleSwitch;
const theme = mergeDeep(useTheme().theme.toggleSwitch, customTheme);
const id = useId();

const toggle = (): void => onChange(!checked);
Expand Down
Loading

0 comments on commit fb34230

Please sign in to comment.