@luscii-healthtech/web-ui 42.8.7 → 42.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -5938,6 +5938,159 @@ const Collapse = (props) => {
5938
5938
  return jsxRuntime.jsx(jsxRuntime.Fragment, { children: jsxRuntime.jsxs("button", { className: buttonClassName, onClick, "aria-expanded": !isCollapsed, children: [jsxRuntime.jsx("div", { className: contentClassName, children }), isCollapsed && showMoreIndicator && moreIndicator] }) });
5939
5939
  };
5940
5940
 
5941
+ function isColorTuple(color) {
5942
+ return Array.isArray(color) && color.length === 2;
5943
+ }
5944
+ const validateNoOverlaps = (sections) => {
5945
+ sections.forEach((sectionA, i) => {
5946
+ sections.slice(i + 1).forEach((sectionB) => {
5947
+ const aMin = Math.min(sectionA.from, sectionA.to);
5948
+ const aMax = Math.max(sectionA.from, sectionA.to);
5949
+ const bMin = Math.min(sectionB.from, sectionB.to);
5950
+ const bMax = Math.max(sectionB.from, sectionB.to);
5951
+ const overlaps = aMin < bMax && bMin < aMax;
5952
+ if (overlaps) {
5953
+ throw new Error(`RangeCoverage: Sections cannot overlap. Section [${sectionA.from}, ${sectionA.to}] overlaps with section [${sectionB.from}, ${sectionB.to}].`);
5954
+ }
5955
+ });
5956
+ });
5957
+ };
5958
+ const generateIntermediateTicks = (args) => {
5959
+ const { step, start, end } = args;
5960
+ const tickSet = /* @__PURE__ */ new Set();
5961
+ const isDescending = start > end;
5962
+ let currentValue = start;
5963
+ const rangeMin = Math.min(start, end);
5964
+ const rangeMax = Math.max(start, end);
5965
+ tickSet.add(start);
5966
+ tickSet.add(end);
5967
+ while (currentValue >= rangeMin && currentValue <= rangeMax) {
5968
+ tickSet.add(currentValue);
5969
+ if (isDescending) {
5970
+ currentValue -= step;
5971
+ } else {
5972
+ currentValue += step;
5973
+ }
5974
+ }
5975
+ return Array.from(tickSet).sort((a, b) => isDescending ? b - a : a - b);
5976
+ };
5977
+ const calculateSegments = (sections, start, end) => {
5978
+ const isDescending = start > end;
5979
+ const rangeMin = Math.min(start, end);
5980
+ const rangeMax = Math.max(start, end);
5981
+ const totalRange = Math.abs(end - start);
5982
+ const segments = [];
5983
+ const normalizedSections = sections.map((section) => {
5984
+ const clampedFrom = Math.max(rangeMin, Math.min(rangeMax, section.from));
5985
+ const clampedTo = Math.max(rangeMin, Math.min(rangeMax, section.to));
5986
+ const higher = Math.max(clampedFrom, clampedTo);
5987
+ const lower = Math.min(clampedFrom, clampedTo);
5988
+ const startPos = isDescending ? (start - higher) / totalRange * 100 : (lower - start) / totalRange * 100;
5989
+ const width = (higher - lower) / totalRange * 100;
5990
+ return {
5991
+ startPos,
5992
+ width,
5993
+ color: section.color
5994
+ };
5995
+ }).filter((s) => s.width > 0).sort((a, b) => a.startPos - b.startPos);
5996
+ let currentPos = 0;
5997
+ for (const section of normalizedSections) {
5998
+ if (section.startPos > currentPos) {
5999
+ segments.push({
6000
+ widthPercent: section.startPos - currentPos,
6001
+ color: "transparent"
6002
+ });
6003
+ }
6004
+ segments.push({
6005
+ widthPercent: section.width,
6006
+ color: section.color
6007
+ });
6008
+ currentPos = section.startPos + section.width;
6009
+ }
6010
+ if (currentPos < 100) {
6011
+ segments.push({
6012
+ widthPercent: 100 - currentPos,
6013
+ color: "transparent"
6014
+ });
6015
+ }
6016
+ return segments;
6017
+ };
6018
+ const createStripedPattern = (colorA, colorB) => `repeating-linear-gradient(-45deg, ${colorA}, ${colorA} 4px, ${colorB} 4px, ${colorB} 8px)`;
6019
+ const getSegmentStyle = (color) => {
6020
+ const baseStyle = {
6021
+ height: "18px",
6022
+ boxSizing: "content-box"
6023
+ };
6024
+ if (isColorTuple(color)) {
6025
+ return Object.assign(Object.assign({}, baseStyle), { background: createStripedPattern(color[0], color[1]) });
6026
+ }
6027
+ return Object.assign(Object.assign({}, baseStyle), { background: color });
6028
+ };
6029
+ const legendSwatchStyle = {
6030
+ width: "18px",
6031
+ height: "18px",
6032
+ borderRadius: "2px",
6033
+ flexShrink: 0
6034
+ };
6035
+ const COLOR_RED = "var(--ui-color-red-800)";
6036
+ const COLOR_AMBER = "var(--ui-color-amber-700)";
6037
+ const COLOR_GREY_DARK = "var(--ui-color-slate-700)";
6038
+ const COLOR_GREY_LIGHT = "var(--ui-color-slate-300)";
6039
+ const COLOR_BLUE = "var(--ui-color-blue-200)";
6040
+ const BORDER_COLOR = COLOR_GREY_LIGHT;
6041
+ const BORDER_RADIUS = "var(--ui-radius-sm, 4px)";
6042
+ const barContainerStyle = {
6043
+ width: "100%",
6044
+ border: `1px solid ${BORDER_COLOR}`,
6045
+ borderRadius: BORDER_RADIUS,
6046
+ overflow: "hidden"
6047
+ };
6048
+ const barStyle = {
6049
+ display: "flex",
6050
+ alignItems: "center",
6051
+ width: "100%",
6052
+ height: "24px",
6053
+ padding: "0 3px",
6054
+ // 3px looks better than 4px
6055
+ boxSizing: "border-box"
6056
+ };
6057
+ const ticksContainerStyle = {
6058
+ position: "relative",
6059
+ width: "100%",
6060
+ height: "20px"
6061
+ };
6062
+ const RangeCoverageComponent = ({ sections, start, end, ticks = [], title, legendSwatches, className }) => {
6063
+ validateNoOverlaps(sections);
6064
+ const segments = calculateSegments(sections, start, end);
6065
+ return jsxRuntime.jsx(Box, { className, children: jsxRuntime.jsxs(Stack, { gap: "xs", width: "full", align: "stretch", children: [jsxRuntime.jsxs(Stack, { justify: "between", axis: "x", align: "center", children: [jsxRuntime.jsx(Title, { variant: "xs", level: "3", children: title }), legendSwatches && (legendSwatches === null || legendSwatches === void 0 ? void 0 : legendSwatches.length) > 0 && jsxRuntime.jsx(Stack, { axis: "x", gap: "m", children: jsxRuntime.jsx(Stack, { axis: "x", gap: "xxs", align: "center", children: legendSwatches === null || legendSwatches === void 0 ? void 0 : legendSwatches.map((swatch) => {
6066
+ const background = isColorTuple(swatch.color) ? createStripedPattern(swatch.color[0], swatch.color[1]) : swatch.color;
6067
+ return jsxRuntime.jsxs(React.Fragment, { children: [jsxRuntime.jsx("div", { style: Object.assign(Object.assign({}, legendSwatchStyle), { background }) }), jsxRuntime.jsx(Text, { as: "span", children: swatch.label })] }, swatch.label);
6068
+ }) }) })] }), jsxRuntime.jsxs(Stack, { gap: "xs", width: "full", align: "stretch", children: [jsxRuntime.jsx("div", { style: barContainerStyle, children: jsxRuntime.jsx("div", { style: barStyle, children: segments.map((segment, index) => jsxRuntime.jsx("div", { style: Object.assign({ flexBasis: `${segment.widthPercent}%`, flexGrow: 0, flexShrink: 0 }, getSegmentStyle(segment.color)) }, index)) }) }), ticks.length > 0 && jsxRuntime.jsx("div", { style: ticksContainerStyle, children: ticks.map((tick, index) => {
6069
+ const totalRange = Math.abs(end - start);
6070
+ const isDescending = start > end;
6071
+ const position = isDescending ? (start - tick) / totalRange * 100 : (tick - start) / totalRange * 100;
6072
+ const isFirst = index === 0;
6073
+ const isLast = index === ticks.length - 1;
6074
+ return jsxRuntime.jsx(Text, { style: {
6075
+ position: "absolute",
6076
+ color: COLOR_GREY_DARK,
6077
+ whiteSpace: "nowrap",
6078
+ left: `${position}%`,
6079
+ transform: isFirst ? "translateX(0%)" : isLast ? "translateX(-100%)" : "translateX(-50%)"
6080
+ }, children: tick }, tick);
6081
+ }) })] })] }) });
6082
+ };
6083
+ const RangeCoverage = Object.assign(RangeCoverageComponent, {
6084
+ Colors: {
6085
+ RED: COLOR_RED,
6086
+ AMBER: COLOR_AMBER,
6087
+ GREY_DARK: COLOR_GREY_DARK,
6088
+ GREY_LIGHT: COLOR_GREY_LIGHT,
6089
+ BLUE: COLOR_BLUE
6090
+ },
6091
+ generateIntermediateTicks
6092
+ });
6093
+
5941
6094
  const AsideLayout = (_a) => {
5942
6095
  var { aside, children } = _a, rest = __rest(_a, ["aside", "children"]);
5943
6096
  const containerClasses = classNames__default.default("ui:flex-col ui:md:flex-row");
@@ -6444,6 +6597,7 @@ exports.Radio = Radio;
6444
6597
  exports.RadioGroup = RadioGroup;
6445
6598
  exports.RadioGroupV2 = RadioGroupV2;
6446
6599
  exports.RadioV2 = RadioV2;
6600
+ exports.RangeCoverage = RangeCoverage;
6447
6601
  exports.RedAlertColoredIcon = RedAlertColoredIcon;
6448
6602
  exports.RedAlertIcon = RedAlertIcon;
6449
6603
  exports.RightArrowIcon = ChevronRightIcon;