@instructure/ui-truncate-text 8.33.1 → 8.33.2

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/CHANGELOG.md CHANGED
@@ -3,6 +3,10 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ ## [8.33.2](https://github.com/instructure/instructure-ui/compare/v8.33.1...v8.33.2) (2023-01-25)
7
+
8
+ **Note:** Version bump only for package @instructure/ui-truncate-text
9
+
6
10
  ## [8.33.1](https://github.com/instructure/instructure-ui/compare/v8.33.0...v8.33.1) (2023-01-06)
7
11
 
8
12
  **Note:** Version bump only for package @instructure/ui-truncate-text
@@ -1,5 +1,4 @@
1
1
  var _dec, _dec2, _dec3, _class, _class2;
2
-
3
2
  /*
4
3
  * The MIT License (MIT)
5
4
  *
@@ -23,7 +22,6 @@ var _dec, _dec2, _dec3, _class, _class2;
23
22
  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24
23
  * SOFTWARE.
25
24
  */
26
-
27
25
  /** @jsx jsx */
28
26
  import React, { Component } from 'react';
29
27
  import { debounce } from '@instructure/debounce';
@@ -36,7 +34,6 @@ import generateStyle from './styles';
36
34
  import generateComponentTheme from './theme';
37
35
  import truncate from './utils/truncate';
38
36
  import { propTypes, allowedProps } from './props';
