@trackunit/react-components 1.16.7 → 1.16.9

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.
package/index.cjs.js CHANGED
@@ -2166,6 +2166,43 @@ const getMarginValue = (height) => {
2166
2166
  }
2167
2167
  return "0";
2168
2168
  };
2169
+ /**
2170
+ * Type-safe helper to construct a CSSLength from a number and unit.
2171
+ * Uses a generic to preserve the specific unit type in the return type.
2172
+ */
2173
+ const makeCSSLength = (value, unit) => {
2174
+ return `${value}${unit}`;
2175
+ };
2176
+ /**
2177
+ * Generates a random CSS length value.
2178
+ *
2179
+ * Note: For React components, prefer `useRandomCSSLengths` hook to ensure stable values across re-renders.
2180
+ *
2181
+ * @param params - The parameters object
2182
+ * @param params.min - Minimum numeric value
2183
+ * @param params.max - Maximum numeric value
2184
+ * @param params.unit - CSS unit (defaults to "%")
2185
+ * @returns {CSSLength} A CSS length string (e.g., "65%", "120px", "4rem")
2186
+ */
2187
+ const getRandomCSSLength = ({ min, max, unit = "%", }) => {
2188
+ const randomValue = Math.floor(Math.random() * (max - min + 1)) + min;
2189
+ return makeCSSLength(randomValue, unit);
2190
+ };
2191
+ /**
2192
+ * React hook that generates stable random CSS length values for skeleton loading components.
2193
+ *
2194
+ * Values are memoized and only regenerate when count, min, max, or unit changes.
2195
+ *
2196
+ * @param params - The parameters object
2197
+ * @param params.count - Number of random lengths to generate
2198
+ * @param params.min - Minimum numeric value
2199
+ * @param params.max - Maximum numeric value
2200
+ * @param params.unit - CSS unit (defaults to "%")
2201
+ * @returns {Array<CSSLength>} Array of CSS length strings (e.g., ["65%", "42%", "78%"])
2202
+ */
2203
+ const useRandomCSSLengths = ({ count, min, max, unit = "%", }) => {
2204
+ return react.useMemo(() => Array.from({ length: count }, () => getRandomCSSLength({ min, max, unit })), [count, min, max, unit]);
2205
+ };
2169
2206
 
