@codacy/ui-components 0.67.41 → 0.67.43

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.
@@ -0,0 +1,5 @@
1
+ import React from 'react';
2
+ import { BreadcrumbsItemProps, BreadcrumbsProps } from './Breadcrumbs.types';
3
+ export declare const Breadcrumbs: React.FC<BreadcrumbsProps> & {
4
+ Item: React.FC<BreadcrumbsItemProps>;
5
+ };
@@ -0,0 +1,63 @@
1
+ import React from 'react';
2
+ import { Caption } from '../Typography';
3
+ import { Flex } from '../Flexbox';
4
+ import { BreadcrumbsItemWrapper } from './Breadcrumbs.styles';
5
+ import { useBreadcrumbsOverflow, SEGMENT_ATTR } from './useBreadcrumbsOverflow';
6
+ const ELLIPSIS = Symbol('breadcrumbs-ellipsis');
7
+ function findChildren(ofType, children) {
8
+ return React.Children.toArray(children).filter(child => /*#__PURE__*/React.isValidElement(child) && child.type === ofType);
9
+ }
10
+ const BreadcrumbsItem = ({
11
+ children,
12
+ ...props
13
+ }) => {
14
+ return /*#__PURE__*/React.createElement(BreadcrumbsItemWrapper, props, children);
15
+ };
16
+ const BreadcrumbsList = ({
17
+ children,
18
+ separator,
19
+ size = 'sm',
20
+ itemMinWidth
21
+ }) => {
22
+ const breadcrumbItems = findChildren(BreadcrumbsItem, children);
23
+ const {
24
+ containerRef,
25
+ collapsed
26
+ } = useBreadcrumbsOverflow(breadcrumbItems.length, itemMinWidth);
27
+
28
+ // When collapsed, keep only the first and last segment and replace the
29
+ // middle with an ellipsis. Needs at least 3 segments to be worth collapsing.
30
+ const displayed = collapsed && breadcrumbItems.length > 2 ? [breadcrumbItems[0], ELLIPSIS, breadcrumbItems[breadcrumbItems.length - 1]] : breadcrumbItems;
31
+ return /*#__PURE__*/React.createElement(Flex, {
32
+ ref: containerRef,
33
+ overflow: "hidden"
34
+ }, displayed.map((item, index) => {
35
+ const isLast = index === displayed.length - 1;
36
+ const separatorNode = !isLast && /*#__PURE__*/React.createElement(Caption, {
37
+ size: size,
38
+ fontWeight: "medium",
39
+ color: "text-primary",
40
+ mx: 1,
41
+ flexShrink: 0
42
+ }, separator);
43
+ if (item === ELLIPSIS) {
44
+ return /*#__PURE__*/React.createElement(React.Fragment, {
45
+ key: "ellipsis"
46
+ }, /*#__PURE__*/React.createElement(Caption, {
47
+ size: size,
48
+ color: "text-secondary",
49
+ flexShrink: 0
50
+ }, "\u2026"), separatorNode);
51
+ }
52
+ return /*#__PURE__*/React.createElement(React.Fragment, {
53
+ key: index
54
+ }, /*#__PURE__*/React.cloneElement(item, {
55
+ current: isLast,
56
+ size: size,
57
+ [SEGMENT_ATTR]: ''
58
+ }), separatorNode);
59
+ }));
60
+ };
61
+ export const Breadcrumbs = Object.assign(BreadcrumbsList, {
62
+ Item: BreadcrumbsItem
63
+ });
@@ -0,0 +1,5 @@
1
+ /// <reference types="react" />
2
+ import { BreadcrumbsItemProps } from './Breadcrumbs.types';
3
+ export declare const BreadcrumbsItemWrapper: import("@emotion/styled").StyledComponent<import("../Typography").CaptionProps & import("react").RefAttributes<HTMLParagraphElement> & {
4
+ theme?: import("@emotion/react").Theme | undefined;
5
+ } & BreadcrumbsItemProps, {}, {}>;
@@ -0,0 +1,34 @@
1
+ import _styled from "@emotion/styled/base";
2
+ import { Caption } from '../Typography';
3
+ const fontSizeKeyBySize = {
4
+ lg: 'l',
5
+ md: 'm',
6
+ sm: 's',
7
+ xs: 'xs'
8
+ };
9
+ export const BreadcrumbsItemWrapper = /*#__PURE__*/_styled(Caption, process.env.NODE_ENV === "production" ? {
10
+ shouldForwardProp: prop => prop !== 'current',
11
+ target: "e1gjlqct0"
12
+ } : {
13
+ shouldForwardProp: prop => prop !== 'current',
14
+ target: "e1gjlqct0",
15
+ label: "codacy"
16
+ })("flex-shrink:1;", ({
17
+ theme,
18
+ size = 'sm'
19
+ }) => `
20
+ &,
21
+ & * {
22
+ font-size: ${theme.fontSizes[fontSizeKeyBySize[size]]} !important;
23
+ }
24
+ `, " ", ({
25
+ current,
26
+ theme
27
+ }) => current && `
28
+ flex-shrink: 0;
29
+ pointer-events: none;
30
+ &,
31
+ & * {
32
+ color: ${theme.colors['text-secondary']} !important;
33
+ }
34
+ `, ";" + (process.env.NODE_ENV === "production" ? "" : "/*# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9CcmVhZGNydW1icy9CcmVhZGNydW1icy5zdHlsZXMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBYXdCIiwiZmlsZSI6Ii4uLy4uL3NyYy9CcmVhZGNydW1icy9CcmVhZGNydW1icy5zdHlsZXMudHMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgc3R5bGVkIGZyb20gJ0BlbW90aW9uL3N0eWxlZCdcbmltcG9ydCB7IEJyZWFkY3J1bWJzSXRlbVByb3BzIH0gZnJvbSAnLi9CcmVhZGNydW1icy50eXBlcydcbmltcG9ydCB7IENhcHRpb24sIFRleHRTaXplIH0gZnJvbSAnLi4vVHlwb2dyYXBoeSdcblxuY29uc3QgZm9udFNpemVLZXlCeVNpemU6IFJlY29yZDxUZXh0U2l6ZSwgJ2wnIHwgJ20nIHwgJ3MnIHwgJ3hzJz4gPSB7XG4gIGxnOiAnbCcsXG4gIG1kOiAnbScsXG4gIHNtOiAncycsXG4gIHhzOiAneHMnLFxufVxuXG5leHBvcnQgY29uc3QgQnJlYWRjcnVtYnNJdGVtV3JhcHBlciA9IHN0eWxlZChDYXB0aW9uLCB7XG4gIHNob3VsZEZvcndhcmRQcm9wOiBwcm9wID0+IHByb3AgIT09ICdjdXJyZW50Jyxcbn0pPEJyZWFkY3J1bWJzSXRlbVByb3BzPmBcbiAgZmxleC1zaHJpbms6IDE7XG5cbiAgJHsoeyB0aGVtZSwgc2l6ZSA9ICdzbScgfSkgPT4gYFxuICAgICYsXG4gICAgJiAqIHtcbiAgICAgIGZvbnQtc2l6ZTogJHt0aGVtZS5mb250U2l6ZXNbZm9udFNpemVLZXlCeVNpemVbc2l6ZV1dfSAhaW1wb3J0YW50O1xuICAgIH1cbiAgYH1cblxuICAkeyh7IGN1cnJlbnQsIHRoZW1lIH0pID0+XG4gICAgY3VycmVudCAmJlxuICAgIGBcbiAgICAgIGZsZXgtc2hyaW5rOiAwO1xuICAgICAgcG9pbnRlci1ldmVudHM6IG5vbmU7XG4gICAgICAmLFxuICAgICAgJiAqIHtcbiAgICAgICAgY29sb3I6ICR7dGhlbWUuY29sb3JzWyd0ZXh0LXNlY29uZGFyeSddfSAhaW1wb3J0YW50O1xuICAgICAgfVxuICAgIGB9XG5gXG4iXX0= */"));
@@ -0,0 +1,15 @@
1
+ /// <reference types="react" />
2
+ import { ColorProps, LayoutProps, SpaceProps, TypographyProps } from '../system-props/types';
3
+ import { ContainerComponentProps } from '../types';
4
+ import { TextSize } from '../Typography';
5
+ export interface BreadcrumbsProps extends ContainerComponentProps, SpaceProps, LayoutProps, ColorProps, TypographyProps {
6
+ children: React.ReactNode;
7
+ separator: string;
8
+ size?: TextSize;
9
+ itemMinWidth?: number;
10
+ }
11
+ export interface BreadcrumbsItemProps extends ContainerComponentProps, SpaceProps, LayoutProps, ColorProps, TypographyProps {
12
+ children: React.ReactNode;
13
+ current?: boolean;
14
+ size?: TextSize;
15
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ export * from './Breadcrumbs';
@@ -0,0 +1 @@
1
+ export * from './Breadcrumbs';
@@ -0,0 +1,11 @@
1
+ /// <reference types="react" />
2
+ /** Marks the segment elements the hook should measure and floor. */
3
+ export declare const SEGMENT_ATTR = "data-breadcrumb-segment";
4
+ /**
5
+ * Detects whether a horizontal row of breadcrumb segments overflows its
6
+ * container and should collapse its middle segments
7
+ */
8
+ export declare const useBreadcrumbsOverflow: (itemCount: number, itemMinWidth?: number) => {
9
+ containerRef: import("react").RefObject<HTMLDivElement>;
10
+ collapsed: boolean;
11
+ };
@@ -0,0 +1,69 @@
1
+ import { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react';
2
+ import { throttle } from 'lodash';
3
+ const FLOOR_REM = 4;
4
+
5
+ /** Marks the segment elements the hook should measure and floor. */
6
+ export const SEGMENT_ATTR = 'data-breadcrumb-segment';
7
+
8
+ /**
9
+ * Detects whether a horizontal row of breadcrumb segments overflows its
10
+ * container and should collapse its middle segments
11
+ */
12
+ export const useBreadcrumbsOverflow = (itemCount, itemMinWidth = FLOOR_REM) => {
13
+ const containerRef = useRef(null);
14
+ // Natural width of the row, cached while expanded so we can still decide
15
+ // whether it would fit again once we're already collapsed.
16
+ const naturalWidthRef = useRef(0);
17
+ const [collapsed, setCollapsed] = useState(false);
18
+ // Latest `collapsed` for reading inside `measure` without making it a dep.
19
+ const collapsedRef = useRef(collapsed);
20
+ collapsedRef.current = collapsed;
21
+
22
+ // Floor every visible segment at min(4rem, its content width)
23
+ const applyFloors = useCallback(() => {
24
+ const el = containerRef.current;
25
+ if (!el) return;
26
+ const remPx = parseFloat(getComputedStyle(document.documentElement).fontSize) || 16;
27
+ const floor = itemMinWidth * remPx;
28
+ const segments = Array.from(el.querySelectorAll(`[${SEGMENT_ATTR}]`));
29
+ segments.forEach(node => node.style.minWidth = '0px');
30
+ const contentWidths = segments.map(node => node.scrollWidth);
31
+ segments.forEach((node, i) => node.style.minWidth = `${Math.min(floor, contentWidths[i])}px`);
32
+ }, [itemMinWidth]);
33
+ const measure = useCallback(() => {
34
+ const el = containerRef.current;
35
+ if (!el) return;
36
+ applyFloors();
37
+ if (!collapsedRef.current) naturalWidthRef.current = el.scrollWidth;
38
+ // +1 tolerance avoids ping-ponging at the exact boundary.
39
+ setCollapsed(naturalWidthRef.current > el.clientWidth + 1);
40
+ }, [applyFloors]);
41
+
42
+ // Measure on mount and whenever the set of segments changes.
43
+ useLayoutEffect(() => {
44
+ naturalWidthRef.current = 0;
45
+ setCollapsed(false);
46
+ measure();
47
+ }, [itemCount, measure]);
48
+
49
+ // After a collapse toggle the rendered segments change; re-floor them without
50
+ // re-deciding, so a shrink-to-fit parent's size change can't cause a flip.
51
+ useLayoutEffect(() => {
52
+ applyFloors();
53
+ }, [collapsed, applyFloors]);
54
+ const throttledMeasure = useMemo(() => throttle(measure, 100), [measure]);
55
+ useEffect(() => {
56
+ const el = containerRef.current;
57
+ if (!el) return;
58
+ const observer = new ResizeObserver(throttledMeasure);
59
+ observer.observe(el);
60
+ return () => {
61
+ observer.disconnect();
62
+ throttledMeasure.cancel();
63
+ };
64
+ }, [throttledMeasure]);
65
+ return {
66
+ containerRef,
67
+ collapsed
68
+ };
69
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@codacy/ui-components",
3
- "version": "0.67.41",
3
+ "version": "0.67.43",
4
4
  "description": "",
5
5
  "license": "ISC",
6
6
  "author": "",