39
-
40
37
  /**
41
38
  ---
42
39
  category: components
@@ -52,20 +49,16 @@ let TruncateText = (_dec = withStyle(generateStyle, generateComponentTheme), _de
52
49
  this._stage = null;
53
50
  this._wasTruncated = void 0;
54
51
  this._resizeListener = void 0;
55
-
56
52
  this.update = () => {
57
53
  if (this.ref) {
58
54
  this.setState(this.initialState);
59
55
  }
60
56
  };
61
-
62
57
  this.state = this.initialState;
63
58
  }
64
-
65
59
  get _ref() {
66
60
  return this.ref;
67
61
  }
68
-
69
62
  get initialState() {
70
63
  return {
71
64
  isTruncated: false,
@@ -74,13 +67,11 @@ let TruncateText = (_dec = withStyle(generateStyle, generateComponentTheme), _de
74
67
  truncatedText: void 0
75
68
  };
76
69
  }
77
-
78
70
  componentDidMount() {
79
71
  const _this$props = this.props,
80
- children = _this$props.children,
81
- makeStyles = _this$props.makeStyles;
72
+ children = _this$props.children,
73
+ makeStyles = _this$props.makeStyles;
82
74
  makeStyles === null || makeStyles === void 0 ? void 0 : makeStyles();
83
-
84
75
  if (children) {
85
76
  this.checkChildren();
86
77
  const txt = ensureSingleChild(children);
@@ -90,10 +81,8 @@ let TruncateText = (_dec = withStyle(generateStyle, generateComponentTheme), _de
90
81
  leading: true,
91
82
  trailing: true
92
83
  });
93
-
94
84
  const _getBoundingClientRec = getBoundingClientRect(this.ref),
95
- origWidth = _getBoundingClientRec.width;
96
-
85
+ origWidth = _getBoundingClientRec.width;
97
86
  this._resizeListener = new ResizeObserver(entries => {
98
87
  // requestAnimationFrame call is needed becuase some truncatetext test cases
99
88
  // failed due to ResizeObserver was not able to deliver all observations within a single animation frame
@@ -101,39 +90,33 @@ let TruncateText = (_dec = withStyle(generateStyle, generateComponentTheme), _de
101
90
  requestAnimationFrame(() => {
102
91
  for (const entry of entries) {
103
92
  const width = entry.contentRect.width;
104
-
105
93
  if (origWidth !== width) {
106
94
  this.props.debounce === 0 ? this.update() : this._debounced();
107
95
  }
108
96
  }
109
97
  });
110
98
  });
111
-
112
99
  this._resizeListener.observe(this.ref);
113
100
  }
114
101
  }
115
-
116
102
  componentWillUnmount() {
117
103
  if (this._resizeListener) {
118
104
  this._resizeListener.disconnect();
119
105
  }
120
-
121
106
  if (this._debounced) {
122
107
  this._debounced.cancel();
123
108
  }
124
109
  }
125
-
126
110
  componentDidUpdate(prevProps) {
127
111
  const _this$props2 = this.props,
128
- children = _this$props2.children,
129
- onUpdate = _this$props2.onUpdate,
130
- makeStyles = _this$props2.makeStyles;
112
+ children = _this$props2.children,
113
+ onUpdate = _this$props2.onUpdate,
114
+ makeStyles = _this$props2.makeStyles;
131
115
  makeStyles === null || makeStyles === void 0 ? void 0 : makeStyles();
132
116
  const _this$state = this.state,
133
- isTruncated = _this$state.isTruncated,
134
- needsSecondRender = _this$state.needsSecondRender,
135
- truncatedText = _this$state.truncatedText;
136
-
117
+ isTruncated = _this$state.isTruncated,
118
+ needsSecondRender = _this$state.needsSecondRender,
119
+ truncatedText = _this$state.truncatedText;
137
120
  if (children) {
138
121
  if (prevProps !== this.props) {
139
122
  if (prevProps.children !== this.props.children) {
@@ -141,13 +124,11 @@ let TruncateText = (_dec = withStyle(generateStyle, generateComponentTheme), _de
141
124
  this.checkChildren();
142
125
  const txt = ensureSingleChild(children);
143
126
  this._text = txt ? txt : void 0;
144
- } // require the double render whenever props change
145
-
146
-
127
+ }
128
+ // require the double render whenever props change
147
129
  this.setState(this.initialState);
148
130
  return;
149
131
  }
150
-
151
132
  if (!needsSecondRender && (isTruncated || this._wasTruncated)) {
152
133
  onUpdate === null || onUpdate === void 0 ? void 0 : onUpdate(isTruncated, truncatedText);
153
134
  this._wasTruncated = isTruncated;
@@ -156,7 +137,6 @@ let TruncateText = (_dec = withStyle(generateStyle, generateComponentTheme), _de
156
137
  }
157
138
  }
158
139
  }
159
-
160
140
  checkChildren() {
161
141
  error(!(() => {
162
142
  let isTooDeep = false;
@@ -175,20 +155,17 @@ let TruncateText = (_dec = withStyle(generateStyle, generateComponentTheme), _de
175
155
  return isTooDeep;
176
156
  })(), `[TruncateText] Some children are too deep in the node tree and will not render.`);
177
157
  }
178
-
179
158
  truncate() {
180
159
  if (!this.state.needsSecondRender) {
181
160
  return;
182
161
  }
183
-
184
162
  if (canUseDOM) {
185
163
  var _this$props$styles;
186
-
187
- const result = truncate(this._stage, { ...this.props,
164
+ const result = truncate(this._stage, {
165
+ ...this.props,
188
166
  parent: this.ref ? this.ref : void 0,
189
167
  lineHeight: (_this$props$styles = this.props.styles) === null || _this$props$styles === void 0 ? void 0 : _this$props$styles.lineHeight
190
168
  });
191
-
192
169
  if (result) {
193
170
  const element = this.renderChildren(result.isTruncated, result.data, result.constraints.width);
194
171
  this.setState({
@@ -200,9 +177,8 @@ let TruncateText = (_dec = withStyle(generateStyle, generateComponentTheme), _de
200
177
  }
201
178
  } else {
202
179
  var _this$ref, _this$ref2;
203
-
204
- const textContent = (_this$ref = this.ref) !== null && _this$ref !== void 0 && _this$ref.textContent ? (_this$ref2 = this.ref) === null || _this$ref2 === void 0 ? void 0 : _this$ref2.textContent : void 0; // if dom isn't available, use original children
205
-
180
+ const textContent = (_this$ref = this.ref) !== null && _this$ref !== void 0 && _this$ref.textContent ? (_this$ref2 = this.ref) === null || _this$ref2 === void 0 ? void 0 : _this$ref2.textContent : void 0;
181
+ // if dom isn't available, use original children
206
182
  this.setState({
207
183
  needsSecondRender: false,
208
184
  isTruncated: false,
@@ -211,32 +187,27 @@ let TruncateText = (_dec = withStyle(generateStyle, generateComponentTheme), _de
211
187
  });
212
188
  }
213
189
  }
214
-
215
190
  renderChildren(truncated, data, width) {
216
191
  var _this$props$styles2;
217
-
218
192
  if (!truncated) {
219
193
  return this._text;
220
194
  }
221
-
222
- const childElements = []; // iterate over each node used in the truncated string
223
-
195
+ const childElements = [];
196
+ // iterate over each node used in the truncated string
224
197
  for (let i = 0; i < data.length; i++) {
225
198
  const item = data[i];
226
199
  const element = this._text.props.children[i];
227
200
  const nodeText = item.join('');
228
-
229
201
  if (element && element.props) {
230
202
  // if node is an html element and not just a string
231
203
  childElements.push(safeCloneElement(element, element.props, nodeText));
232
204
  } else {
233
205
  childElements.push(nodeText);
234
206
  }
235
- } // this spacer element is set to the max width the full text could
207
+ }
208
+ // this spacer element is set to the max width the full text could
236
209
  // potentially be without this, text in `width: auto` elements won't expand
237
210
  // to accommodate more text, once truncated
238
-
239
-
240
211
  childElements.push(jsx("span", {
241
212
  css: (_this$props$styles2 = this.props.styles) === null || _this$props$styles2 === void 0 ? void 0 : _this$props$styles2.spacer,
242
213
  style: {
@@ -246,10 +217,8 @@ let TruncateText = (_dec = withStyle(generateStyle, generateComponentTheme), _de
246
217
  const children = React.Children.map(childElements, child => child);
247
218
  return this._text.props ? safeCloneElement(this._text, this._text.props, children) : children;
248
219
  }
249
-
250
220
  render() {
251
221
  var _this$props$styles3;
252
-
253
222
  const truncatedElement = this.state.truncatedElement;
254
223
  const children = this.props.children;
255
224
  return jsx("span", {
@@ -263,7 +232,6 @@ let TruncateText = (_dec = withStyle(generateStyle, generateComponentTheme), _de
263
232
  }
264
233
  }, ensureSingleChild(children))), truncatedElement);
265
234
  }
266
-
267
235
  }, _class2.displayName = "TruncateText", _class2.componentId = 'TruncateText', _class2.allowedProps = allowedProps, _class2.propTypes = propTypes, _class2.defaultProps = {
268
236
  maxLines: 1,
269
237
  ellipsis: '\u2026',
@@ -21,6 +21,7 @@
21
21
  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
22
  * SOFTWARE.
23
23
  */