2170
2207
  const cvaSkeleton = cssClassVarianceUtilities.cvaMerge([
2171
2208
  "relative",
@@ -4409,19 +4446,6 @@ const KPI = ({ title, value, unit, className, "data-testid": dataTestId, tooltip
4409
4446
  return (jsxRuntime.jsx(Tooltip, { className: "min-w-8 shrink-0", "data-testid": dataTestId ? `${dataTestId}-tooltip` : undefined, disabled: tooltipLabel === undefined || tooltipLabel === "", label: tooltipLabel, placement: "bottom", children: jsxRuntime.jsxs("div", { className: cvaKPI({ variant, className }), "data-testid": dataTestId, style: style, ...rest, children: [jsxRuntime.jsx(Text, { className: tailwindMerge.twMerge("truncate", "whitespace-nowrap"), "data-testid": dataTestId ? `${dataTestId}-title` : undefined, size: isSmallVariant ? "small" : "medium", subtle: true, weight: isSmallVariant ? "normal" : "bold", children: title }), jsxRuntime.jsx("div", { className: tailwindMerge.twMerge("truncate", "whitespace-nowrap"), children: jsxRuntime.jsxs(Text, { className: "truncate whitespace-nowrap text-lg font-medium", "data-testid": dataTestId ? `${dataTestId}-value` : undefined, size: isSmallVariant ? "small" : "large", type: "div", weight: isSmallVariant ? "bold" : "thick", children: [value, " ", unit] }) })] }) }));
4410
4447
  };
4411
4448
 
4412
- /**
4413
- * Generates a random width percentage string for skeleton loading components.
4414
- *
4415
- * @param {object} params - The parameter object
4416
- * @param {number} params.min - Minimum percentage value (e.g., 30 for 30%)
4417
- * @param {number} params.max - Maximum percentage value (e.g., 80 for 80%)
4418
- * @returns {string} A percentage string (e.g., "65%")
4419
- */
4420
- const getResponsiveRandomWidthPercentage = ({ min, max }) => {
4421
- const randomWidth = Math.floor(Math.random() * (max - min + 1)) + min;
4422
- return `${randomWidth}%`;
4423
- };
4424
-
4425
4449
  /**
4426
4450
  * Skeleton loading indicator that mimics the KPI component structure.
4427
4451
  * Uses the same layout, spacing, and visual hierarchy as KPI.
@@ -4429,13 +4453,8 @@ const getResponsiveRandomWidthPercentage = ({ min, max }) => {
4429
4453
  const KPISkeleton = ({ variant = "default", className, "data-testid": dataTestId, style, ...rest }) => {
4430
4454
  const isSmallVariant = variant === "small";
4431
4455
  // Generate stable random widths once and never change them
4432
- const lineWidths = react.useMemo(() => {
4433
- return {
4434
- title: getResponsiveRandomWidthPercentage({ min: 60, max: 85 }),
4435
- value: getResponsiveRandomWidthPercentage({ min: 70, max: 100 }),
4436
- };
4437
- }, []);
4438
- return (jsxRuntime.jsxs("div", { className: cvaKPI({ variant, className }), "data-testid": dataTestId, style: style, ...rest, children: [jsxRuntime.jsx("div", { className: tailwindMerge.twMerge("flex", "items-center", "flex-row", isSmallVariant ? "h-4" : "h-5"), children: jsxRuntime.jsx(SkeletonLabel, { "data-testid": dataTestId ? `${dataTestId}-title-loading` : undefined, textSize: isSmallVariant ? "text-xs" : "text-sm", width: lineWidths.title }) }), jsxRuntime.jsx("div", { className: tailwindMerge.twMerge("truncate", "whitespace-nowrap", "flex h-7 flex-row items-center"), children: jsxRuntime.jsx(SkeletonLabel, { "data-testid": dataTestId ? `${dataTestId}-value-loading` : undefined, textSize: isSmallVariant ? "text-xs" : "text-lg", width: lineWidths.value }) })] }));
4456
+ const [titleWidth, valueWidth] = useRandomCSSLengths({ count: 2, min: 60, max: 100 });
4457
+ return (jsxRuntime.jsxs("div", { className: cvaKPI({ variant, className }), "data-testid": dataTestId, style: style, ...rest, children: [jsxRuntime.jsx("div", { className: tailwindMerge.twMerge("flex", "items-center", "flex-row", isSmallVariant ? "h-4" : "h-5"), children: jsxRuntime.jsx(SkeletonLabel, { "data-testid": dataTestId ? `${dataTestId}-title-loading` : undefined, textSize: isSmallVariant ? "text-xs" : "text-sm", width: titleWidth }) }), jsxRuntime.jsx("div", { className: tailwindMerge.twMerge("truncate", "whitespace-nowrap", "flex h-7 flex-row items-center"), children: jsxRuntime.jsx(SkeletonLabel, { "data-testid": dataTestId ? `${dataTestId}-value-loading` : undefined, textSize: isSmallVariant ? "text-xs" : "text-lg", width: valueWidth }) })] }));
4439
4458
  };
4440
4459
 
4441
4460
  /**
@@ -4776,15 +4795,12 @@ const DEFAULT_SKELETON_LIST_ITEM_PROPS = {
4776
4795
  */
4777
4796
  const ListItemSkeleton = ({ hasThumbnail = DEFAULT_SKELETON_LIST_ITEM_PROPS.hasThumbnail, thumbnailShape = "circle", hasDescription = DEFAULT_SKELETON_LIST_ITEM_PROPS.hasDescription, hasMeta = DEFAULT_SKELETON_LIST_ITEM_PROPS.hasMeta, hasDetails = DEFAULT_SKELETON_LIST_ITEM_PROPS.hasDetails, }) => {
4778
4797
  // Generate stable random widths once and never change them
4779
- const lineWidths = react.useMemo(() => {
4780
- return {
4781
- title: getResponsiveRandomWidthPercentage({ min: 60, max: 85 }),
4782
- description: getResponsiveRandomWidthPercentage({ min: 45, max: 70 }),
4783
- meta: getResponsiveRandomWidthPercentage({ min: 30, max: 55 }),
4784
- details: getResponsiveRandomWidthPercentage({ min: 25, max: 45 }),
4785
- };
4786
- }, []);
4787
- return (jsxRuntime.jsxs("div", { className: cvaListItem({ className: "w-full" }), children: [jsxRuntime.jsxs("div", { className: cvaMainInformationClass({ hasThumbnail, className: "w-full" }), children: [hasThumbnail ? (jsxRuntime.jsx("div", { className: cvaThumbnailContainer({ className: "bg-gray-200" }), children: jsxRuntime.jsx("div", { className: tailwindMerge.twMerge("bg-neutral-300", thumbnailShape === "circle" ? "rounded-full" : "rounded"), style: { width: 20, height: 20 } }) })) : null, jsxRuntime.jsxs("div", { className: cvaTextContainer(), children: [jsxRuntime.jsx("div", { className: cvaTitleRow(), children: jsxRuntime.jsx(SkeletonLabel, { textSize: "text-sm", width: lineWidths.title }) }), hasDescription ? (jsxRuntime.jsx("div", { className: cvaDescriptionRow(), children: jsxRuntime.jsx(SkeletonLabel, { textSize: "text-xs", width: lineWidths.description }) })) : null, hasMeta ? (jsxRuntime.jsx("div", { className: cvaMetaRow(), children: jsxRuntime.jsx(SkeletonLabel, { textSize: "text-xs", width: lineWidths.meta }) })) : null] })] }), hasDetails ? (jsxRuntime.jsx("div", { className: cvaDetailsContainer(), children: jsxRuntime.jsx(SkeletonLabel, { textSize: "text-sm", width: lineWidths.details }) })) : null] }));
4798
+ const [titleWidth, descriptionWidth, metaWidth, detailsWidth] = useRandomCSSLengths({
4799
+ count: 4,
4800
+ min: 25,
4801
+ max: 85,
4802
+ });
4803
+ return (jsxRuntime.jsxs("div", { className: cvaListItem({ className: "w-full" }), children: [jsxRuntime.jsxs("div", { className: cvaMainInformationClass({ hasThumbnail, className: "w-full" }), children: [hasThumbnail ? (jsxRuntime.jsx("div", { className: cvaThumbnailContainer({ className: "bg-gray-200" }), children: jsxRuntime.jsx("div", { className: tailwindMerge.twMerge("bg-neutral-300", thumbnailShape === "circle" ? "rounded-full" : "rounded"), style: { width: 20, height: 20 } }) })) : null, jsxRuntime.jsxs("div", { className: cvaTextContainer(), children: [jsxRuntime.jsx("div", { className: cvaTitleRow(), children: jsxRuntime.jsx(SkeletonLabel, { textSize: "text-sm", width: titleWidth }) }), hasDescription ? (jsxRuntime.jsx("div", { className: cvaDescriptionRow(), children: jsxRuntime.jsx(SkeletonLabel, { textSize: "text-xs", width: descriptionWidth }) })) : null, hasMeta ? (jsxRuntime.jsx("div", { className: cvaMetaRow(), children: jsxRuntime.jsx(SkeletonLabel, { textSize: "text-xs", width: metaWidth }) })) : null] })] }), hasDetails ? (jsxRuntime.jsx("div", { className: cvaDetailsContainer(), children: jsxRuntime.jsx(SkeletonLabel, { textSize: "text-sm", width: detailsWidth }) })) : null] }));
4788
4804
  };
4789
4805
 
4790
4806
  /**
@@ -8463,7 +8479,6 @@ exports.cvaZStackItem = cvaZStackItem;
8463
8479
  exports.defaultPageSize = defaultPageSize;
8464
8480
  exports.docs = docs;
8465
8481
  exports.getDevicePixelRatio = getDevicePixelRatio;
8466
- exports.getResponsiveRandomWidthPercentage = getResponsiveRandomWidthPercentage;
8467
8482
  exports.getValueBarColorByValue = getValueBarColorByValue;
8468
8483
  exports.iconColorNames = iconColorNames;
8469
8484
  exports.iconPalette = iconPalette;
@@ -8496,6 +8511,7 @@ exports.useOverflowItems = useOverflowItems;
8496
8511
  exports.usePopoverContext = usePopoverContext;
8497
8512
  exports.usePrevious = usePrevious;
8498
8513
  exports.usePrompt = usePrompt;
8514
+ exports.useRandomCSSLengths = useRandomCSSLengths;
8499
8515
  exports.useRelayPagination = useRelayPagination;
8500
8516
  exports.useResize = useResize;
8501
8517
  exports.useScrollBlock = useScrollBlock;
package/index.esm.js CHANGED
@@ -2164,6 +2164,43 @@ const getMarginValue = (height) => {
2164
2164
  }
2165
2165
  return "0";
2166
2166
  };
2167
+ /**
2168
+ * Type-safe helper to construct a CSSLength from a number and unit.
2169
+ * Uses a generic to preserve the specific unit type in the return type.
2170
+ */
2171
+ const makeCSSLength = (value, unit) => {
2172
+ return `${value}${unit}`;
2173
+ };
2174
+ /**
2175
+ * Generates a random CSS length value.
2176
+ *
2177
+ * Note: For React components, prefer `useRandomCSSLengths` hook to ensure stable values across re-renders.
2178
+ *
2179
+ * @param params - The parameters object
2180
+ * @param params.min - Minimum numeric value
2181
+ * @param params.max - Maximum numeric value
2182
+ * @param params.unit - CSS unit (defaults to "%")
2183
+ * @returns {CSSLength} A CSS length string (e.g., "65%", "120px", "4rem")
2184
+ */
2185
+ const getRandomCSSLength = ({ min, max, unit = "%", }) => {
2186
+ const randomValue = Math.floor(Math.random() * (max - min + 1)) + min;
2187
+ return makeCSSLength(randomValue, unit);
2188
+ };
2189
+ /**
2190
+ * React hook that generates stable random CSS length values for skeleton loading components.
2191
+ *
2192
+ * Values are memoized and only regenerate when count, min, max, or unit changes.
2193
+ *
2194
+ * @param params - The parameters object
2195
+ * @param params.count - Number of random lengths to generate
2196
+ * @param params.min - Minimum numeric value
2197
+ * @param params.max - Maximum numeric value
2198
+ * @param params.unit - CSS unit (defaults to "%")
2199
+ * @returns {Array<CSSLength>} Array of CSS length strings (e.g., ["65%", "42%", "78%"])
2200
+ */
2201
+ const useRandomCSSLengths = ({ count, min, max, unit = "%", }) => {
2202
+ return useMemo(() => Array.from({ length: count }, () => getRandomCSSLength({ min, max, unit })), [count, min, max, unit]);
2203
+ };
2167
2204
 
2168
2205
  const cvaSkeleton = cvaMerge([
2169
2206
  "relative",
@@ -4407,19 +4444,6 @@ const KPI = ({ title, value, unit, className, "data-testid": dataTestId, tooltip
4407
4444
  return (jsx(Tooltip, { className: "min-w-8 shrink-0", "data-testid": dataTestId ? `${dataTestId}-tooltip` : undefined, disabled: tooltipLabel === undefined || tooltipLabel === "", label: tooltipLabel, placement: "bottom", children: jsxs("div", { className: cvaKPI({ variant, className }), "data-testid": dataTestId, style: style, ...rest, children: [jsx(Text, { className: twMerge("truncate", "whitespace-nowrap"), "data-testid": dataTestId ? `${dataTestId}-title` : undefined, size: isSmallVariant ? "small" : "medium", subtle: true, weight: isSmallVariant ? "normal" : "bold", children: title }), jsx("div", { className: twMerge("truncate", "whitespace-nowrap"), children: jsxs(Text, { className: "truncate whitespace-nowrap text-lg font-medium", "data-testid": dataTestId ? `${dataTestId}-value` : undefined, size: isSmallVariant ? "small" : "large", type: "div", weight: isSmallVariant ? "bold" : "thick", children: [value, " ", unit] }) })] }) }));
4408
4445
  };
4409
4446
 
4410
- /**
4411
- * Generates a random width percentage string for skeleton loading components.
4412
- *
4413
- * @param {object} params - The parameter object
4414
- * @param {number} params.min - Minimum percentage value (e.g., 30 for 30%)
4415
- * @param {number} params.max - Maximum percentage value (e.g., 80 for 80%)
4416
- * @returns {string} A percentage string (e.g., "65%")
4417
- */
4418
- const getResponsiveRandomWidthPercentage = ({ min, max }) => {
4419
- const randomWidth = Math.floor(Math.random() * (max - min + 1)) + min;
4420
- return `${randomWidth}%`;
4421
- };
4422
-
4423
4447
  /**
4424
4448
  * Skeleton loading indicator that mimics the KPI component structure.
4425
4449
  * Uses the same layout, spacing, and visual hierarchy as KPI.
@@ -4427,13 +4451,8 @@ const getResponsiveRandomWidthPercentage = ({ min, max }) => {
4427
4451
  const KPISkeleton = ({ variant = "default", className, "data-testid": dataTestId, style, ...rest }) => {
4428
4452
  const isSmallVariant = variant === "small";
4429
4453
  // Generate stable random widths once and never change them
4430
- const lineWidths = useMemo(() => {
4431
- return {
4432
- title: getResponsiveRandomWidthPercentage({ min: 60, max: 85 }),
4433
- value: getResponsiveRandomWidthPercentage({ min: 70, max: 100 }),
4434
- };
4435
- }, []);
4436
- return (jsxs("div", { className: cvaKPI({ variant, className }), "data-testid": dataTestId, style: style, ...rest, children: [jsx("div", { className: twMerge("flex", "items-center", "flex-row", isSmallVariant ? "h-4" : "h-5"), children: jsx(SkeletonLabel, { "data-testid": dataTestId ? `${dataTestId}-title-loading` : undefined, textSize: isSmallVariant ? "text-xs" : "text-sm", width: lineWidths.title }) }), jsx("div", { className: twMerge("truncate", "whitespace-nowrap", "flex h-7 flex-row items-center"), children: jsx(SkeletonLabel, { "data-testid": dataTestId ? `${dataTestId}-value-loading` : undefined, textSize: isSmallVariant ? "text-xs" : "text-lg", width: lineWidths.value }) })] }));
4454
+ const [titleWidth, valueWidth] = useRandomCSSLengths({ count: 2, min: 60, max: 100 });
4455
+ return (jsxs("div", { className: cvaKPI({ variant, className }), "data-testid": dataTestId, style: style, ...rest, children: [jsx("div", { className: twMerge("flex", "items-center", "flex-row", isSmallVariant ? "h-4" : "h-5"), children: jsx(SkeletonLabel, { "data-testid": dataTestId ? `${dataTestId}-title-loading` : undefined, textSize: isSmallVariant ? "text-xs" : "text-sm", width: titleWidth }) }), jsx("div", { className: twMerge("truncate", "whitespace-nowrap", "flex h-7 flex-row items-center"), children: jsx(SkeletonLabel, { "data-testid": dataTestId ? `${dataTestId}-value-loading` : undefined, textSize: isSmallVariant ? "text-xs" : "text-lg", width: valueWidth }) })] }));
4437
4456
  };
4438
4457
 
4439
4458
  /**
@@ -4774,15 +4793,12 @@ const DEFAULT_SKELETON_LIST_ITEM_PROPS = {
4774
4793
  */
4775
4794
  const ListItemSkeleton = ({ hasThumbnail = DEFAULT_SKELETON_LIST_ITEM_PROPS.hasThumbnail, thumbnailShape = "circle", hasDescription = DEFAULT_SKELETON_LIST_ITEM_PROPS.hasDescription, hasMeta = DEFAULT_SKELETON_LIST_ITEM_PROPS.hasMeta, hasDetails = DEFAULT_SKELETON_LIST_ITEM_PROPS.hasDetails, }) => {
4776
4795
  // Generate stable random widths once and never change them
4777
- const lineWidths = useMemo(() => {
4778
- return {
4779
- title: getResponsiveRandomWidthPercentage({ min: 60, max: 85 }),
4780
- description: getResponsiveRandomWidthPercentage({ min: 45, max: 70 }),
4781
- meta: getResponsiveRandomWidthPercentage({ min: 30, max: 55 }),
4782
- details: getResponsiveRandomWidthPercentage({ min: 25, max: 45 }),
4783
- };
4784
- }, []);
4785
- return (jsxs("div", { className: cvaListItem({ className: "w-full" }), children: [jsxs("div", { className: cvaMainInformationClass({ hasThumbnail, className: "w-full" }), children: [hasThumbnail ? (jsx("div", { className: cvaThumbnailContainer({ className: "bg-gray-200" }), children: jsx("div", { className: twMerge("bg-neutral-300", thumbnailShape === "circle" ? "rounded-full" : "rounded"), style: { width: 20, height: 20 } }) })) : null, jsxs("div", { className: cvaTextContainer(), children: [jsx("div", { className: cvaTitleRow(), children: jsx(SkeletonLabel, { textSize: "text-sm", width: lineWidths.title }) }), hasDescription ? (jsx("div", { className: cvaDescriptionRow(), children: jsx(SkeletonLabel, { textSize: "text-xs", width: lineWidths.description }) })) : null, hasMeta ? (jsx("div", { className: cvaMetaRow(), children: jsx(SkeletonLabel, { textSize: "text-xs", width: lineWidths.meta }) })) : null] })] }), hasDetails ? (jsx("div", { className: cvaDetailsContainer(), children: jsx(SkeletonLabel, { textSize: "text-sm", width: lineWidths.details }) })) : null] }));
4796
+ const [titleWidth, descriptionWidth, metaWidth, detailsWidth] = useRandomCSSLengths({
4797
+ count: 4,
4798
+ min: 25,
4799
+ max: 85,
4800
+ });
4801
+ return (jsxs("div", { className: cvaListItem({ className: "w-full" }), children: [jsxs("div", { className: cvaMainInformationClass({ hasThumbnail, className: "w-full" }), children: [hasThumbnail ? (jsx("div", { className: cvaThumbnailContainer({ className: "bg-gray-200" }), children: jsx("div", { className: twMerge("bg-neutral-300", thumbnailShape === "circle" ? "rounded-full" : "rounded"), style: { width: 20, height: 20 } }) })) : null, jsxs("div", { className: cvaTextContainer(), children: [jsx("div", { className: cvaTitleRow(), children: jsx(SkeletonLabel, { textSize: "text-sm", width: titleWidth }) }), hasDescription ? (jsx("div", { className: cvaDescriptionRow(), children: jsx(SkeletonLabel, { textSize: "text-xs", width: descriptionWidth }) })) : null, hasMeta ? (jsx("div", { className: cvaMetaRow(), children: jsx(SkeletonLabel, { textSize: "text-xs", width: metaWidth }) })) : null] })] }), hasDetails ? (jsx("div", { className: cvaDetailsContainer(), children: jsx(SkeletonLabel, { textSize: "text-sm", width: detailsWidth }) })) : null] }));
4786
4802
  };
4787
4803
 
4788
4804
  /**
@@ -8339,4 +8355,4 @@ const useWindowActivity = ({ onFocus, onBlur, skip = false } = { onBlur: undefin
8339
8355
  return useMemo(() => ({ focused }), [focused]);
8340
8356
  };
8341
8357
 
8342
- export { ActionRenderer, Alert, Badge, Breadcrumb, BreadcrumbContainer, Button, Card, CardBody, CardFooter, CardHeader, Collapse, CompletionStatusIndicator, CopyableText, DEFAULT_SKELETON_PREFERENCE_CARD_PROPS, DetailsList, EmptyState, EmptyValue, ExternalLink, GridAreas, Heading, Highlight, HorizontalOverflowScroller, Icon, IconButton, Indicator, KPI, KPICard, KPICardSkeleton, KPISkeleton, List, ListItem, MenuDivider, MenuItem, MenuList, MoreMenu, Notice, PackageNameStoryComponent, Page, PageContent, PageHeader, PageHeaderKpiMetrics, PageHeaderSecondaryActions, PageHeaderTitle, Pagination, Polygon, Popover, PopoverContent, PopoverTitle, PopoverTrigger, Portal, PreferenceCard, PreferenceCardSkeleton, Prompt, ROLE_CARD, SectionHeader, Sidebar, SkeletonBlock, SkeletonLabel, SkeletonLines, Spacer, Spinner, StarButton, Tab, TabContent, TabList, Tabs, Tag, Text, ToggleGroup, Tooltip, TrendIndicator, TrendIndicators, ValueBar, ZStack, createGrid, cvaButton, cvaButtonPrefixSuffix, cvaButtonSpinner, cvaButtonSpinnerContainer, cvaClickable, cvaContainerStyles, cvaContentContainer, cvaContentWrapper, cvaDescriptionCard, cvaIconBackground, cvaIconButton, cvaImgStyles, cvaIndicator, cvaIndicatorIcon, cvaIndicatorIconBackground, cvaIndicatorLabel, cvaIndicatorPing, cvaInputContainer, cvaInteractableItem, cvaList, cvaListContainer, cvaListItem$1 as cvaListItem, cvaMenu, cvaMenuItem, cvaMenuItemLabel, cvaMenuItemPrefix, cvaMenuItemStyle, cvaMenuItemSuffix, cvaMenuList, cvaMenuListDivider, cvaMenuListItem, cvaMenuListMultiSelect, cvaPageHeader, cvaPageHeaderContainer, cvaPageHeaderHeading, cvaPreferenceCard, cvaTitleCard, cvaToggleGroup, cvaToggleGroupWithSlidingBackground, cvaToggleItem, cvaToggleItemContent, cvaToggleItemText, cvaZStackContainer, cvaZStackItem, defaultPageSize, docs, getDevicePixelRatio, getResponsiveRandomWidthPercentage, getValueBarColorByValue, iconColorNames, iconPalette, noPagination, preferenceCardGrid, useClickOutside, useContainerBreakpoints, useContinuousTimeout, useCopyToClipboard, useCustomEncoding, useDebounce, useDevicePixelRatio, useElevatedReducer, useElevatedState, useGridAreas, useHover, useInfiniteScroll, useIsFirstRender, useIsFullscreen, useIsTextTruncated, useKeyboardShortcut, useList, useListItemHeight, useLocalStorage, useLocalStorageReducer, useMeasure, useMergeRefs, useModifierKey, useOverflowItems, usePopoverContext, usePrevious, usePrompt, useRelayPagination, useResize, useScrollBlock, useScrollDetection, useSelfUpdatingRef, useTextSearch, useTimeout, useViewportBreakpoints, useWatch, useWindowActivity };
8358
+ export { ActionRenderer, Alert, Badge, Breadcrumb, BreadcrumbContainer, Button, Card, CardBody, CardFooter, CardHeader, Collapse, CompletionStatusIndicator, CopyableText, DEFAULT_SKELETON_PREFERENCE_CARD_PROPS, DetailsList, EmptyState, EmptyValue, ExternalLink, GridAreas, Heading, Highlight, HorizontalOverflowScroller, Icon, IconButton, Indicator, KPI, KPICard, KPICardSkeleton, KPISkeleton, List, ListItem, MenuDivider, MenuItem, MenuList, MoreMenu, Notice, PackageNameStoryComponent, Page, PageContent, PageHeader, PageHeaderKpiMetrics, PageHeaderSecondaryActions, PageHeaderTitle, Pagination, Polygon, Popover, PopoverContent, PopoverTitle, PopoverTrigger, Portal, PreferenceCard, PreferenceCardSkeleton, Prompt, ROLE_CARD, SectionHeader, Sidebar, SkeletonBlock, SkeletonLabel, SkeletonLines, Spacer, Spinner, StarButton, Tab, TabContent, TabList, Tabs, Tag, Text, ToggleGroup, Tooltip, TrendIndicator, TrendIndicators, ValueBar, ZStack, createGrid, cvaButton, cvaButtonPrefixSuffix, cvaButtonSpinner, cvaButtonSpinnerContainer, cvaClickable, cvaContainerStyles, cvaContentContainer, cvaContentWrapper, cvaDescriptionCard, cvaIconBackground, cvaIconButton, cvaImgStyles, cvaIndicator, cvaIndicatorIcon, cvaIndicatorIconBackground, cvaIndicatorLabel, cvaIndicatorPing, cvaInputContainer, cvaInteractableItem, cvaList, cvaListContainer, cvaListItem$1 as cvaListItem, cvaMenu, cvaMenuItem, cvaMenuItemLabel, cvaMenuItemPrefix, cvaMenuItemStyle, cvaMenuItemSuffix, cvaMenuList, cvaMenuListDivider, cvaMenuListItem, cvaMenuListMultiSelect, cvaPageHeader, cvaPageHeaderContainer, cvaPageHeaderHeading, cvaPreferenceCard, cvaTitleCard, cvaToggleGroup, cvaToggleGroupWithSlidingBackground, cvaToggleItem, cvaToggleItemContent, cvaToggleItemText, cvaZStackContainer, cvaZStackItem, defaultPageSize, docs, getDevicePixelRatio, getValueBarColorByValue, iconColorNames, iconPalette, noPagination, preferenceCardGrid, useClickOutside, useContainerBreakpoints, useContinuousTimeout, useCopyToClipboard, useCustomEncoding, useDebounce, useDevicePixelRatio, useElevatedReducer, useElevatedState, useGridAreas, useHover, useInfiniteScroll, useIsFirstRender, useIsFullscreen, useIsTextTruncated, useKeyboardShortcut, useList, useListItemHeight, useLocalStorage, useLocalStorageReducer, useMeasure, useMergeRefs, useModifierKey, useOverflowItems, usePopoverContext, usePrevious, usePrompt, useRandomCSSLengths, useRelayPagination, useResize, useScrollBlock, useScrollDetection, useSelfUpdatingRef, useTextSearch, useTimeout, useViewportBreakpoints, useWatch, useWindowActivity };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@trackunit/react-components",
3
- "version": "1.16.7",
3
+ "version": "1.16.9",
4
4
  "repository": "https://github.com/Trackunit/manager",
5
5
  "license": "SEE LICENSE IN LICENSE.txt",
6
6
  "engines": {
@@ -14,10 +14,10 @@
14
14
  "@floating-ui/react": "^0.26.25",
15
15
  "string-ts": "^2.0.0",
16
16
  "tailwind-merge": "^2.0.0",
17
- "@trackunit/ui-design-tokens": "1.11.26",
18
- "@trackunit/css-class-variance-utilities": "1.11.26",
19
- "@trackunit/shared-utils": "1.13.26",
20
- "@trackunit/ui-icons": "1.11.25",
17
+ "@trackunit/ui-design-tokens": "1.11.27",
18
+ "@trackunit/css-class-variance-utilities": "1.11.27",
19
+ "@trackunit/shared-utils": "1.13.27",
20
+ "@trackunit/ui-icons": "1.11.26",
21
21
  "@tanstack/react-router": "1.114.29",
22
22
  "es-toolkit": "^1.39.10",
23
23
  "@tanstack/react-virtual": "3.13.12",
@@ -1,5 +1,6 @@
1
1
  import { fontSizeKeys } from "@trackunit/ui-design-tokens";
2
2
  export type CSSLength = `${number}px` | `${number}rem` | `${number}em` | `${number}ch` | `${number}ex` | `${number}%`;
3
+ export type CSSLengthUnit = "px" | "rem" | "em" | "ch" | "ex" | "%";
3
4
  export type TextSizeKey = `text-${fontSizeKeys}`;
4
5
  export type SkeletonVariant = "text" | "block";
5
6
  export declare const VALID_SIZE_KEYS: ReadonlyArray<fontSizeKeys>;
@@ -26,3 +27,37 @@ export declare const getHeightValue: (height: TextSizeKey | number | string, var
26
27
  * @returns {string} The calculated CSS margin value
27
28
  */
28
29
  export declare const getMarginValue: (height: TextSizeKey | number | string) => string;
30
+ /**
31
+ * Generates a random CSS length value.
32
+ *
33
+ * Note: For React components, prefer `useRandomCSSLengths` hook to ensure stable values across re-renders.
34
+ *
35
+ * @param params - The parameters object
36
+ * @param params.min - Minimum numeric value
37
+ * @param params.max - Maximum numeric value
38
+ * @param params.unit - CSS unit (defaults to "%")
39
+ * @returns {CSSLength} A CSS length string (e.g., "65%", "120px", "4rem")
40
+ */
41
+ export declare const getRandomCSSLength: ({ min, max, unit, }: {
42
+ min: number;
43
+ max: number;
44
+ unit?: CSSLengthUnit;
45
+ }) => CSSLength;
46
+ /**
47
+ * React hook that generates stable random CSS length values for skeleton loading components.
48
+ *
49
+ * Values are memoized and only regenerate when count, min, max, or unit changes.
50
+ *
51
+ * @param params - The parameters object
52
+ * @param params.count - Number of random lengths to generate
53
+ * @param params.min - Minimum numeric value
54
+ * @param params.max - Maximum numeric value
55
+ * @param params.unit - CSS unit (defaults to "%")
56
+ * @returns {Array<CSSLength>} Array of CSS length strings (e.g., ["65%", "42%", "78%"])
57
+ */
58
+ export declare const useRandomCSSLengths: ({ count, min, max, unit, }: {
59
+ count: number;
60
+ min: number;
61
+ max: number;
62
+ unit?: CSSLengthUnit;
63
+ }) => Array<CSSLength>;
@@ -1,8 +1,6 @@
1
1
  import { StringWithAutocompleteOptions } from "@trackunit/shared-utils";
2
- import { fontSizeKeys } from "@trackunit/ui-design-tokens";
3
2
  import { CommonProps } from "../../common/CommonProps";
4
- type CSSLength = `${number}px` | `${number}rem` | `${number}em` | `${number}ch` | `${number}ex` | `${number}%`;
5
- type TextSizeKey = `text-${fontSizeKeys}`;
3
+ import { CSSLength, TextSizeKey } from "../Skeleton/Skeleton.helpers";
6
4
  /**
7
5
  * Preset configurations for common skeleton patterns.
8
6
  */
package/src/index.d.ts CHANGED
@@ -78,11 +78,12 @@ export * from "./components/Prompt/Prompt";
78
78
  export * from "./components/SectionHeader/SectionHeader";
79
79
  export * from "./components/Sidebar/Sidebar";
80
80
  export * from "./components/Sidebar/useOverflowItems";
81
+ export { useRandomCSSLengths } from "./components/Skeleton/Skeleton.helpers";
82
+ export type { CSSLength, CSSLengthUnit } from "./components/Skeleton/Skeleton.helpers";
81
83
  export { SkeletonBlock } from "./components/Skeleton/SkeletonBlock/SkeletonBlock";
82
84
  export type { SkeletonBlockProps } from "./components/Skeleton/SkeletonBlock/SkeletonBlock";
83
85
  export { SkeletonLabel } from "./components/Skeleton/SkeletonLabel/SkeletonLabel";
84
86
  export type { SkeletonLabelProps } from "./components/Skeleton/SkeletonLabel/SkeletonLabel";
85
- export * from "./components/SkeletonLines/skeleton-utils";
86
87
  export * from "./components/SkeletonLines/SkeletonLines";
87
88
  export * from "./components/Spacer/Spacer";
88
89
  export * from "./components/Spinner/Spinner";
@@ -1,12 +0,0 @@
1
- /**
2
- * Generates a random width percentage string for skeleton loading components.
3
- *
4
- * @param {object} params - The parameter object
5
- * @param {number} params.min - Minimum percentage value (e.g., 30 for 30%)
6
- * @param {number} params.max - Maximum percentage value (e.g., 80 for 80%)
7
- * @returns {string} A percentage string (e.g., "65%")
8
- */
9
- export declare const getResponsiveRandomWidthPercentage: ({ min, max }: {
10
- min: number;
11
- max: number;
12
- }) => `${number}%`;