@zendesk/react-measure-timing-hooks
Version:
react hooks for measuring time to interactive and time to render of components
161 lines (156 loc) • 7.19 kB
JavaScript
"use strict";
/* eslint-disable no-magic-numbers */
/* eslint-disable import/no-extraneous-dependencies */
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const react_1 = __importDefault(require("react"));
const styled_components_1 = __importStar(require("styled-components"));
const annotation_1 = require("@visx/annotation");
const event_1 = require("@visx/event");
const shape_1 = require("@visx/shape");
const text_1 = require("@visx/text");
const react_theming_1 = require("@zendeskgarden/react-theming");
const constants_1 = require("../constants");
const interactiveStyles = `
cursor: pointer;
transition: all 0.2s ease-in-out;
&:hover {
filter: brightness(1.2);
}
`;
const MIN_SPAN_WIDTH = 10; // minimum width in pixels for any span bar
const StyledLine = (0, styled_components_1.default)(shape_1.Line) `
${interactiveStyles}
&:hover {
stroke-opacity: 0.8;
stroke-width: 3.5px;
}
`;
const StyledBar = (0, styled_components_1.default)(shape_1.Bar) `
${interactiveStyles}
&:hover {
opacity: 0.7 !important;
stroke: #fff;
stroke-width: 2px;
}
${(props) => props.$isTiny &&
`
stroke: ${props.$fill};
stroke-width: 2px;
rx: 4px;
&:hover {
stroke-width: 3px;
filter: brightness(1.3);
}
`}
`;
const InteractiveSpan = (props) => {
const { xScale, yScale, yMax, data, showTooltip, hideTooltip, onClick, scrollContainerRef, titleColor: color, title, annotateAt, ...restProps } = props;
let tooltipTimeout;
const theme = (0, styled_components_1.useTheme)();
const handleMouseLeave = () => {
// prevent tooltip flickering
tooltipTimeout = window.setTimeout(() => {
hideTooltip();
}, 300);
};
const handleMouseMove = (event) => {
if (tooltipTimeout)
clearTimeout(tooltipTimeout);
if (!('ownerSVGElement' in event.target))
return;
const coords = (0, event_1.localPoint)(event.target.ownerSVGElement, event);
if (coords && scrollContainerRef.current) {
const { scrollTop } = scrollContainerRef.current;
showTooltip({
tooltipLeft: coords.x + 20,
tooltipTop: coords.y + 10 - scrollTop,
tooltipData: data,
});
}
};
const handleClick = (event) => {
event.stopPropagation(); // Prevent click from bubbling to container
onClick();
};
let element;
if (restProps.type === 'line') {
element = (react_1.default.createElement(StyledLine, { ...restProps, from: {
x: xScale(data.annotation.operationRelativeEndTime),
y: 0,
}, to: {
x: xScale(data.annotation.operationRelativeEndTime),
y: yMax,
}, stroke: constants_1.BAR_FILL_COLOR[data.type], strokeOpacity: 0.3, strokeWidth: 2.5, strokeDasharray: "8,4", strokeLinecap: "round", onMouseMove: handleMouseMove, onMouseLeave: handleMouseLeave, onClick: handleClick }));
}
else {
/* Calculate if span is tiny based on scaled width */
const scaledWidth = xScale(data.annotation.operationRelativeEndTime) -
xScale(data.annotation.operationRelativeStartTime);
const isTiny = scaledWidth < MIN_SPAN_WIDTH;
const width = isTiny ? MIN_SPAN_WIDTH : scaledWidth;
const fill = data.span.status === 'error'
? (0, react_theming_1.getColor)({ theme, variable: 'background.dangerEmphasis' })
: constants_1.BAR_FILL_COLOR[data.type];
const height = isTiny ? yScale.bandwidth() / 2 : yScale.bandwidth();
const y = (yScale(data.groupName) ?? 0) + (isTiny ? yScale.bandwidth() / 4 : 0);
element = (react_1.default.createElement(react_1.default.Fragment, null,
react_1.default.createElement(StyledBar, { ...restProps, "data-status": data.span.status, x: xScale(data.annotation.operationRelativeStartTime), y: y, width: width, height: height, fill: fill, rx: 2, onMouseMove: handleMouseMove, onMouseLeave: handleMouseLeave, onClick: handleClick }),
data.span.status === 'error' && (react_1.default.createElement(text_1.Text, { x: (xScale(data.annotation.operationRelativeStartTime) +
xScale(data.annotation.operationRelativeEndTime)) /
2, y: yScale(data.groupName) + yScale.bandwidth() / 2, dy: ".33em", fontSize: 12, textAnchor: "middle", fill: (0, react_theming_1.getColor)({ theme, variable: 'background.danger' }), style: { pointerEvents: 'none' } }, "\u274C"))));
}
const xCoordinate = xScale(data.annotation.operationRelativeEndTime);
return (react_1.default.createElement(react_1.default.Fragment, null,
element,
annotateAt === 'top' && (react_1.default.createElement(annotation_1.Annotation, { x: xCoordinate + 15, y: -2, dx: 0, dy: 0 },
react_1.default.createElement(annotation_1.Label, { fontColor: color, title: title, titleFontSize: 13, subtitle: `${data.annotation.operationRelativeEndTime.toFixed(2)} ms`, showAnchorLine: false, backgroundFill: (0, react_theming_1.getColor)({
theme,
variable: 'background.success',
}), titleProps: {
width: 200,
color: (0, react_theming_1.getColor)({ theme, variable: 'foreground.primary' }),
}, backgroundProps: {
opacity: 1,
rx: 5,
width: 160,
} })))));
};
// eslint-disable-next-line import/no-default-export
exports.default = InteractiveSpan;
//# sourceMappingURL=InteractiveSpan.js.map