diff --git a/.changeset/new-cougars-collect.md b/.changeset/new-cougars-collect.md new file mode 100644 index 0000000000..292c420571 --- /dev/null +++ b/.changeset/new-cougars-collect.md @@ -0,0 +1,6 @@ +--- +"@nextui-org/alert": patch +"@nextui-org/theme": patch +--- + +Alert styles improved diff --git a/apps/docs/content/components/alert/controlled.ts b/apps/docs/content/components/alert/controlled.ts index 3a4780f3e2..33af02947f 100644 --- a/apps/docs/content/components/alert/controlled.ts +++ b/apps/docs/content/components/alert/controlled.ts @@ -13,6 +13,8 @@ export default function App() { title={title} description={description} isVisible={isVisible} + variant="faded" + color="success" onClose={() => setIsVisible(false)} /> ) : ( diff --git a/apps/docs/content/components/alert/custom-styles.ts b/apps/docs/content/components/alert/custom-styles.ts index b2c5fb17d3..5a9aeb1af0 100644 --- a/apps/docs/content/components/alert/custom-styles.ts +++ b/apps/docs/content/components/alert/custom-styles.ts @@ -1,27 +1,54 @@ -const App = `import {Alert} from "@nextui-org/react"; +const App = `import {Alert, Button} from "@nextui-org/react"; export default function App() { - const title = "Success"; - const description = "Thanks for subscribing to our newsletter!"; - + const [isVisible, setIsVisible] = React.useState(true); + return (
+ {!isVisible && ( + + )} + isVisible={isVisible} + title="The documents you requested are ready to be viewed" + variant="faded" + onClose={() => setIsVisible(false)} + > +
+ + +
+
); }`; diff --git a/apps/docs/content/components/alert/index.ts b/apps/docs/content/components/alert/index.ts index 1be9439d70..7fc0ee5ca4 100644 --- a/apps/docs/content/components/alert/index.ts +++ b/apps/docs/content/components/alert/index.ts @@ -5,6 +5,7 @@ import customImpl from "./custom-impl"; import customStyles from "./custom-styles"; import variants from "./variants"; import withIcon from "./with-icon"; +import withAction from "./with-action"; import controlled from "./controlled"; export const alertContent = { @@ -15,5 +16,6 @@ export const alertContent = { customStyles, variants, withIcon, + withAction, controlled, }; diff --git a/apps/docs/content/components/alert/variants.ts b/apps/docs/content/components/alert/variants.ts index 637553b085..48f57385c7 100644 --- a/apps/docs/content/components/alert/variants.ts +++ b/apps/docs/content/components/alert/variants.ts @@ -3,15 +3,9 @@ const App = `import {Alert} from "@nextui-org/react"; export default function App() { return (
- - A solid variant alert - - - A bordered variant alert - - - A flat variant alert - + {["solid", "bordered", "flat", "faded"].map((variant) => ( + + ))}
); }`; diff --git a/apps/docs/content/components/alert/with-action.ts b/apps/docs/content/components/alert/with-action.ts new file mode 100644 index 0000000000..b4f9665f62 --- /dev/null +++ b/apps/docs/content/components/alert/with-action.ts @@ -0,0 +1,29 @@ +const App = `import {Alert, Button} from "@nextui-org/react"; + +export default function App() { + const [isVisible, setIsVisible] = React.useState(true); + + return ( +
+ + Upgrade + + } + title="You have no credits left" + variant="faded" + /> +
+ ); +}`; + +const react = { + "/App.jsx": App, +}; + +export default { + ...react, +}; diff --git a/apps/docs/content/docs/components/alert.mdx b/apps/docs/content/docs/components/alert.mdx index 3d2b30bc8f..08d7bd3bbe 100644 --- a/apps/docs/content/docs/components/alert.mdx +++ b/apps/docs/content/docs/components/alert.mdx @@ -59,7 +59,11 @@ Alert comes with 6 color variants to convey different meanings. By default, Alert displays an appropriate icon based on the `color` prop. You can override this by providing a custom icon using the `icon` prop. - +### With Action + +Alert supports an `endContent` prop for additional actions. + + ### Controlled Visibility @@ -92,6 +96,18 @@ Alert has the following attributes on the `base` element: +### Slots + +Alert has the following slots: + +- `base`: The main alert container element +- `title`: The title element +- `description`: The description element +- `mainWrapper`: The wrapper for the title and description content +- `closeButton`: The close button element +- `iconWrapper`: The wrapper for the alert icon +- `alertIcon`: The alert icon element + ## Accessibility - Alert has role of `alert` @@ -112,6 +128,8 @@ Alert has the following attributes on the `base` element: | color | `default` \| `primary` \| `secondary` \| `success` \| `warning` \| `danger` | The alert color theme | `default` | | variant | `solid` \| `bordered` \| `flat` \| `faded` | The alert variant | `flat` | | radius | `none` \| `sm` \| `md` \| `lg` \| `full` | The alert border radius | `md` | +| startContent | `ReactNode` | The alert start content | - | +| endContent | `ReactNode` | The alert end content | - | | isVisible | `boolean` | Whether the alert is visible | - | | isClosable | `boolean` | Whether the alert can be closed | `false` | | hideIcon | `boolean` | Whether the icon is hidden | `false` | diff --git a/packages/components/alert/package.json b/packages/components/alert/package.json index 7dec7b453c..0e4283c81b 100644 --- a/packages/components/alert/package.json +++ b/packages/components/alert/package.json @@ -47,9 +47,9 @@ "@nextui-org/react-utils": "workspace:*", "@nextui-org/shared-icons": "workspace:*", "@nextui-org/shared-utils": "workspace:*", + "@nextui-org/button": "workspace:*", "@react-stately/utils": "3.10.1", - "@react-aria/utils": "3.24.1", - "@nextui-org/button": "workspace:*" + "@react-aria/utils": "3.24.1" }, "devDependencies": { "@nextui-org/system": "workspace:*", diff --git a/packages/components/alert/src/alert.tsx b/packages/components/alert/src/alert.tsx index d6460aa45d..384ed1d0fb 100644 --- a/packages/components/alert/src/alert.tsx +++ b/packages/components/alert/src/alert.tsx @@ -32,7 +32,10 @@ const Alert = forwardRef<"div", AlertProps>((props, ref) => { const { title, icon, + children, description, + endContent, + startContent, isClosable, domRef, handleClose, @@ -56,14 +59,16 @@ const Alert = forwardRef<"div", AlertProps>((props, ref) => { return (
+ {startContent}
{customIcon || }
{title &&
{title}
} {!isEmpty(description) &&
{description}
} + {children}
- + {endContent} {(isClosable || onClose) && ( + } + title="You have no credits left" + variant="faded" + /> + ); +}; + +export const CustomStylesTemplate = (args) => { + const [isVisible, setIsVisible] = React.useState(true); + + return ( + <> + {!isVisible && ( + + )} + setIsVisible(false)} + > +
+ + +
+
+ + ); +}; + export const Default = { render: Template, args: { @@ -122,6 +193,7 @@ export const Color = { render: ColorTemplate, args: { ...defaultProps, + variant: "faded", }, }; @@ -172,21 +244,16 @@ export const Closable = { }, }; -export const CustomWithClassNames = { - render: Template, +export const WithEndContent = { + render: WithEndContentTemplate, + args: { + ...defaultProps, + }, +}; + +export const CustomStyles = { + render: CustomStylesTemplate, args: { ...defaultProps, - classNames: { - base: [ - "bg-background", - "border", - "border-foreground-400", - "shadow", - "hover:bg-slate-200", - "cursor-pointer", - ], - title: ["text-base", "text-foreground", "font-semibold"], - description: ["text-base", "text-foreground-600"], - }, }, }; diff --git a/packages/core/theme/src/components/alert.ts b/packages/core/theme/src/components/alert.ts index 3af4e45dfd..bc76f4dd23 100644 --- a/packages/core/theme/src/components/alert.ts +++ b/packages/core/theme/src/components/alert.ts @@ -26,11 +26,11 @@ const alert = tv({ slots: { base: "flex flex-grow flex-row w-full items-start py-3 px-4 gap-x-1", mainWrapper: "h-full flex-grow min-h-10 ms-2 flex flex-col box-border items-start text-inherit", - title: "w-full font-medium block text-inherit leading-5", + title: "text-small w-full font-medium block text-inherit leading-5", description: "pl-[1px] text-small font-normal text-inherit", - closeButton: "relative text-inherit", - iconWrapper: "flex items-center justify-center w-9 h-9 rounded-full", - alertIcon: "fill-current w-6", + closeButton: "relative text-inherit translate-x-1 -translate-y-1", + iconWrapper: "flex-none relative w-9 h-9 rounded-full", + alertIcon: "fill-current w-6 absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2", }, variants: { color: { @@ -81,7 +81,7 @@ const alert = tv({ }, hasDescription: { false: { - base: "items-center", + base: "items-start", mainWrapper: "justify-center", }, }, @@ -139,60 +139,64 @@ const alert = tv({ base: colorVariants.solid.danger, }, }, - // flat / color + // flat & faded / color { variant: ["flat", "faded"], color: "default", class: { - base: [colorVariants.flat.default, "text-default-foreground"], + base: [ + colorVariants.flat.default, + "bg-default-100 dark:bg-default-50", + "text-default-foreground", + ], description: "text-default-600", closeButton: "text-default-400", - iconWrapper: "bg-default-50 dark:bg-default-100", + iconWrapper: "bg-default-50 dark:bg-default-100 border-default-200", }, }, { variant: ["flat", "faded"], color: "primary", class: { - base: colorVariants.flat.primary, - closeButton: "text-primary-400 data-[hover]:bg-primary-100", - iconWrapper: "bg-primary-50 dark:bg-primary-100", + base: [colorVariants.flat.primary, "bg-primary-50"], + closeButton: "text-primary-500 data-[hover]:bg-primary-200", + iconWrapper: "bg-primary-50 dark:bg-primary-100 border-primary-100", }, }, { variant: ["flat", "faded"], color: "secondary", class: { - base: colorVariants.flat.secondary, - closeButton: "text-secondary-400 data-[hover]:bg-secondary-100", - iconWrapper: "bg-secondary-50 dark:bg-secondary-100", + base: [colorVariants.flat.secondary, "bg-secondary-50"], + closeButton: "text-secondary-500 data-[hover]:bg-secondary-200", + iconWrapper: "bg-secondary-50 dark:bg-secondary-100 border-secondary-100", }, }, { variant: ["flat", "faded"], color: "success", class: { - base: colorVariants.flat.success, - closeButton: "text-success-400 data-[hover]:bg-success-100", - iconWrapper: "bg-success-50 dark:bg-success-100", + base: [colorVariants.flat.success, "bg-success-50"], + closeButton: "text-success-500 data-[hover]:bg-success-200", + iconWrapper: "bg-success-50 dark:bg-success-100 border-success-100", }, }, { variant: ["flat", "faded"], color: "warning", class: { - base: colorVariants.flat.warning, + base: [colorVariants.flat.warning, "bg-warning-50"], closeButton: "text-warning-500 data-[hover]:bg-warning-200", - iconWrapper: "bg-warning-50 dark:bg-warning-100", + iconWrapper: "bg-warning-50 dark:bg-warning-100 border-warning-100", }, }, { variant: ["flat", "faded"], color: "danger", class: { - base: colorVariants.flat.danger, - closeButton: "text-danger-400 data-[hover]:bg-danger-100", - iconWrapper: "bg-danger-50 dark:bg-danger-100", + base: [colorVariants.flat.danger, "bg-danger-50"], + closeButton: "text-danger-500 data-[hover]:bg-danger-200", + iconWrapper: "bg-danger-50 dark:bg-danger-100 border-danger-100", }, }, // faded / color @@ -200,42 +204,42 @@ const alert = tv({ variant: "faded", color: "default", class: { - base: "border-default", + base: "border-default-300 dark:border-default-200", }, }, { variant: "faded", color: "primary", class: { - base: "border-primary", + base: "border-primary-200", }, }, { variant: "faded", color: "secondary", class: { - base: "border-secondary", + base: "border-secondary-200", }, }, { variant: "faded", color: "success", class: { - base: "border-success", + base: "border-success-200 dark:border-success-100", }, }, { variant: "faded", color: "warning", class: { - base: "border-warning", + base: "border-warning-200 dark:border-warning-100", }, }, { variant: "faded", color: "danger", class: { - base: "border-danger", + base: "border-danger-200 dark:border-danger-100", }, }, // bordered / color @@ -288,13 +292,20 @@ const alert = tv({ closeButton: "data-[hover]:bg-danger-50", }, }, - // flat & bordered + // flat & bordered & faded { variant: ["flat", "bordered", "faded"], class: { iconWrapper: "shadow-small", }, }, + // flat & faded + { + variant: ["flat", "faded"], + class: { + iconWrapper: "shadow-small border-1", + }, + }, // bordered & color { variant: "bordered",