Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: replace classnames by tailwind-merge #816

Merged
merged 16 commits into from
Jun 20, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions app/components/code-preview.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
'use client';

import classNames from 'classnames';
import { usePathname } from 'next/navigation';
import prismjs from 'prismjs';
import type { ComponentProps, FC, PropsWithChildren } from 'react';
Expand All @@ -9,6 +8,7 @@ import type { Options } from 'react-element-to-jsx-string';
import reactElementToJSXString from 'react-element-to-jsx-string';
import { BsCheckLg, BsFillClipboardFill } from 'react-icons/bs';
import { HiMoon, HiSun } from 'react-icons/hi';
import { twMerge } from 'tailwind-merge';
import { Tooltip } from '~/src';

const reactElementToJSXStringOptions: Options = {
Expand Down Expand Up @@ -90,11 +90,11 @@ export default function ${titleCaseToUpperCamelCase(title)}() {${
</div>
</div>
</div>
<div className={classNames('code-preview-wrapper', isDarkMode && 'dark')}>
<div className={twMerge('code-preview-wrapper', isDarkMode && 'dark')}>
<div className="code-preview flex border-x border-gray-200 bg-white bg-gradient-to-r p-0 dark:border-gray-600 dark:bg-gray-900">
<div className="code-responsive-wrapper w-full">
<div className="mx-auto w-full bg-white bg-gradient-to-r p-2 dark:bg-gray-900 sm:p-6">
<div className={classNames('py-4', className)}>{children}</div>
<div className={twMerge('py-4', className)}>{children}</div>
</div>
</div>
</div>
Expand All @@ -113,7 +113,7 @@ export default function ${titleCaseToUpperCamelCase(title)}() {${
<CopyToClipboardButton isJustCopied={isJustCopied} onClick={() => copyToClipboard(code)} />
</div>
</div>
<pre className={classNames('language-tsx !overflow-y-hidden', !isExpanded && 'max-h-72')}>
<pre className={twMerge('language-tsx !overflow-y-hidden', !isExpanded && 'max-h-72')}>
<code>{code}</code>
</pre>
<CollapseExpandButton isExpanded={isExpanded} onClick={() => setExpanded(!isExpanded)} />
Expand Down
4 changes: 2 additions & 2 deletions app/components/navbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -71,9 +71,9 @@ export const NavbarIcons: FC = () => {
<a href="https://npmjs.com/package/flowbite-react" className="hidden lg:block">
<Badge
color="info"
className="border-primary-700 !bg-primary-50 !text-sm !font-normal !text-primary-700 hover:!bg-primary-600 hover:!text-white dark:border-primary-700 dark:!bg-gray-700 dark:!text-primary-700 dark:hover:!bg-primary-800 dark:hover:!text-white lg:block"
className="border-primary-700 bg-primary-50 px-2 text-sm font-normal text-primary-700 hover:bg-primary-600 hover:text-white dark:border-primary-700 dark:bg-gray-700 dark:text-primary-700 dark:hover:bg-primary-800 dark:hover:text-white lg:block"
>
{version}
v{version}
</Badge>
</a>
</div>
Expand Down
8 changes: 4 additions & 4 deletions app/docs/components/table/table.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,7 @@ Use this example to show multiple checkbox form elements for each table row that
<CodePreview importFlowbiteReact="Checkbox, Table" title="Checkbox">
<Table hoverable>
<Table.Head>
<Table.HeadCell className="!p-4">
<Table.HeadCell className="p-4">
<Checkbox />
</Table.HeadCell>
<Table.HeadCell>Product name</Table.HeadCell>
Expand All @@ -228,7 +228,7 @@ Use this example to show multiple checkbox form elements for each table row that
</Table.Head>
<Table.Body className="divide-y">
<Table.Row className="bg-white dark:border-gray-700 dark:bg-gray-800">
<Table.Cell className="!p-4">
<Table.Cell className="p-4">
<Checkbox />
</Table.Cell>
<Table.Cell className="whitespace-nowrap font-medium text-gray-900 dark:text-white">
Expand All @@ -244,7 +244,7 @@ Use this example to show multiple checkbox form elements for each table row that
</Table.Cell>
</Table.Row>
<Table.Row className="bg-white dark:border-gray-700 dark:bg-gray-800">
<Table.Cell className="!p-4">
<Table.Cell className="p-4">
<Checkbox />
</Table.Cell>
<Table.Cell className="whitespace-nowrap font-medium text-gray-900 dark:text-white">
Expand All @@ -260,7 +260,7 @@ Use this example to show multiple checkbox form elements for each table row that
</Table.Cell>
</Table.Row>
<Table.Row className="bg-white dark:border-gray-700 dark:bg-gray-800">
<Table.Cell className="!p-4">
<Table.Cell className="p-4">
<Checkbox />
</Table.Cell>
<Table.Cell className="whitespace-nowrap font-medium text-gray-900 dark:text-white">Magic Mouse 2</Table.Cell>
Expand Down
2 changes: 1 addition & 1 deletion app/docs/components/toast/toast.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ This component can be used to show more complex messages with buttons and other

<CodePreview importFlowbiteReact="Button, Toast" title="Interactive toast">
<Toast>
<div className="flex !items-start">
<div className="flex items-start">
<div className="inline-flex h-8 w-8 shrink-0 items-center justify-center rounded-lg bg-cyan-100 text-cyan-500 dark:bg-cyan-900 dark:text-cyan-300">
<MdLoop className="h-5 w-5" />
</div>
Expand Down
43 changes: 22 additions & 21 deletions app/docs/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
'use client';

import classNames from 'classnames';
import Image from 'next/image';
import Link from 'next/link';
import { usePathname } from 'next/navigation';
Expand All @@ -15,6 +14,7 @@ import 'prismjs/components/prism-typescript';
import type { FC, PropsWithChildren } from 'react';
import { useEffect, useState } from 'react';
import { HiMenuAlt1, HiX } from 'react-icons/hi';
import { twMerge } from 'tailwind-merge';
import '~/app/docs.css';
import '~/app/style.css';
import { Accordion, Badge, Flowbite, Footer, Navbar, Sidebar } from '~/src';
Expand Down Expand Up @@ -145,11 +145,9 @@ const DocsSidebar: FC<DocsLayoutState> = ({ isCollapsed, setCollapsed }) => {
return (
<>
<div
className={classNames(
className={twMerge(
'fixed inset-0 z-30 h-full w-64 flex-none lg:static lg:block lg:h-auto lg:overflow-y-visible lg:pt-0',
{
hidden: isCollapsed,
},
isCollapsed && 'hidden',
)}
>
<Sidebar
Expand All @@ -172,21 +170,24 @@ const DocsSidebar: FC<DocsLayoutState> = ({ isCollapsed, setCollapsed }) => {
off: 'mb-1 text-gray-900 dark:text-gray-300 hover:text-gray-900 dark:hover:text-gray-200',
},
}}
className={classNames(
'flex w-full items-center justify-between !bg-transparent !p-0 text-sm font-semibold uppercase tracking-wide',
className={twMerge(
'flex w-full items-center justify-between bg-transparent p-0 text-sm font-semibold uppercase tracking-wide',
pathname.includes('/getting-started/') &&
'text-primary-700 hover:text-primary-700 dark:text-primary-300 dark:hover:text-primary-200',
)}
>
Getting started
</Accordion.Title>
<Accordion.Content className="mb-2 border-none !p-0">
<Accordion.Content className="mb-2 border-none p-0">
<Sidebar.ItemGroup className="border-none">
<SidebarLink href="/docs/getting-started/introduction">Introduction</SidebarLink>
<SidebarLink href="/docs/getting-started/quickstart">Quickstart</SidebarLink>
<SidebarLink href="/docs/getting-started/nextjs">
<span className="flex items-center gap-2">
Next.js <Badge color="cyan">New</Badge>
Next.js{' '}
<Badge color="cyan" className="px-2">
New
</Badge>
</span>
</SidebarLink>
<SidebarLink href="/docs/getting-started/typescript">TypeScript</SidebarLink>
Expand All @@ -206,15 +207,15 @@ const DocsSidebar: FC<DocsLayoutState> = ({ isCollapsed, setCollapsed }) => {
off: 'mb-1 text-gray-900 dark:text-gray-300 hover:text-gray-900 dark:hover:text-gray-200',
},
}}
className={classNames(
'flex w-full items-center justify-between !bg-transparent !p-0 text-sm font-semibold uppercase tracking-wide',
className={twMerge(
'flex w-full items-center justify-between bg-transparent p-0 text-sm font-semibold uppercase tracking-wide',
pathname.includes('/customize/') &&
'text-primary-700 hover:text-primary-700 dark:text-primary-300 dark:hover:text-primary-200',
)}
>
Customize
</Accordion.Title>
<Accordion.Content className="mb-2 space-y-0.5 border-none !p-0">
<Accordion.Content className="mb-2 space-y-0.5 border-none p-0">
<Sidebar.ItemGroup className="border-none">
<SidebarLink href="/docs/customize/theme">Theme</SidebarLink>
<SidebarLink href="/docs/customize/dark-mode">Dark mode</SidebarLink>
Expand All @@ -223,23 +224,23 @@ const DocsSidebar: FC<DocsLayoutState> = ({ isCollapsed, setCollapsed }) => {
</Accordion.Panel>
</Accordion>
<Accordion collapseAll={!pathname.includes('/components/')} flush className="border-none">
<Accordion.Panel className="focus:!outline-none focus:!ring-0">
<Accordion.Panel className="focus:outline-none focus:ring-0">
<Accordion.Title
theme={{
open: {
on: 'mb-2 text-primary-700 hover:text-primary-700 dark:text-primary-300 dark:hover:text-primary-200',
off: 'mb-1 text-gray-900 dark:text-gray-300 hover:text-gray-900 dark:hover:text-gray-200',
},
}}
className={classNames(
'flex w-full items-center justify-between !bg-transparent !p-0 text-sm font-semibold uppercase tracking-wide',
className={twMerge(
'flex w-full items-center justify-between bg-transparent p-0 text-sm font-semibold uppercase tracking-wide',
pathname.includes('/components/') &&
'text-primary-700 hover:text-primary-700 dark:text-primary-300 dark:hover:text-primary-200',
)}
>
Components
</Accordion.Title>
<Accordion.Content className="mb-2 border-none !p-0">
<Accordion.Content className="mb-2 border-none p-0">
<Sidebar.ItemGroup className="border-none">
<SidebarLink href="/docs/components/accordion">Accordion</SidebarLink>
<SidebarLink href="/docs/components/alert">Alert</SidebarLink>
Expand Down Expand Up @@ -293,11 +294,11 @@ const SidebarLink: FC<PropsWithChildren & { href: string }> = ({ children, href
<Sidebar.Item
as={Link}
href={href}
className={classNames(
'!p-0 !font-medium transition-all hover:!bg-transparent lg:text-sm [&>*]:px-0',
className={twMerge(
'p-0 font-medium transition-all hover:bg-transparent lg:text-sm [&>*]:px-0',
pathname === href
? '!text-primary-700 hover:!text-primary-800 dark:!text-primary-200'
: '!text-gray-500 hover:!text-gray-900 dark:hover:!text-gray-200',
? 'text-primary-700 hover:text-primary-800 dark:text-primary-200'
: 'text-gray-500 hover:text-gray-900 dark:hover:text-gray-200',
)}
>
{children}
Expand Down Expand Up @@ -394,7 +395,7 @@ const DocsFooter: FC = () => {
by="All Rights Reserved. Flowbite™ is a registered trademark."
href="/"
year={2023}
className="!text-base"
className="text-base"
/>
</div>
</div>
Expand Down
2 changes: 1 addition & 1 deletion app/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -1236,7 +1236,7 @@ const MainFooter: FC = () => {
by="All Rights Reserved. Flowbite™ is a registered trademark."
href="/"
year={2023}
className="!text-base"
className="text-base"
/>
</div>
</div>
Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -55,10 +55,10 @@
},
"dependencies": {
"@floating-ui/react": "^0.24.1",
"classnames": "^2.3.2",
"flowbite": "^1.6.5",
"react-icons": "^4.8.0",
"react-indiana-drag-scroll": "^2.2.0"
"react-indiana-drag-scroll": "^2.2.0",
"tailwind-merge": "^1.13.1"
},
"devDependencies": {
"@mdx-js/loader": "^2.3.0",
Expand Down
3 changes: 2 additions & 1 deletion src/components/Accordion/Accordion.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,8 @@ describe('Components / Accordion', () => {
expect(title).toHaveClass('text-3xl');
});
openTitles.forEach((title) => {
expect(title).toHaveClass('text-gray-600');
// Note: it is being overwrited by the className prop which is expected
expect(title).toHaveClass('text-cyan-300');
});
closedTitles.forEach((title) => {
expect(title).toHaveClass('text-gray-400');
Expand Down
4 changes: 2 additions & 2 deletions src/components/Accordion/Accordion.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import classNames from 'classnames';
import type { ComponentProps, FC, PropsWithChildren, ReactElement } from 'react';
import { Children, cloneElement, useMemo, useState } from 'react';
import { HiChevronDown } from 'react-icons/hi';
import { twMerge } from 'tailwind-merge';
import type { DeepPartial, FlowbiteBoolean } from '../../';
import { useTheme } from '../../';
import { mergeDeep } from '../../helpers/merge-deep';
Expand Down Expand Up @@ -62,7 +62,7 @@ const AccordionComponent: FC<AccordionProps> = ({

return (
<div
className={classNames(theme.base, theme.flush[flush ? 'on' : 'off'], className)}
className={twMerge(theme.base, theme.flush[flush ? 'on' : 'off'], className)}
data-testid="flowbite-accordion"
{...props}
>
Expand Down
4 changes: 2 additions & 2 deletions src/components/Accordion/AccordionContent.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import classNames from 'classnames';
import type { ComponentProps, FC, PropsWithChildren } from 'react';
import { twMerge } from 'tailwind-merge';
import type { DeepPartial } from '../../';
import { useTheme } from '../../';
import { mergeDeep } from '../../helpers/merge-deep';
Expand All @@ -25,7 +25,7 @@ export const AccordionContent: FC<AccordionContentProps> = ({

return (
<div
className={classNames(theme.base, className)}
className={twMerge(theme.base, className)}
data-testid="flowbite-accordion-content"
hidden={!isOpen}
{...props}
Expand Down
11 changes: 3 additions & 8 deletions src/components/Accordion/AccordionTitle.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import classNames from 'classnames';
import type { ComponentProps, FC } from 'react';
import { twMerge } from 'tailwind-merge';
import type { DeepPartial, FlowbiteBoolean, FlowbiteHeadingLevel } from '../../';
import { useTheme } from '../../';
import { mergeDeep } from '../../helpers/merge-deep';
Expand Down Expand Up @@ -36,12 +36,7 @@ export const AccordionTitle: FC<AccordionTitleProps> = ({

return (
<button
className={classNames(
theme.base,
theme.flush[flush ? 'on' : 'off'],
theme.open[isOpen ? 'on' : 'off'],
className,
)}
className={twMerge(theme.base, theme.flush[flush ? 'on' : 'off'], theme.open[isOpen ? 'on' : 'off'], className)}
onClick={onClick}
type="button"
{...props}
Expand All @@ -52,7 +47,7 @@ export const AccordionTitle: FC<AccordionTitleProps> = ({
{ArrowIcon && (
<ArrowIcon
aria-hidden
className={classNames(theme.arrow.base, theme.arrow.open[isOpen ? 'on' : 'off'])}
className={twMerge(theme.arrow.base, theme.arrow.open[isOpen ? 'on' : 'off'])}
data-testid="flowbite-accordion-arrow"
/>
)}
Expand Down
33 changes: 33 additions & 0 deletions src/components/Accordion/theme.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import type { FlowbiteAccordionTheme } from './Accordion';

export const accordionTheme: FlowbiteAccordionTheme = {
root: {
base: 'divide-y divide-gray-200 border-gray-200 dark:divide-gray-700 dark:border-gray-700',
flush: {
off: 'rounded-lg border',
on: 'border-b',
},
},
content: {
base: 'py-5 px-5 last:rounded-b-lg dark:bg-gray-900 first:rounded-t-lg',
},
title: {
arrow: {
base: 'h-6 w-6 shrink-0',
open: {
off: '',
on: 'rotate-180',
},
},
base: 'flex w-full items-center justify-between first:rounded-t-lg last:rounded-b-lg py-5 px-5 text-left font-medium text-gray-500 dark:text-gray-400',
flush: {
off: 'hover:bg-gray-100 focus:ring-4 focus:ring-gray-200 dark:hover:bg-gray-800 dark:focus:ring-gray-800',
on: 'bg-transparent dark:bg-transparent',
},
heading: '',
open: {
off: '',
on: 'text-gray-900 bg-gray-100 dark:bg-gray-800 dark:text-white',
},
},
};
4 changes: 3 additions & 1 deletion src/components/Alert/Alert.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@ describe.concurrent('Components / Alert', () => {
it('should use custom `base` classes', () => {
const theme = {
alert: {
base: 'text-purple-100',
color: {
info: 'text-purple-100',
},
},
};
render(
Expand Down
6 changes: 3 additions & 3 deletions src/components/Alert/Alert.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import classNames from 'classnames';
import type { ComponentProps, FC, PropsWithChildren, ReactNode } from 'react';
import { HiX } from 'react-icons/hi';
import { twMerge } from 'tailwind-merge';
import type { DeepPartial, FlowbiteColors } from '../../';
import { useTheme } from '../../';
import { mergeDeep } from '../../helpers/merge-deep';
Expand Down Expand Up @@ -47,7 +47,7 @@ export const Alert: FC<AlertProps> = ({

return (
<div
className={classNames(
className={twMerge(
theme.base,
theme.color[color],
rounded && theme.rounded,
Expand All @@ -63,7 +63,7 @@ export const Alert: FC<AlertProps> = ({
{typeof onDismiss === 'function' && (
<button
aria-label="Dismiss"
className={classNames(theme.closeButton.base, theme.closeButton.color[color])}
className={twMerge(theme.closeButton.base, theme.closeButton.color[color])}
onClick={onDismiss}
type="button"
>
Expand Down
Loading