✨ Add Button, BodyShort and Heading to @navikt/ds-react

forwardRef-based components with navds-* classnames composed via a small
local cn() utility. Adds shared tsconfig.base.json and truncate modifier
for BodyShort.
This commit is contained in:
Aksel Mini committed 2026-08-10 11:00:00 +02:00
1 parent b4930f754e
commit 559fd2b971
12 files changed
+164

No files matched your search

+6
View File
@@ -19,6 +19,12 @@
line-height: 1.5;
}
.navds-body-short--truncate {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.navds-heading {
margin: 0;
font-family: var(--a-font-family);
+33
View File
@@ -0,0 +1,33 @@
{
"name": "@navikt/ds-react",
"version": "0.1.0",
"description": "React components for Aksel Mini",
"license": "MIT",
"type": "module",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"exports": {
".": {
"types": "./dist/index.d.ts",
"import": "./dist/index.js"
}
},
"files": [
"dist"
],
"scripts": {
"build": "tsc -p tsconfig.json",
"clean": "rm -rf dist"
},
"peerDependencies": {
"react": "^18.0.0",
"react-dom": "^18.0.0"
},
"devDependencies": {
"@types/react": "18.3.11",
"@types/react-dom": "18.3.1",
"react": "18.3.1",
"react-dom": "18.3.1",
"typescript": "5.5.4"
}
}
@@ -0,0 +1,29 @@
import { forwardRef } from "react";
import type { HTMLAttributes } from "react";
import { cn } from "../util/cn";
export interface BodyShortProps extends HTMLAttributes<HTMLParagraphElement> {
/**
* Text size.
* @default "medium"
*/
size?: "medium" | "small";
/**
* Truncates the text to a single line with an ellipsis.
* @default false
*/
truncate?: boolean;
}
export const BodyShort = forwardRef<HTMLParagraphElement, BodyShortProps>(function BodyShort(
{ size = "medium", truncate = false, className, ...rest },
ref,
) {
return (
<p
ref={ref}
className={cn("navds-body-short", `navds-body-short--${size}`, truncate && "navds-body-short--truncate", className)}
{...rest}
/>
);
});
@@ -0,0 +1,2 @@
export { BodyShort } from "./BodyShort";
export type { BodyShortProps } from "./BodyShort";
+30
View File
@@ -0,0 +1,30 @@
import { forwardRef } from "react";
import type { ButtonHTMLAttributes } from "react";
import { cn } from "../util/cn";
export interface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
/**
* Visual variant.
* @default "primary"
*/
variant?: "primary" | "secondary" | "tertiary" | "danger";
/**
* Button size.
* @default "medium"
*/
size?: "medium" | "small";
}
export const Button = forwardRef<HTMLButtonElement, ButtonProps>(function Button(
{ variant = "primary", size = "medium", type = "button", className, ...rest },
ref,
) {
return (
<button
ref={ref}
type={type}
className={cn("navds-button", `navds-button--${variant}`, `navds-button--${size}`, className)}
{...rest}
/>
);
});
+2
View File
@@ -0,0 +1,2 @@
export { Button } from "./Button";
export type { ButtonProps } from "./Button";
@@ -0,0 +1,27 @@
import { createElement, forwardRef } from "react";
import type { HTMLAttributes } from "react";
import { cn } from "../util/cn";
export interface HeadingProps extends HTMLAttributes<HTMLHeadingElement> {
/**
* Visual size, decoupled from the semantic level.
* @default "medium"
*/
size?: "xlarge" | "large" | "medium" | "small" | "xsmall";
/**
* Semantic heading level (h1–h6).
* @default 1
*/
level?: 1 | 2 | 3 | 4 | 5 | 6;
}
export const Heading = forwardRef<HTMLHeadingElement, HeadingProps>(function Heading(
{ size = "medium", level = 1, className, ...rest },
ref,
) {
return createElement(`h${level}`, {
ref,
className: cn("navds-heading", `navds-heading--${size}`, className),
...rest,
});
});
+2
View File
@@ -0,0 +1,2 @@
export { Heading } from "./Heading";
export type { HeadingProps } from "./Heading";
+6
View File
@@ -0,0 +1,6 @@
export { Button } from "./button";
export type { ButtonProps } from "./button";
export { BodyShort } from "./body-short";
export type { BodyShortProps } from "./body-short";
export { Heading } from "./heading";
export type { HeadingProps } from "./heading";
+5
View File
@@ -0,0 +1,5 @@
type ClassValue = string | false | null | undefined;
export function cn(...classes: ClassValue[]): string {
return classes.filter(Boolean).join(" ");
}
+8
View File
@@ -0,0 +1,8 @@
{
"extends": "../../../tsconfig.base.json",
"compilerOptions": {
"outDir": "dist",
"rootDir": "src"
},
"include": ["src"]
}
+14
View File
@@ -0,0 +1,14 @@
{
"compilerOptions": {
"target": "ES2020",
"module": "ESNext",
"moduleResolution": "Bundler",
"jsx": "react-jsx",
"strict": true,
"skipLibCheck": true,
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"declaration": true,
"sourceMap": false
}
}