UNPKG

@navikt/ds-react

Version:

React components from the Norwegian Labour and Welfare Administration.

148 lines 7.5 kB
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