24
+
24
25
  import PropTypes from 'prop-types';
25
26
  const propTypes = {
26
27
  children: PropTypes.node.isRequired,
@@ -54,5 +54,4 @@ const generateStyle = componentTheme => {
54
54
  lineHeight: componentTheme.lineHeight
55
55
  };
56
56
  };
57
-
58
57
  export default generateStyle;
@@ -33,8 +33,8 @@ const generateComponentTheme = theme => {
33
33
  fontFamily: typography === null || typography === void 0 ? void 0 : typography.fontFamily,
34
34
  lineHeight: typography === null || typography === void 0 ? void 0 : typography.lineHeight
35
35
  };
36
- return { ...componentVariables
36
+ return {
37
+ ...componentVariables
37
38
  };
38
39
  };
39
-
40
40
  export default generateComponentTheme;
@@ -21,8 +21,8 @@
21
21
  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
22
  * SOFTWARE.
23
23
  */
24
- import { cloneArray } from '@instructure/ui-utils';
25
24
 
25
+ import { cloneArray } from '@instructure/ui-utils';
26
26
  /**
27
27
  * ---
28
28
  * parent: TruncateText
@@ -41,91 +41,73 @@ import { cloneArray } from '@instructure/ui-utils';
41
41
  function cleanData(stringData, options) {
42
42
  let repeat = arguments.length > 2 && arguments[2] !== void 0 ? arguments[2] : false;
43
43
  const truncate = options.truncate,
44
- ignore = options.ignore,
45
- ellipsis = options.ellipsis;
44
+ ignore = options.ignore,
45
+ ellipsis = options.ellipsis;
46
46
  let newData = cloneArray(stringData);
47
47
  let ellipsisNode = -1;
48
48
  let ellipsisIndex = -1;
49
-
50
49
  const findEllipsis = () => {
51
50
  for (let i = 0; i < newData.length; i++) {
52
51
  const nodeData = newData[i];
53
-
54
52
  if (nodeData.indexOf(ellipsis) !== -1) {
55
53
  ellipsisNode = i;
56
54
  ellipsisIndex = nodeData.indexOf(ellipsis);
57
55
  }
58
56
  }
59
57
  };
60
-
61
58
  if (truncate === 'character') {
62
59
  findEllipsis();
63
60
  let node = newData[ellipsisNode];
64
-
65
61
  if (node) {
66
62
  const before = node[ellipsisIndex - 1];
67
-
68
63
  if (before && ignore.indexOf(before) !== -1) {
69
64
  // remove character immediately BEFORE the ellipsis in the same node
70
65
  newData[ellipsisNode].splice(ellipsisIndex - 1, 1);
71
66
  }
72
-
73
67
  if (!before) {
74
68
  // character before the ellipsis is part of a different node
75
69
  // find the next node with data and remove last datum
76
70
  let prevNode = null;
77
71
  let prevNodeIndex = ellipsisNode - 1;
78
-
79
72
  while (prevNodeIndex >= 0) {
80
73
  prevNode = newData[prevNodeIndex];
81
-
82
74
  if (prevNode.length > 0) {
83
75
  break;
84
76
  } else {
85
77
  prevNodeIndex--;
86
78
  }
87
79
  }
88
-
89
80
  if (prevNode) {
90
81
  const lastChar = String(prevNode.slice(-1));
91
-
92
82
  if (ignore.indexOf(lastChar) !== -1) {
93
83
  newData[prevNodeIndex].length -= 1;
94
84
  }
95
85
  }
96
86
  }
97
87
  }
98
-
99
88
  findEllipsis();
100
89
  node = newData[ellipsisNode];
101
-
102
90
  if (node) {
103
91
  const after = node[ellipsisIndex + 1];
104
-
105
92
  if (after && ignore.indexOf(after) !== -1) {
106
93
  // remove character immediately AFTER the ellipsis in the same node
107
94
  newData[ellipsisNode].splice(ellipsisIndex + 1, 1);
108
95
  }
109
-
110
96
  if (!after) {
111
97
  // character after the ellipsis is part of a different node
112
98
  // find the next node with data and remove first datum
113
99
  let nextNode = null;
114
100
  let nextNodeIndex = ellipsisNode + 1;
115
-
116
101
  while (nextNodeIndex < newData.length) {
117
102
  nextNode = newData[nextNodeIndex];
118
-
119
103
  if (nextNode.length > 0) {
120
104
  break;
121
105
  } else {
122
106
  nextNodeIndex++;
123
107
  }
124
108
  }
125
-
126
109
  if (nextNode) {
127
110
  const firstChar = String(nextNode[0]);
128
-
129
111
  if (ignore.indexOf(firstChar) !== -1) {
130
112
  newData[nextNodeIndex].shift();
131
113
  }
@@ -135,10 +117,8 @@ function cleanData(stringData, options) {
135
117
  } else {
136
118
  findEllipsis();
137
119
  const node = newData[ellipsisNode];
138
-
139
120
  if (node) {
140
121
  const before = node[ellipsisIndex - 1];
141
-
142
122
  if (before && ignore.indexOf(before.slice(-1)) !== -1) {
143
123
  if (before.length === 1) {
144
124
  // remove entire word datum
@@ -148,26 +128,21 @@ function cleanData(stringData, options) {
148
128
  newData[ellipsisNode][ellipsisIndex - 1] = before.slice(0, -1);
149
129
  }
150
130
  }
151
-
152
131
  if (!before) {
153
132
  // word before the ellipsis is part of a different node
154
133
  // find the next node with data and remove last datum
155
134
  let prevNode = null;
156
135
  let prevNodeIndex = ellipsisNode - 1;
157
-
158
136
  while (prevNodeIndex >= 0) {
159
137
  prevNode = newData[prevNodeIndex];
160
-
161
138
  if (prevNode.length > 0) {
162
139
  break;
163
140
  } else {
164
141
  prevNodeIndex--;
165
142
  }
166
143
  }
167
-
168
144
  if (prevNode) {
169
145
  const lastChar = String(prevNode.slice(-1)).slice(-1);
170
-
171
146
  if (ignore.indexOf(lastChar) !== -1) {
172
147
  const lastItem = prevNode.length - 1;
173
148
  newData[prevNodeIndex][lastItem] = prevNode[lastItem].slice(0, -1);
@@ -176,12 +151,9 @@ function cleanData(stringData, options) {
176
151
  }
177
152
  }
178
153
  }
179
-
180
154
  if (repeat) {
181
155
  newData = cleanData(newData, options, false);
182
156
  }
183
-
184
157
  return newData;
185
158
  }
186
-
187
159
  export default cleanData;
@@ -42,20 +42,15 @@ function cleanString(string, ignore) {
42
42
  let text = string;
43
43
  const firstChar = text.charAt(0);
44
44
  const lastChar = text.slice(-1);
45
-
46
45
  if (start && ignore.indexOf(firstChar) !== -1) {
47
46
  text = text.slice(1);
48
47
  }
49
-
50
48
  if (end && ignore.indexOf(lastChar) !== -1) {
51
49
  text = text.slice(0, -1);
52
50
  }
53
-
54
51
  if (repeat) {
55
52
  text = cleanString(text, ignore, start, end, false);
56
53
  }
57
-
58
54
  return text;
59
55
  }
60
-
61
56
  export default cleanString;
@@ -21,7 +21,9 @@
21
21
  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
22
  * SOFTWARE.
23
23
  */
