@navikt/ds-react
Version:
React components from the Norwegian Labour and Welfare Administration.
155 lines • 7.37 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 { endOfDay, isSameDay, startOfDay } from "date-fns";
import React, { forwardRef, useMemo, useRef, useState } from "react";
import { useRenameCSS } from "../theme/Theme.js";
import { AxisLabels } from "./AxisLabels.js";
import TimelineRow from "./TimelineRow.js";
import { RowContext } from "./hooks/useRowContext.js";
import { TimelineContext } from "./hooks/useTimelineContext.js";
import { useEarliestDate, useLatestDate, useTimelineRows, } from "./hooks/useTimelineRows.js";
import Period from "./period/index.js";
import Pin from "./pin/Pin.js";
import { parseRows } from "./utils/timeline.js";
import Zoom from "./zoom/index.js";
/**
* A component that displays a timeline of events. Meant for Internal systems.
*
* Component is made for desktop enviroments and will start having issues on smaller screens.
*
* @see [📝 Documentation](https://aksel.nav.no/komponenter/core/timeline)
* @see 🏷️ {@link TimelineProps}
*
* @example
* ```jsx
* <Timeline>
* <Timeline.Row>
* <Timeline.Period start={new Date("2020-01-01")} end={new Date("2020-01-31")}>
* <p>Period 1</p>
* </Timeline.Period>
* <Timeline.Row>
* </Timeline>
* ```
*/
export const Timeline = forwardRef((_a, ref) => {
var { children, startDate, endDate, direction = "left", axisLabelTemplates } = _a, rest = __rest(_a, ["children", "startDate", "endDate", "direction", "axisLabelTemplates"]);
const { cn } = useRenameCSS();
const isMultipleRows = Array.isArray(children);
const firstFocusabled = useRef([]);
if (!isMultipleRows) {
children = [children];
}
const rowChildren = React.Children.toArray(children).filter((c) => { var _a; return ((_a = c === null || c === void 0 ? void 0 : c.type) === null || _a === void 0 ? void 0 : _a.componentType) === "row"; });
const pins = React.Children.toArray(children)
.filter((c) => { var _a; return ((_a = c === null || c === void 0 ? void 0 : c.type) === null || _a === void 0 ? void 0 : _a.componentType) === "pin"; })
.map((x) => () => x);
const zoomComponent = React.Children.toArray(children).find((c) => { var _a; return ((_a = c === null || c === void 0 ? void 0 : c.type) === null || _a === void 0 ? void 0 : _a.componentType) === "zoom"; });
const rowsRaw = useMemo(() => {
return parseRows(rowChildren);
}, [rowChildren]);
const rows = rowsRaw.map((r) => {
if (r === null || r === void 0 ? void 0 : r.periods) {
return r.periods;
}
return [];
});
const initialStartDate = startOfDay(useEarliestDate({ startDate, rows }));
const [start, setStart] = useState(initialStartDate);
const [activeRow, setActiveRow] = useState(null);
const [endInclusive, setEndInclusive] = useState(endOfDay(useLatestDate({ endDate, rows })));
const initialEndDate = endOfDay(useLatestDate({ endDate, rows }));
const processedRows = useTimelineRows(rowsRaw, startDate !== null && startDate !== void 0 ? startDate : start, endDate !== null && endDate !== void 0 ? endDate : endInclusive, direction);
const handleZoomChange = (zoomStart) => {
if (startDate || endDate) {
if (process.env.NODE_ENV !== "production") {
console.warn("Zooming is not supported when startDate or endDate is set");
}
return;
}
if (direction === "left") {
if (isSameDay(zoomStart, start)) {
setStart(initialStartDate);
return;
}
setStart(zoomStart);
}
else {
if (isSameDay(zoomStart, endInclusive)) {
setEndInclusive(initialEndDate);
return;
}
setEndInclusive(zoomStart);
}
};
const handleActiveRowChange = (key) => {
var _a, _b, _c, _d;
if (activeRow !== null && key === "ArrowDown") {
for (let i = activeRow + 1; i < processedRows.length; i++) {
const row = processedRows[i];
if (row.periods.find((p) => !!p.children || !!p.onSelectPeriod)) {
setActiveRow(i);
(_b = (_a = firstFocusabled.current.find((x) => x.id === i)) === null || _a === void 0 ? void 0 : _a.ref) === null || _b === void 0 ? void 0 : _b.focus();
break;
}
}
return;
}
if (activeRow !== null && key === "ArrowUp") {
for (let i = activeRow - 1; i >= 0; i--) {
const row = processedRows[i];
if (row.periods.find((p) => !!p.children || !!p.onSelectPeriod)) {
setActiveRow(i);
(_d = (_c = firstFocusabled.current.find((x) => x.id === i)) === null || _c === void 0 ? void 0 : _c.ref) === null || _d === void 0 ? void 0 : _d.focus();
break;
}
}
return;
}
};
const addFocusable = (btnRef, id) => {
let items = firstFocusabled.current;
items = items.filter((x) => x.id !== id);
items.push({ ref: btnRef, id });
firstFocusabled.current = items;
};
return (React.createElement(TimelineContext.Provider, { value: {
startDate: startDate !== null && startDate !== void 0 ? startDate : start,
endDate: endDate !== null && endDate !== void 0 ? endDate : endInclusive,
direction,
setStart: (d) => handleZoomChange(d),
setEndInclusive: (d) => setEndInclusive(d),
activeRow,
setActiveRow: (key) => handleActiveRowChange(key),
initiate: (i) => setActiveRow(i),
addFocusable,
} },
React.createElement("div", Object.assign({}, rest, { ref: ref }),
React.createElement("div", { className: cn("navds-timeline") },
React.createElement(AxisLabels, { templates: axisLabelTemplates }),
pins.map((PinChild, i) => (React.createElement(PinChild, { key: `pin-${i}` }))),
processedRows.map((row, i) => {
return (React.createElement(RowContext.Provider, { key: `row-${row.id}`, value: {
periods: row.periods,
id: row.id,
active: activeRow === i,
index: i,
} },
React.createElement(TimelineRow, Object.assign({}, row === null || row === void 0 ? void 0 : row.restProps, { ref: row === null || row === void 0 ? void 0 : row.ref, label: row.label, icon: row.icon, headingTag: row.headingTag }))));
})),
zoomComponent)));
});
Timeline.Row = TimelineRow;
Timeline.Period = Period;
Timeline.Pin = Pin;
Timeline.Zoom = Zoom;
export default Timeline;
//# sourceMappingURL=Timeline.js.map