@indico-data/design-system 3.6.1 → 3.6.3

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@indico-data/design-system",
3
- "version": "3.6.1",
3
+ "version": "3.6.3",
4
4
  "description": "",
5
5
  "author": "",
6
6
  "main": "lib/index.js",
@@ -16,6 +16,24 @@ const meta: Meta = {
16
16
  },
17
17
  },
18
18
  },
19
+ width: {
20
+ control: 'text',
21
+ table: {
22
+ category: 'Props',
23
+ type: {
24
+ summary: 'string',
25
+ },
26
+ },
27
+ },
28
+ maxWidth: {
29
+ control: 'text',
30
+ table: {
31
+ category: 'Props',
32
+ type: {
33
+ summary: 'string',
34
+ },
35
+ },
36
+ },
19
37
  place: {
20
38
  control: 'select',
21
39
  options: ['top', 'top-start', 'top-end', 'right', 'right-start', 'right-end', 'bottom'],
@@ -53,12 +71,13 @@ const meta: Meta = {
53
71
  },
54
72
  },
55
73
  },
56
- zIndex: {
57
- control: 'number',
74
+ positionStrategy: {
75
+ control: 'select',
76
+ options: ['absolute', 'fixed'],
58
77
  table: {
59
78
  category: 'Props',
60
79
  type: {
61
- summary: 'number',
80
+ summary: 'absolute | fixed',
62
81
  },
63
82
  },
64
83
  },
@@ -80,12 +99,7 @@ type Story = StoryObj<typeof Tooltip>;
80
99
 
81
100
  export const Default: Story = {
82
101
  args: {
83
- place: 'bottom',
84
102
  id: 'tooltip-1',
85
- clickToShow: false,
86
- delayShow: 0,
87
- delayHide: 0,
88
- zIndex: 1000,
89
103
  },
90
104
 
91
105
  render: (args) => {
@@ -103,3 +117,57 @@ export const Default: Story = {
103
117
  );
104
118
  },
105
119
  };
120
+
121
+ export const TooltipWithWidth: Story = {
122
+ args: {
123
+ id: 'tooltip-1',
124
+ width: '100%',
125
+ },
126
+
127
+ render: (args) => {
128
+ return (
129
+ <Container>
130
+ <Row>
131
+ <Col xs={12}>
132
+ <Button ariaLabel="Tooltip Button" data-tooltip-id="tooltip-1">
133
+ Tooltip!
134
+ </Button>
135
+ <Tooltip {...args} place="bottom-start">
136
+ Lorem ipsum dolor sit amet consectetur adipisicing elit. Quisquam, quos. Lorem ipsum
137
+ dolor sit amet consectetur adipisicing elit. Quisquam, quos. Lorem ipsum dolor sit
138
+ amet consectetur adipisicing elit. Quisquam, quos. Lorem ipsum dolor sit amet
139
+ consectetur adipisicing elit. Quisquam, quos.
140
+ </Tooltip>
141
+ </Col>
142
+ </Row>
143
+ </Container>
144
+ );
145
+ },
146
+ };
147
+
148
+ export const TooltipWithMaxWidth: Story = {
149
+ args: {
150
+ id: 'tooltip-1',
151
+ maxWidth: '200px',
152
+ },
153
+
154
+ render: (args) => {
155
+ return (
156
+ <Container>
157
+ <Row>
158
+ <Col xs={12}>
159
+ <Button ariaLabel="Tooltip Button" data-tooltip-id="tooltip-1">
160
+ Tooltip!
161
+ </Button>
162
+ <Tooltip {...args} place="bottom-start">
163
+ Lorem ipsum dolor sit amet consectetur adipisicing elit. Quisquam, quos. Lorem ipsum
164
+ dolor sit amet consectetur adipisicing elit. Quisquam, quos. Lorem ipsum dolor sit
165
+ amet consectetur adipisicing elit. Quisquam, quos. Lorem ipsum dolor sit amet
166
+ consectetur adipisicing elit. Quisquam, quos.
167
+ </Tooltip>
168
+ </Col>
169
+ </Row>
170
+ </Container>
171
+ );
172
+ },
173
+ };
@@ -1,6 +1,7 @@
1
- import { PlacesType, Tooltip as ReactTooltip } from 'react-tooltip';
1
+ import { CSSProperties } from 'react';
2
+ import { PlacesType, Tooltip as ReactTooltip, PositionStrategy } from 'react-tooltip';
2
3
 
3
- interface TooltipProps {
4
+ export interface TooltipProps {
4
5
  id: string;
5
6
  /** Whether the tooltip should be shown on click */
6
7
  clickToShow?: boolean;
@@ -8,12 +9,16 @@ interface TooltipProps {
8
9
  delayShow?: number;
9
10
  /** The delay in milliseconds before the tooltip is hidden */
10
11
  delayHide?: number;
11
- children: React.ReactNode;
12
- /** This is an override for the z-index of the tooltip */
13
- zIndex?: number;
14
12
  /** The placement of the tooltip */
15
13
  place?: PlacesType;
14
+ /** The width of the tooltip */
15
+ width?: CSSProperties['width'];
16
+ /** The max width of the tooltip */
17
+ maxWidth?: CSSProperties['maxWidth'];
18
+ /** The position strategy of the tooltip */
19
+ positionStrategy?: PositionStrategy;
16
20
  /** The content of the tooltip */
21
+ children: React.ReactNode;
17
22
  [key: string]: any;
18
23
  }
19
24
 
@@ -23,8 +28,11 @@ export const Tooltip = ({
23
28
  delayShow,
24
29
  delayHide,
25
30
  children,
26
- zIndex = 1000,
27
31
  place = 'top',
32
+ width = 'max-content',
33
+ maxWidth,
34
+ opacity = 1,
35
+ positionStrategy = 'absolute',
28
36
  ...rest
29
37
  }: TooltipProps) => {
30
38
  return (
@@ -32,13 +40,21 @@ export const Tooltip = ({
32
40
  style={{
33
41
  backgroundColor: 'var(--pf-semantic-background-inverted)',
34
42
  color: 'var(--pf-semantic-font-inverted)',
35
- zIndex,
43
+ width,
44
+ maxWidth,
45
+ boxSizing: 'border-box',
46
+ textWrap: 'wrap',
47
+ wordWrap: 'break-word',
48
+ zIndex: 1000,
36
49
  }}
50
+ className="tooltip"
37
51
  id={id}
38
52
  place={place}
39
53
  openOnClick={clickToShow}
40
54
  delayShow={delayShow}
41
55
  delayHide={delayHide}
56
+ opacity={opacity}
57
+ positionStrategy={positionStrategy}
42
58
  {...rest}
43
59
  >
44
60
  {children}
@@ -13,22 +13,30 @@ The truncate component accepts a string prop and will truncate the string to fit
13
13
 
14
14
  <Controls of={Truncate.Default} />
15
15
 
16
-
17
16
  ## Usage
17
+
18
18
  Simply pass in a string to the `truncateString` prop.
19
19
 
20
+ ## No Truncate
21
+
22
+ If the string is shorter than the available space, it will not be truncated.
23
+
24
+ <Canvas of={Truncate.NoTruncate} />
20
25
 
21
- ### With Line Clamp
26
+ ### With Num Lines
22
27
 
23
- If you want to truncate the text to a specific number of lines, set the `lineClamp` prop to the number of lines you want to truncate to.
28
+ If you want to truncate the text to a specific number of lines, set the `numLines` prop to the number of lines you want to truncate to.
24
29
 
25
- <Canvas of={Truncate.WithLineClamp} />
30
+ <Canvas of={Truncate.WithNumLines} />
31
+
32
+ ### With Tooltip Options
33
+
34
+ If you want to customize the tooltip, set the `tooltipOptions` prop to the options you want to use.
35
+
36
+ <Canvas of={Truncate.WithTooltipOptions} />
26
37
 
27
38
  ### No Tooltip
28
39
 
29
- If you want to disable the tooltip, set the `hasTooltip` prop to `false`.
40
+ If you want to disable the tooltip, set the `tooltipOptions` prop to `{ disabled: true }`.
30
41
 
31
42
  <Canvas of={Truncate.NoTooltip} />
32
-
33
- ### Notes on Tooltips
34
- If a duplicate ID is provided, the tooltip will only show on the first instance of the ID.
@@ -7,7 +7,7 @@ const meta: Meta<typeof Truncate> = {
7
7
  component: Truncate,
8
8
  decorators: [
9
9
  (Story) => (
10
- <div style={{ width: '300px' }}>
10
+ <div style={{ width: '300px', border: '1px solid black', padding: '10px' }}>
11
11
  <Story />
12
12
  </div>
13
13
  ),
@@ -20,22 +20,15 @@ const meta: Meta<typeof Truncate> = {
20
20
  category: 'Props',
21
21
  },
22
22
  },
23
- lineClamp: {
23
+ numLines: {
24
24
  control: 'number',
25
- defaultValue: 0,
25
+ defaultValue: 1,
26
26
  table: {
27
27
  category: 'Props',
28
28
  },
29
29
  },
30
- tooltipId: {
31
- control: 'text',
32
- table: {
33
- category: 'Props',
34
- },
35
- },
36
- hasTooltip: {
37
- control: 'boolean',
38
- defaultValue: true,
30
+ tooltipOptions: {
31
+ control: 'object',
39
32
  table: {
40
33
  category: 'Props',
41
34
  },
@@ -49,19 +42,35 @@ type Story = StoryObj<TruncateProps>;
49
42
 
50
43
  export const Default: Story = {
51
44
  args: {
52
- lineClamp: 0,
53
- hasTooltip: true,
54
- tooltipId: 'truncate-tooltip',
45
+ numLines: 1,
46
+ truncateString: 'Lorem ipsum dolor sit amet consectetur adipisicing elit. Quisquam, quos.',
47
+ },
48
+ render: (args) => <Truncate {...args} />,
49
+ };
50
+
51
+ export const NoTruncate: Story = {
52
+ args: {
53
+ numLines: 1,
54
+ truncateString: 'No truncate',
55
+ },
56
+ render: (args) => <Truncate {...args} />,
57
+ };
58
+
59
+ export const WithNumLines: Story = {
60
+ args: {
61
+ numLines: 2,
55
62
  truncateString: 'Lorem ipsum dolor sit amet consectetur adipisicing elit. Quisquam, quos.',
56
63
  },
57
64
  render: (args) => <Truncate {...args} />,
58
65
  };
59
66
 
60
- export const WithLineClamp: Story = {
67
+ export const WithTooltipOptions: Story = {
61
68
  args: {
62
- lineClamp: 2,
63
- hasTooltip: true,
64
- tooltipId: 'truncate-tooltip-line-clamp',
69
+ numLines: 1,
70
+ tooltipOptions: {
71
+ place: 'right',
72
+ width: '150px',
73
+ },
65
74
  truncateString: 'Lorem ipsum dolor sit amet consectetur adipisicing elit. Quisquam, quos.',
66
75
  },
67
76
  render: (args) => <Truncate {...args} />,
@@ -69,10 +78,23 @@ export const WithLineClamp: Story = {
69
78
 
70
79
  export const NoTooltip: Story = {
71
80
  args: {
72
- lineClamp: 2,
73
- hasTooltip: false,
74
- tooltipId: 'truncate-tooltip-no-tooltip',
81
+ numLines: 1,
82
+ tooltipOptions: {
83
+ disabled: true,
84
+ },
75
85
  truncateString: 'Lorem ipsum dolor sit amet consectetur adipisicing elit. Quisquam, quos.',
76
86
  },
77
87
  render: (args) => <Truncate {...args} />,
78
88
  };
89
+
90
+ export const TruncateWithTooltipWidth: Story = {
91
+ args: {
92
+ numLines: 1,
93
+ tooltipOptions: {
94
+ width: 'calc(100% - 40px)',
95
+ },
96
+ truncateString:
97
+ 'Lorem ipsum dolor sit amet consectetur adipisicing elit. Quisquam, quos. Lorem ipsum dolor sit amet consectetur adipisicing elit. Quisquam, quos. Lorem ipsum dolor sit amet consectetur adipisicing elit. Quisquam, quos. Lorem ipsum dolor sit amet consectetur adipisicing elit. Quisquam, quos.',
98
+ },
99
+ render: (args) => <Truncate {...args} />,
100
+ };
@@ -1,51 +1,56 @@
1
- import { useState, useEffect, CSSProperties } from 'react';
1
+ import { useState, useEffect, CSSProperties, useMemo, useRef } from 'react';
2
2
  import { Tooltip } from '../tooltip';
3
3
  import { TruncateProps } from './types';
4
4
  import { v4 as uuidv4 } from 'uuid';
5
+ import classNames from 'classnames';
6
+
5
7
  export const Truncate = ({
6
- lineClamp = 0,
8
+ numLines = 1,
7
9
  truncateString,
8
- hasTooltip = true,
9
- tooltipId,
10
+ tooltipOptions = {},
10
11
  ...rest
11
12
  }: TruncateProps) => {
12
13
  const [isTruncated, setIsTruncated] = useState(false);
13
- const id = (tooltipId ?? uuidv4()).replace(/[^a-zA-Z0-9-_]/g, '_');
14
+ const id = useMemo(() => uuidv4().replace(/[^a-zA-Z0-9-_]/g, '_'), []);
15
+ const ref = useRef<HTMLSpanElement>(null);
14
16
 
15
17
  useEffect(() => {
16
18
  const checkTruncation = () => {
17
- const element = document.querySelector(`[data-tooltip-id="${id}"]`);
18
- if (element) {
19
- if (lineClamp === 0) {
20
- setIsTruncated(element.scrollWidth > element.clientWidth);
21
- } else {
22
- setIsTruncated(element.scrollHeight > element.clientHeight);
23
- }
19
+ const element = ref.current;
20
+ if (!element) return;
21
+
22
+ if (numLines === 1) {
23
+ setIsTruncated(element.scrollWidth > element.clientWidth);
24
+ } else {
25
+ setIsTruncated(element.scrollHeight > element.clientHeight);
24
26
  }
25
27
  };
26
28
 
27
29
  checkTruncation();
28
30
  window.addEventListener('resize', checkTruncation);
29
31
  return () => window.removeEventListener('resize', checkTruncation);
30
- }, [id, lineClamp]);
32
+ }, [id, numLines]);
31
33
 
32
34
  const truncateStyle = {
33
- '--line-clamp': lineClamp,
35
+ '--line-clamp': numLines,
34
36
  } as CSSProperties;
35
37
 
36
38
  return (
37
39
  <div className="truncate-wrapper" style={truncateStyle}>
38
40
  <span
41
+ ref={ref}
39
42
  data-testid={`truncate-${id}-${isTruncated ? 'truncated' : 'not-truncated'}`}
40
43
  data-tooltip-id={id}
41
- data-tooltip-content={isTruncated ? truncateString : undefined}
42
- className={lineClamp > 0 ? 'truncate-clip' : 'truncate'}
44
+ className={classNames('truncate', {
45
+ 'truncate--multi-line': numLines > 1,
46
+ 'truncate--single-line': numLines === 1,
47
+ })}
43
48
  {...rest}
44
49
  >
45
50
  {truncateString}
46
51
  </span>
47
- {isTruncated && truncateString && hasTooltip && (
48
- <Tooltip data-tooltip-delay-hide={0} id={id}>
52
+ {isTruncated && truncateString && !tooltipOptions.disabled && (
53
+ <Tooltip {...tooltipOptions} id={id}>
49
54
  {truncateString}
50
55
  </Tooltip>
51
56
  )}
@@ -29,12 +29,6 @@ describe('Truncate', () => {
29
29
 
30
30
  // Now we can use exact IDs instead of regex
31
31
  expect(screen.getByTestId('truncate-test-id-truncated')).toBeInTheDocument();
32
-
33
- // Verify tooltip appears when truncated
34
- expect(screen.getByTestId('truncate-test-id-truncated')).toHaveAttribute(
35
- 'data-tooltip-content',
36
- 'This is a very long text that should be truncated',
37
- );
38
32
  });
39
33
 
40
34
  it('shows non-truncated state when content fits', () => {
@@ -52,10 +46,5 @@ describe('Truncate', () => {
52
46
 
53
47
  // Now we can use exact IDs
54
48
  expect(screen.getByTestId('truncate-test-id-not-truncated')).toBeInTheDocument();
55
-
56
- // Verify no tooltip when not truncated
57
- expect(screen.getByTestId('truncate-test-id-not-truncated')).not.toHaveAttribute(
58
- 'data-tooltip-content',
59
- );
60
49
  });
61
50
  });
@@ -7,20 +7,20 @@
7
7
  }
8
8
 
9
9
  .truncate {
10
- white-space: nowrap;
11
- overflow: hidden;
12
- text-overflow: ellipsis;
13
10
  width: 100%;
14
- display: inline-block;
15
- }
16
-
17
- .truncate-clip {
18
- display: -webkit-box;
19
- -webkit-box-orient: vertical;
20
- -webkit-line-clamp: var(--line-clamp);
21
- line-clamp: var(--line-clamp);
22
11
  overflow: hidden;
23
12
  text-overflow: ellipsis;
24
- width: 100%;
13
+
14
+ &--multi-line {
15
+ display: -webkit-box;
16
+ -webkit-box-orient: vertical;
17
+ -webkit-line-clamp: var(--line-clamp);
18
+ line-clamp: var(--line-clamp);
19
+ }
20
+
21
+ &--single-line {
22
+ display: inline-block;
23
+ white-space: nowrap;
24
+ }
25
25
  }
26
26
  }
@@ -1,11 +1,11 @@
1
+ import { TooltipProps } from '../tooltip/Tooltip';
2
+
1
3
  export interface TruncateProps {
2
4
  /** The number of lines to truncate the text to. If left blank, it will default to 1 line. */
3
- lineClamp?: number;
5
+ numLines?: number;
4
6
  /** The string to truncate. This value will also be displayed in the tooltip when the text is truncated. */
5
7
  truncateString: string;
6
- /** Whether to show the tooltip. If left blank, it will default to true. If set to false, the tooltip will not be shown. */
7
- hasTooltip?: boolean;
8
- /** The id of the tooltip. If an ID is not provided, it will generate one from uuid */
9
- tooltipId?: string;
8
+ /** The options for the tooltip. If `disabled` is `true`, the tooltip will not be shown. If left blank, the tooltip will be shown by default. This is particularly useful if you want to set the width of the tooltip to something other than the default `max-content`. */
9
+ tooltipOptions?: Partial<TooltipProps> & { disabled?: boolean };
10
10
  [key: string]: any;
11
11
  }
@@ -73,12 +73,3 @@ a,
73
73
  .theme {
74
74
  background-color: var(--pf-semantic-background-primary);
75
75
  }
76
-
77
- // Tooltip
78
- .react-tooltip {
79
- z-index: 5;
80
- background-color: var(--pf-semantic-background-inverted);
81
- color: var(--pf-semantic-font-inverted);
82
- opacity: 1 !important;
83
- text-wrap: wrap;
84
- }