24
+
24
25
  import { getComputedStyle } from '@instructure/ui-dom-utils';
26
+
25
27
  /**
26
28
  * ---
27
29
  * parent: TruncateText
@@ -32,36 +34,29 @@ import { getComputedStyle } from '@instructure/ui-dom-utils';
32
34
  * @param {DOMNode[]} nodes Array of DOM nodes.
33
35
  * @param {DOMNode} parentNode The node to inherit default styles from.
34
36
  */
35
-
36
37
  function measureText(nodes, parentNode) {
37
38
  let width = 0;
38
-
39
39
  for (let i = 0; i < nodes.length; i++) {
40
40
  const node = nodes[i];
41
41
  width += measure(node.textContent, node.nodeType === 1 ? node : parentNode);
42
42
  }
43
-
44
43
  return width;
45
44
  }
46
-
47
45
  function measure(string, domNode) {
48
- const style = getComputedStyle(domNode); // we use a canvas in a doc fragment to prevent having to render the string full width in the DOM
49
-
46
+ const style = getComputedStyle(domNode);
47
+ // we use a canvas in a doc fragment to prevent having to render the string full width in the DOM
50
48
  const canvas = document.createElement('canvas');
51
49
  document.createDocumentFragment().appendChild(canvas);
52
50
  const context = canvas.getContext('2d');
53
-
54
51
  if (!context || !string) {
55
52
  return 0;
56
53
  }
57
-
58
54
  let text = string;
59
55
  let letterOffset = 0;
60
- let width = 0; // grab individual font styles
56
+ let width = 0;
57
+ // grab individual font styles
61
58
  // some browsers don't report a value for style['font']
62
-
63
59
  context.font = [style.fontWeight, style.fontStyle, style.fontSize, style.fontFamily].join(' ');
64
-
65
60
  if (style.textTransform === 'uppercase') {
66
61
  text = string.toUpperCase();
67
62
  } else if (style.textTransform === 'lowercase') {
@@ -69,14 +64,11 @@ function measure(string, domNode) {
69
64
  } else if (style.textTransform === 'capitalize') {
70
65
  text = string.replace(/\b\w/g, str => str.toUpperCase());
71
66
  }
72
-
73
67
  if (style.letterSpacing !== 'normal') {
74
68
  letterOffset = text.length * parseInt(style.letterSpacing);
75
69
  }
76
-
77
- width = context.measureText(text).width + letterOffset; // returns the max potential width of the text, assuming the text was on a single line
78
-
70
+ width = context.measureText(text).width + letterOffset;
71
+ // returns the max potential width of the text, assuming the text was on a single line
79
72
  return width;
80
73
  }
81
-
82
74
  export default measureText;