@navikt/ds-react
Version:
React components from the Norwegian Labour and Welfare Administration.
148 lines • 7.5 kB
JavaScript
var __rest = (this && this.__rest) || function (s, e) {
var t = {};
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
t[p] = s[p];
if (s != null && typeof Object.getOwnPropertySymbols === "function")
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
t[p[i]] = s[p[i]];
}
return t;
};
import React, { forwardRef, useCallback, useEffect, useRef, useState, } from "react";
import { useRenameCSS } from "../theme/Theme.js";
import { BodyLong, BodyShort, Heading } from "../typography/index.js";
import { useId } from "../util/index.js";
import { createContext } from "../util/create-context.js";
import { useMergeRefs } from "../util/hooks/index.js";
import { useI18n } from "../util/i18n/i18n.hooks.js";
const [ProcessContextProvider, useProcessContext] = createContext({
providerName: "ProcessContextProvider",
hookName: "useProcessContext",
name: "ProcessContext",
errorMessage: "`<Process.Event />` must be used within a `<Process />` component.",
});
/**
* A component that presents a Process as a vertical line of events.
* Each event can contain information, actions, links or status indicators.
*
* @see [📝 Documentation](https://aksel.nav.no/komponenter/core/process)
* @see 🏷️ {@link ProcessProps}
*
* @example
* ```jsx
* <>
* <Heading size="medium" spacing level="2" id="Process-heading">
* Søknadssteg
* </Heading>
* <Process
* aria-labelledby="Process-heading"
* activeStep={activeStep}
* >
* <Process.Event title="Start søknad" timestamp="21. august 2025" />
* <Process.Event
* title="Saksopplysninger"
* timestamp="22. august 2025"
* icon={<PaperclipIcon />}
* >
* Saksopplysninger er sendt inn
* </Process.Event>
* <Process.Event
* title="Vedlegg"
* timestamp="25. august 2025"
* >
* <h3> Vedlegg er lastet opp </h3>
* <p>
* Dokumentasjon av saksopplysninger er lastet opp og tilgjengelig for
* saksbehandler.
* </p>
* </Process.Event>
* <Process.Event title="Vedtak" timestamp="8. september 2025">
* Det er gjort endelig vedtak i saken
* </Process.Event>
* </Process>
* </>
* ```
*/
export const Process = forwardRef((_a, forwardedRef) => {
var { children, className, hideStatusText = false, id } = _a, restProps = __rest(_a, ["children", "className", "hideStatusText", "id"]);
const { cn } = useRenameCSS();
const rootId = useId(id);
const rootRef = useRef(null);
const mergedRef = useMergeRefs(forwardedRef, rootRef);
const [activeChildId, setActiveChildId] = useState(undefined);
const syncAriaControls = useCallback(() => {
var _a;
const activeChildren = (_a = rootRef.current) === null || _a === void 0 ? void 0 : _a.querySelectorAll('[data-process-event][aria-current="true"]');
if (!activeChildren) {
setActiveChildId(undefined);
return;
}
if (activeChildren.length > 1) {
if (process.env.NODE_ENV !== "production") {
console.warn("Aksel: Found multiple `<Process.Event />` elements with `status='active'`. Only one event should be active at a time.", rootRef.current);
}
setActiveChildId(undefined);
return;
}
if (activeChildren.length === 1) {
const lastActiveChild = activeChildren[activeChildren.length - 1];
setActiveChildId(lastActiveChild.id);
}
else {
setActiveChildId(undefined);
}
}, []);
return (
// `<ol />` elements with `list-style: none;` tends to be ignored by voiceover on Safari.
// To resolve this, we add `role="list"` to the `<ol />` element.
// eslint-disable-next-line jsx-a11y/no-redundant-roles
React.createElement("ol", Object.assign({ ref: mergedRef, "data-color": "info",
// biome-ignore lint/a11y/noRedundantRoles: See comment above
role: "list" }, restProps, { className: cn("navds-process", className), id: rootId, "aria-controls": activeChildId }),
React.createElement(ProcessContextProvider, { hideStatusText: hideStatusText, rootId: rootId, syncAriaControls: syncAriaControls }, children)));
});
export const ProcessEvent = forwardRef((_a, forwardedRef) => {
var { title, timestamp, children, bullet, hideContent, className, id, status = "uncompleted" } = _a, restProps = __rest(_a, ["title", "timestamp", "children", "bullet", "hideContent", "className", "id", "status"]);
const translate = useI18n("Process");
const { cn } = useRenameCSS();
const eventId = useId();
const { syncAriaControls, hideStatusText, rootId } = useProcessContext();
// syncAriaControls is already memoized with useCallback
// biome-ignore lint/correctness/useExhaustiveDependencies: We want to run this only when status changes
useEffect(syncAriaControls, [status]); // eslint-disable-line react-hooks/exhaustive-deps
const isActive = status === "active";
return (React.createElement("li", Object.assign({ ref: forwardedRef, "aria-current": isActive, id: id !== null && id !== void 0 ? id : eventId }, restProps, { "aria-controls": isActive ? rootId : undefined, className: cn("navds-process__event", className), "data-dot": bullet === undefined, "data-process-event": "", "data-status": status }),
React.createElement("div", { className: cn("navds-process__item") },
React.createElement(ProcessBullet, null, bullet),
React.createElement("div", { className: cn("navds-process__body") },
title && React.createElement(ProcessTitle, null, title),
isActive && !hideStatusText && (React.createElement(BodyShort, { size: "small", className: cn("navds-process__active-label") }, translate("active"))),
timestamp && React.createElement(ProcessTimestamp, null, timestamp),
!hideContent && !!children && (React.createElement(ProcessContent, null, children)))),
React.createElement(ProcessLine, null)));
});
const ProcessTitle = ({ children }) => {
const { cn } = useRenameCSS();
return (React.createElement(Heading, { size: "small", as: "div", className: cn("navds-process__title") }, children));
};
const ProcessTimestamp = ({ children }) => {
const { cn } = useRenameCSS();
return (React.createElement(BodyShort, { spacing: true, as: "div", size: "small", textColor: "subtle", className: cn("navds-process__timestamp") }, children));
};
const ProcessContent = ({ children }) => {
const { cn } = useRenameCSS();
return (React.createElement(BodyLong, { as: "div", className: cn("navds-process__content") }, children));
};
const ProcessBullet = ({ children }) => {
const { cn } = useRenameCSS();
return (React.createElement(BodyShort, { as: "span", weight: "semibold", className: cn("navds-process__bullet"), "aria-hidden": true }, children));
};
/* ------------------------------ Process Line ------------------------------ */
const ProcessLine = () => {
const { cn } = useRenameCSS();
return React.createElement("span", { className: cn("navds-process__line") });
};
/* -------------------------- Process exports ------------------------- */
Process.Event = ProcessEvent;
//# sourceMappingURL=Process.js.map