Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 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
6 changes: 6 additions & 0 deletions .changeset/metal-pigs-sing.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@navikt/ds-react": minor
"@navikt/ds-css": minor
---

InlineMessage: :tada: New component! Replaces `<Alert inline />` variant as a standalone component.
5 changes: 5 additions & 0 deletions @navikt/core/css/config/_mappings.js
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,11 @@ const StyleMappings = {
dependencies: ["popover.css"],
},
{ component: "Ingress", main: typoCss },
{
component: "InlineMessage",
main: "inline-message.css",
dependencies: [typoCss],
},
{
component: "InternalHeader",
main: "internalheader.css",
Expand Down
1 change: 1 addition & 0 deletions @navikt/core/css/darkside/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
@import "./expansioncard.darkside.css" layer(aksel.components);
@import "./guide-panel.darkside.css" layer(aksel.components);
@import "./help-text.darkside.css" layer(aksel.components);
@import "./inline-message.darkside.css" layer(aksel.components);
@import "./internalheader.darkside.css" layer(aksel.components);
@import "./link.darkside.css" layer(aksel.components);
@import "./link-panel.darkside.css" layer(aksel.components);
Expand Down
17 changes: 17 additions & 0 deletions @navikt/core/css/darkside/inline-message.darkside.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
.aksel-inline-message {
display: flex;
align-items: flex-start;
gap: var(--ax-space-4);
color: var(--ax-text-default);
}

.aksel-inline-message__icon {
color: var(--ax-text-subtle);
font-size: 1.5rem;
display: flex;
flex: 0 0 auto;

.aksel-inline-message[data-size="small"] & {
font-size: 1.25rem;
}
}
1 change: 1 addition & 0 deletions @navikt/core/css/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
@import "guide-panel.css";
@import "form/index.css";
@import "help-text.css";
@import "inline-message.css";
@import "internalheader.css";
@import "link.css";
@import "link-anchor.css";
Expand Down
47 changes: 47 additions & 0 deletions @navikt/core/css/inline-message.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
.navds-inline-message {
display: flex;
align-items: flex-start;
gap: var(--a-spacing-1);
}

.navds-inline-message[data-color="info"] {
color: var(--a-lightblue-900);

& .navds-inline-message__icon {
color: var(--a-icon-info);
}
}

.navds-inline-message[data-color="success"] {
color: var(--a-green-900);

& .navds-inline-message__icon {
color: var(--a-icon-success);
}
}

.navds-inline-message[data-color="danger"] {
color: var(--a-red-900);

& .navds-inline-message__icon {
color: var(--a-icon-danger);
}
}

.navds-inline-message[data-color="warning"] {
color: var(--a-orange-900);

& .navds-inline-message__icon {
color: var(--a-icon-warning);
}
}

.navds-inline-message__icon {
font-size: 1.5rem;
display: flex;
flex: 0 0 auto;

.navds-inline-message[data-size="small"] & {
font-size: 1.25rem;
}
}
10 changes: 10 additions & 0 deletions @navikt/core/react/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -624,6 +624,16 @@
"default": "./cjs/form/form-progress/index.js"
}
},
"./InlineMessage": {
"import": {
"types": "./esm/inline-message/index.d.ts",
"default": "./esm/inline-message/index.js"
},
"require": {
"types": "./cjs/inline-message/index.d.ts",
"default": "./cjs/inline-message/index.js"
}
},
"./package.json": "./package.json",
"./Theme": {
"import": {
Expand Down
1 change: 1 addition & 0 deletions @navikt/core/react/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,7 @@ export {
type LinkCardIconProps,
type LinkCardImageProps,
} from "./link-card";
export { InlineMessage, type InlineMessageProps } from "./inline-message";

/**
* Theming
Expand Down
119 changes: 119 additions & 0 deletions @navikt/core/react/src/inline-message/InlineMessage.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
import type { Meta, StoryObj } from "@storybook/react-vite";
import React from "react";
import { VStack } from "../layout/stack";
import { Link } from "../link";
import { renderStoriesForChromatic } from "../util/renderStoriesForChromatic";
import { InlineMessage } from "./index";

const meta: Meta<typeof InlineMessage> = {
title: "ds-react/InlineMessage",
component: InlineMessage,
parameters: {
chromatic: { disable: true },
},
};

export default meta;

type Story = StoryObj<typeof InlineMessage>;

const variants = ["info", "success", "warning", "error"] as const;

export const Default: Story = {
render: (props) => {
return (
<InlineMessage variant={props.variant ?? "warning"}>
{props.children ?? "InlineMessage content"}
</InlineMessage>
);
},

args: {
children: "Id elit esse enim reprehenderit enim nisi veniam nostrud.",
variant: "warning",
},
argTypes: {
variant: {
control: { type: "select" },
options: variants,
},
},
};

export const SizeSmall: Story = {
render: () => {
return (
<InlineMessage variant="warning" size="small">
<DemoContent />
</InlineMessage>
);
},
};

export const Compositions: Story = {
render: () => {
return (
<VStack gap="space-16">
{variants.map((variant) => (
<InlineMessage variant={variant} key={variant}>
<DemoContent />
</InlineMessage>
))}
</VStack>
);
},
};

export const WrappingTitle: Story = {
render: () => {
return (
<InlineMessage variant="warning">
<DemoContent />
</InlineMessage>
);
},
};

export const AsLink: Story = {
render: () => {
return (
<InlineMessage variant="warning" as={Link} href="#">
This is a link inside the InlineMessage
</InlineMessage>
);
},
};

export const Chromatic = renderStoriesForChromatic({
Default,
Compositions,
WrappingTitle,
SizeSmall,
});

export const ChromaticLight = renderStoriesForChromatic({
Default,
Compositions,
WrappingTitle,
SizeSmall,
});
ChromaticLight.globals = { theme: "light", mode: "darkside" };

export const ChromaticDark = renderStoriesForChromatic({
Default,
Compositions,
WrappingTitle,
SizeSmall,
});
ChromaticDark.globals = { theme: "dark", mode: "darkside" };

function DemoContent() {
return (
<span>
Lorem ipsum dolor, sit amet consectetur adipisicing elit. Iure unde,
repudiandae, deleniti exercitationem quod aut veniam sint officiis
necessitatibus nulla nostrum voluptatem <Link href="#">Test</Link>{" "}
facilis! Commodi, nobis tempora quibusdam temporibus nulla quam.
</span>
);
}
39 changes: 39 additions & 0 deletions @navikt/core/react/src/inline-message/icon/InlineMessageIcon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import React from "react";
import {
CheckmarkCircleFillIcon,
ExclamationmarkTriangleFillIcon,
InformationSquareFillIcon,
XMarkOctagonFillIcon,
} from "@navikt/aksel-icons";
import { useRenameCSS } from "../../theme/Theme";
import { useI18n } from "../../util/i18n/i18n.hooks";

const VARIANT_ICONS = {
info: InformationSquareFillIcon,
success: CheckmarkCircleFillIcon,
warning: ExclamationmarkTriangleFillIcon,
error: XMarkOctagonFillIcon,
} as const;

function InlineMessageIcon({
variant,
}: {
variant: "info" | "success" | "warning" | "error";
}) {
const translate = useI18n("Alert");
const { cn } = useRenameCSS();

if (!variant) {
return null;
}

const Icon = VARIANT_ICONS[variant];

return (
<span className={cn("navds-inline-message__icon")}>
<Icon title={translate(variant)} />
</span>
);
}

export { InlineMessageIcon };
3 changes: 3 additions & 0 deletions @navikt/core/react/src/inline-message/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
"use client";
export { InlineMessage } from "./root/InlineMessage";
export type { InlineMessageProps } from "./root/InlineMessage";
86 changes: 86 additions & 0 deletions @navikt/core/react/src/inline-message/root/InlineMessage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import React, { forwardRef } from "react";
import { useRenameCSS, useThemeInternal } from "../../theme/Theme";
import type { AkselColor } from "../../types";
import { BodyShort } from "../../typography";
import type { OverridableComponent } from "../../util";
import { InlineMessageIcon } from "../icon/InlineMessageIcon";

interface InlineMessageProps extends React.HTMLAttributes<HTMLDivElement> {
/**
* InlineMessage variant.
*/
variant: "info" | "success" | "warning" | "error";
/**
* InlineMessage size.
* @default "medium"
*/
size?: "medium" | "small";
}

/**
* Inline message are used to display important messages with other content.
* @see [📝 Documentation](https://aksel.nav.no/komponenter/core/inline-message)
* @see 🏷️ {@link InlineMessageProps}
* @see [🤖 OverridableComponent](https://aksel.nav.no/grunnleggende/kode/overridablecomponent) support
* @example
* ```jsx
* <InlineMessage variant="error">
* Inline Errormessage
* </InlineMessage>
* ```
*
* * @example As a link
* ```jsx
* <InlineMessage variant="error" as={Link} href="#">
* Inline Errormessage
* </InlineMessage>
* ```
*/
const InlineMessage: OverridableComponent<
InlineMessageProps,
HTMLAnchorElement
> = forwardRef(
(
{
as: Component = "div",
children,
className,
variant,
size = "medium",
...restProps
}: InlineMessageProps & { as?: React.ElementType },
forwardedRef,
) => {
const { cn } = useRenameCSS();
const themeContext = useThemeInternal(false);

return (
<BodyShort
ref={forwardedRef}
className={cn("navds-inline-message", className)}
data-color={variantToDataColor(variant)}
{...restProps}
size={size}
as={Component}
data-variant={variant}
data-size={size}
>
<InlineMessageIcon variant={variant} />
<span data-color={themeContext?.color}>{children}</span>
</BodyShort>
);
},
);

function variantToDataColor(
variant: InlineMessageProps["variant"],
): AkselColor | undefined {
if (variant === "error") {
return "danger";
}

return variant;
}

export { InlineMessage };
export type { InlineMessageProps };
Loading