@itwin/itwinui-react 1.23.2 → 1.26.1

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.
Files changed (80) hide show
  1. package/CHANGELOG.md +35 -0
  2. package/cjs/core/Buttons/Button/Button.d.ts +1 -1
  3. package/cjs/core/ColorPicker/ColorBuilder.js +40 -15
  4. package/cjs/core/ColorPicker/ColorInputPanel.js +125 -46
  5. package/cjs/core/ColorPicker/ColorPicker.d.ts +5 -0
  6. package/cjs/core/ColorPicker/ColorPicker.js +7 -6
  7. package/cjs/core/ColorPicker/ColorPickerContext.d.ts +4 -2
  8. package/cjs/core/ColorPicker/ColorSwatch.d.ts +1 -1
  9. package/cjs/core/ColorPicker/ColorSwatch.js +10 -4
  10. package/cjs/core/DatePicker/DatePicker.d.ts +1 -1
  11. package/cjs/core/InformationPanel/InformationPanel.d.ts +4 -1
  12. package/cjs/core/InformationPanel/InformationPanel.js +4 -1
  13. package/cjs/core/InformationPanel/InformationPanelContent.d.ts +42 -0
  14. package/cjs/core/InformationPanel/InformationPanelContent.js +66 -0
  15. package/cjs/core/InformationPanel/index.d.ts +2 -0
  16. package/cjs/core/InformationPanel/index.js +3 -1
  17. package/cjs/core/Label/Label.d.ts +31 -0
  18. package/cjs/core/Label/Label.js +53 -0
  19. package/cjs/core/Label/index.d.ts +4 -0
  20. package/cjs/core/Label/index.js +10 -0
  21. package/cjs/core/LabeledInput/LabeledInput.d.ts +2 -2
  22. package/cjs/core/LabeledTextarea/LabeledTextarea.d.ts +1 -1
  23. package/cjs/core/Menu/MenuItem.d.ts +1 -1
  24. package/cjs/core/Table/TablePaginator.d.ts +1 -1
  25. package/cjs/core/Table/TablePaginator.js +9 -4
  26. package/cjs/core/Tabs/Tabs.js +23 -29
  27. package/cjs/core/index.d.ts +6 -4
  28. package/cjs/core/index.js +6 -2
  29. package/cjs/core/utils/color/ColorValue.d.ts +1 -0
  30. package/cjs/core/utils/color/ColorValue.js +101 -85
  31. package/cjs/core/utils/components/MiddleTextTruncation.d.ts +21 -0
  32. package/cjs/core/utils/components/MiddleTextTruncation.js +56 -0
  33. package/cjs/core/utils/components/index.d.ts +1 -0
  34. package/cjs/core/utils/components/index.js +1 -0
  35. package/cjs/core/utils/hooks/index.d.ts +1 -0
  36. package/cjs/core/utils/hooks/index.js +1 -0
  37. package/cjs/core/utils/hooks/useContainerWidth.d.ts +17 -0
  38. package/cjs/core/utils/hooks/useContainerWidth.js +50 -0
  39. package/cjs/core/utils/hooks/useOverflow.d.ts +1 -1
  40. package/cjs/core/utils/hooks/useOverflow.js +30 -17
  41. package/esm/core/Buttons/Button/Button.d.ts +1 -1
  42. package/esm/core/ColorPicker/ColorBuilder.js +40 -15
  43. package/esm/core/ColorPicker/ColorInputPanel.js +125 -46
  44. package/esm/core/ColorPicker/ColorPicker.d.ts +5 -0
  45. package/esm/core/ColorPicker/ColorPicker.js +7 -6
  46. package/esm/core/ColorPicker/ColorPickerContext.d.ts +4 -2
  47. package/esm/core/ColorPicker/ColorSwatch.d.ts +1 -1
  48. package/esm/core/ColorPicker/ColorSwatch.js +10 -4
  49. package/esm/core/DatePicker/DatePicker.d.ts +1 -1
  50. package/esm/core/InformationPanel/InformationPanel.d.ts +4 -1
  51. package/esm/core/InformationPanel/InformationPanel.js +4 -1
  52. package/esm/core/InformationPanel/InformationPanelContent.d.ts +42 -0
  53. package/esm/core/InformationPanel/InformationPanelContent.js +59 -0
  54. package/esm/core/InformationPanel/index.d.ts +2 -0
  55. package/esm/core/InformationPanel/index.js +1 -0
  56. package/esm/core/Label/Label.d.ts +31 -0
  57. package/esm/core/Label/Label.js +46 -0
  58. package/esm/core/Label/index.d.ts +4 -0
  59. package/esm/core/Label/index.js +6 -0
  60. package/esm/core/LabeledInput/LabeledInput.d.ts +2 -2
  61. package/esm/core/LabeledTextarea/LabeledTextarea.d.ts +1 -1
  62. package/esm/core/Menu/MenuItem.d.ts +1 -1
  63. package/esm/core/Table/TablePaginator.d.ts +1 -1
  64. package/esm/core/Table/TablePaginator.js +9 -4
  65. package/esm/core/Tabs/Tabs.js +24 -30
  66. package/esm/core/index.d.ts +6 -4
  67. package/esm/core/index.js +3 -2
  68. package/esm/core/utils/color/ColorValue.d.ts +1 -0
  69. package/esm/core/utils/color/ColorValue.js +101 -85
  70. package/esm/core/utils/components/MiddleTextTruncation.d.ts +21 -0
  71. package/esm/core/utils/components/MiddleTextTruncation.js +49 -0
  72. package/esm/core/utils/components/index.d.ts +1 -0
  73. package/esm/core/utils/components/index.js +1 -0
  74. package/esm/core/utils/hooks/index.d.ts +1 -0
  75. package/esm/core/utils/hooks/index.js +1 -0
  76. package/esm/core/utils/hooks/useContainerWidth.d.ts +17 -0
  77. package/esm/core/utils/hooks/useContainerWidth.js +43 -0
  78. package/esm/core/utils/hooks/useOverflow.d.ts +1 -1
  79. package/esm/core/utils/hooks/useOverflow.js +30 -17
  80. package/package.json +2 -2
@@ -121,19 +121,20 @@ var ColorValue = /** @class */ (function () {
121
121
  * This allows component builders to know if they received bad input from user.
122
122
  */
123
123
  ColorValue.fromString = function (val, defaultColorIfNotParsed) {
124
- return this.fromTbgr(this.computeTbgrFromString(val, defaultColorIfNotParsed === null || defaultColorIfNotParsed === void 0 ? void 0 : defaultColorIfNotParsed.toTbgr()));
124
+ var _a = this.computeTbgrFromString(val, defaultColorIfNotParsed === null || defaultColorIfNotParsed === void 0 ? void 0 : defaultColorIfNotParsed.toTbgr()), tbgr = _a[0], hue = _a[1];
125
+ return new ColorValue(tbgr, hue);
125
126
  };
126
127
  /** Create a ColorValue from hue, saturation, lightness values. */
127
128
  ColorValue.fromHSL = function (hsl) {
128
129
  var _a;
129
130
  var alpha = (_a = hsl.a) !== null && _a !== void 0 ? _a : 1;
130
- return new ColorValue(this.computeTbgrFromHSL(hsl.h / 360, hsl.s / 100, hsl.l / 100, (1 - alpha) * 255), hsl.h);
131
+ return new ColorValue(this.computeTbgrFromHSL(hsl.h / 360, hsl.s / 100, hsl.l / 100, Math.round((1 - alpha) * 255)), hsl.h);
131
132
  };
132
133
  /** Create a ColorValue from an RgbColor */
133
134
  ColorValue.fromRGB = function (rgb) {
134
135
  var _a;
135
136
  var alpha = (_a = rgb.a) !== null && _a !== void 0 ? _a : 1;
136
- return ColorValue.fromRgbt(rgb.r, rgb.g, rgb.b, (1 - alpha) * 255);
137
+ return ColorValue.fromRgbt(rgb.r, rgb.g, rgb.b, Math.round((1 - alpha) * 255));
137
138
  };
138
139
  /**
139
140
  * Create a ColorValue from an HsvColor
@@ -141,7 +142,7 @@ var ColorValue = /** @class */ (function () {
141
142
  ColorValue.fromHSV = function (hsv) {
142
143
  var _a;
143
144
  var alpha = (_a = hsv.a) !== null && _a !== void 0 ? _a : 1;
144
- var transparency = (1 - alpha) * 255;
145
+ var transparency = Math.round((1 - alpha) * 255);
145
146
  // Check for simple case first.
146
147
  if (!hsv.s || hsv.h === -1) {
147
148
  // hue must be undefined, have no color only white
@@ -226,7 +227,12 @@ var ColorValue = /** @class */ (function () {
226
227
  color = /^(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*(?:,\s*(\d*\.?\d+)\s*)?$/.exec(components);
227
228
  if (color) {
228
229
  // rgb(255,0,0) rgba(255,0,0,0.5)
229
- return this.computeTbgrFromComponents(intOrPercent(color[1]), intOrPercent(color[2]), intOrPercent(color[3]), typeof color[4] === 'string' ? 255 - floatOrPercent(color[4]) : 0);
230
+ return [
231
+ this.computeTbgrFromComponents(intOrPercent(color[1]), intOrPercent(color[2]), intOrPercent(color[3]), typeof color[4] === 'string'
232
+ ? 255 - floatOrPercent(color[4])
233
+ : 0),
234
+ undefined,
235
+ ];
230
236
  }
231
237
  break;
232
238
  case 'hsl':
@@ -234,11 +240,11 @@ var ColorValue = /** @class */ (function () {
234
240
  color = /^(\d*\.?\d+)\s*,\s*(\d+)\%\s*,\s*(\d+)\%\s*(?:,\s*(\d*\.?\d+)\s*)?$/.exec(components);
235
241
  if (color) {
236
242
  // hsl(120,50%,50%) hsla(120,50%,50%,0.5)
237
- var h = parseFloat(color[1]) / 360;
243
+ var h = parseFloat(color[1]);
238
244
  var s = parseInt(color[2], 10) / 100;
239
245
  var l = parseInt(color[3], 10) / 100;
240
246
  var t = typeof color[4] === 'string' ? 255 - floatOrPercent(color[4]) : 0;
241
- return this.computeTbgrFromHSL(h, s, l, t);
247
+ return [this.computeTbgrFromHSL(h / 360, s, l, t), h];
242
248
  }
243
249
  break;
244
250
  }
@@ -250,19 +256,28 @@ var ColorValue = /** @class */ (function () {
250
256
  var size = hex.length;
251
257
  if (size === 3) {
252
258
  // #ff0
253
- return this.computeTbgrFromComponents(parseInt(hex.charAt(0) + hex.charAt(0), 16), parseInt(hex.charAt(1) + hex.charAt(1), 16), parseInt(hex.charAt(2) + hex.charAt(2), 16), 0);
259
+ return [
260
+ this.computeTbgrFromComponents(parseInt(hex.charAt(0) + hex.charAt(0), 16), parseInt(hex.charAt(1) + hex.charAt(1), 16), parseInt(hex.charAt(2) + hex.charAt(2), 16), 0),
261
+ undefined,
262
+ ];
254
263
  }
255
264
  if (size === 6) {
256
265
  // #ff0000
257
- return this.computeTbgrFromComponents(parseInt(hex.charAt(0) + hex.charAt(1), 16), parseInt(hex.charAt(2) + hex.charAt(3), 16), parseInt(hex.charAt(4) + hex.charAt(5), 16), 0);
266
+ return [
267
+ this.computeTbgrFromComponents(parseInt(hex.charAt(0) + hex.charAt(1), 16), parseInt(hex.charAt(2) + hex.charAt(3), 16), parseInt(hex.charAt(4) + hex.charAt(5), 16), 0),
268
+ undefined,
269
+ ];
258
270
  }
259
271
  if (size === 8) {
260
272
  // #ff0000ff
261
- return this.computeTbgrFromComponents(parseInt(hex.charAt(0) + hex.charAt(1), 16), parseInt(hex.charAt(2) + hex.charAt(3), 16), parseInt(hex.charAt(4) + hex.charAt(5), 16), 255 - parseInt(hex.charAt(6) + hex.charAt(7), 16));
273
+ return [
274
+ this.computeTbgrFromComponents(parseInt(hex.charAt(0) + hex.charAt(1), 16), parseInt(hex.charAt(2) + hex.charAt(3), 16), parseInt(hex.charAt(4) + hex.charAt(5), 16), 255 - parseInt(hex.charAt(6) + hex.charAt(7), 16)),
275
+ undefined,
276
+ ];
262
277
  }
263
278
  }
264
279
  if (defaultColorIfNotParsed) {
265
- return defaultColorIfNotParsed;
280
+ return [defaultColorIfNotParsed, undefined];
266
281
  }
267
282
  throw new Error('unable to parse string into ColorValue');
268
283
  };
@@ -309,7 +324,11 @@ var ColorValue = /** @class */ (function () {
309
324
  */
310
325
  ColorValue.prototype.toHexString = function (includeAlpha) {
311
326
  if (includeAlpha) {
312
- return "#" + this.getRgb(includeAlpha).toString(16);
327
+ var value = this.getRgb(includeAlpha);
328
+ if (value < 0) {
329
+ value = 0xffffffff + value + 1;
330
+ }
331
+ return "#" + ("00000000" + value.toString(16)).slice(-8);
313
332
  }
314
333
  return "#" + ("000000" + this.getRgb().toString(16)).slice(-6);
315
334
  };
@@ -366,40 +385,40 @@ var ColorValue = /** @class */ (function () {
366
385
  };
367
386
  /** Create an HslColor from this ColorValue */
368
387
  ColorValue.toHsl = function (tbgr) {
369
- // internally h,s,l ranges are in 0.0 - 1.0
370
- var col = ColorValue.getColors(tbgr);
371
- col.r /= 255;
372
- col.g /= 255;
373
- col.b /= 255;
374
- var max = Math.max(col.r, col.g, col.b);
375
- var min = Math.min(col.r, col.g, col.b);
388
+ var _a = ColorValue.getColors(tbgr), r = _a.r, g = _a.g, b = _a.b;
389
+ var red = r / 255;
390
+ var green = g / 255;
391
+ var blue = b / 255;
392
+ var cMin = Math.min(red, green, blue);
393
+ var cMax = Math.max(red, green, blue);
394
+ var delta = cMax - cMin;
376
395
  var hue = 0;
377
- var saturation;
378
- var lightness = (min + max) / 2.0;
379
- if (min === max) {
380
- saturation = 0;
396
+ var saturation = 0;
397
+ if (0 === delta) {
398
+ hue = 0;
399
+ }
400
+ else if (red === cMax) {
401
+ hue = ((green - blue) / delta) % 6;
402
+ }
403
+ else if (green === cMax) {
404
+ hue = (blue - red) / delta + 2;
381
405
  }
382
406
  else {
383
- var delta = max - min;
384
- saturation =
385
- lightness <= 0.5 ? delta / (max + min) : delta / (2 - max - min);
386
- switch (max) {
387
- case col.r:
388
- hue = (col.g - col.b) / delta + (col.g < col.b ? 6 : 0);
389
- break;
390
- case col.g:
391
- hue = (col.b - col.r) / delta + 2;
392
- break;
393
- case col.b:
394
- hue = (col.r - col.g) / delta + 4;
395
- break;
396
- }
397
- hue /= 6;
407
+ hue = (red - green) / delta + 4;
408
+ }
409
+ hue = Math.round(hue * 60);
410
+ if (hue < 0) {
411
+ hue += 360;
398
412
  }
413
+ var lightness = (cMax + cMin) / 2;
414
+ saturation = 0 === delta ? 0 : delta / (1 - Math.abs(2 * lightness - 1));
415
+ // round values to 1 decimal place
416
+ saturation = Number((saturation * 100).toFixed(1));
417
+ lightness = Number((lightness * 100).toFixed(1));
399
418
  return {
400
- h: Math.round(hue * 360),
401
- s: Math.round(saturation * 100),
402
- l: Math.round(lightness * 100),
419
+ h: hue,
420
+ s: saturation,
421
+ l: lightness,
403
422
  a: this.getAlpha(tbgr) / 255,
404
423
  };
405
424
  };
@@ -421,54 +440,51 @@ var ColorValue = /** @class */ (function () {
421
440
  */
422
441
  ColorValue.toHsv = function (tbgr) {
423
442
  var _a = ColorValue.getColors(tbgr), r = _a.r, g = _a.g, b = _a.b;
424
- var min = r < g ? r : g;
425
- if (b < min) {
426
- min = b;
443
+ var red = r / 255;
444
+ var green = g / 255;
445
+ var blue = b / 255;
446
+ var cMin = Math.min(red, green, blue);
447
+ var cMax = Math.max(red, green, blue);
448
+ var delta = cMax - cMin;
449
+ var hue = 0;
450
+ if (0 === delta) {
451
+ hue = 0;
427
452
  }
428
- var max = r > g ? r : g;
429
- if (b > max) {
430
- max = b;
453
+ else if (red === cMax) {
454
+ hue = ((green - blue) / delta) % 6;
431
455
  }
432
- /* amount of "blackness" present */
433
- var v = Math.floor((max / 255.0) * 100 + 0.5);
434
- var deltaRgb = max - min;
435
- var s = max !== 0.0 ? Math.floor((deltaRgb / max) * 100 + 0.5) : 0;
436
- var h = 0;
437
- if (s) {
438
- var redDistance = (max - r) / deltaRgb;
439
- var greenDistance = (max - g) / deltaRgb;
440
- var blueDistance = (max - b) / deltaRgb;
441
- var intermediateHue = void 0;
442
- if (r === max) {
443
- /* color between yellow & magenta */
444
- intermediateHue = blueDistance - greenDistance;
445
- }
446
- else if (g === max) {
447
- /* color between cyan & yellow */
448
- intermediateHue = 2.0 + redDistance - blueDistance;
449
- }
450
- else {
451
- /* color between magenta & cyan */
452
- intermediateHue = 4.0 + greenDistance - redDistance;
453
- }
454
- /* intermediate hue is [0..6] */
455
- intermediateHue *= 60;
456
- if (intermediateHue < 0.0) {
457
- intermediateHue += 360;
458
- }
459
- h = Math.floor(intermediateHue + 0.5);
460
- if (h >= 360) {
461
- h = 0;
462
- }
456
+ else if (green === cMax) {
457
+ hue = (blue - red) / delta + 2;
463
458
  }
464
459
  else {
465
- h = 0;
460
+ hue = (red - green) / delta + 4;
461
+ }
462
+ hue = Math.round(hue * 60);
463
+ if (hue < 0) {
464
+ hue += 360;
466
465
  }
467
- return { h: h, s: s, v: v, a: this.getAlpha(tbgr) / 255 };
466
+ var brightness = cMax;
467
+ var saturation = cMax === 0 ? 0 : delta / cMax;
468
+ // round values to 1 decimal place
469
+ saturation = Number((saturation * 100).toFixed(1));
470
+ brightness = Number((brightness * 100).toFixed(1));
471
+ return {
472
+ h: hue,
473
+ s: saturation,
474
+ v: brightness,
475
+ a: this.getAlpha(tbgr) / 255,
476
+ };
468
477
  };
469
478
  /** True if the value of this ColorValue is the same as another ColorValue. */
470
479
  ColorValue.prototype.equals = function (other) {
471
- return this._tbgr === other._tbgr && this._hue === other._hue;
480
+ return this._tbgr === other._tbgr;
481
+ };
482
+ ColorValue.getFormattedColorNumber = function (value, precision) {
483
+ if (precision === void 0) { precision = 1; }
484
+ if (0 === precision) {
485
+ Math.round(value).toString();
486
+ }
487
+ return Number(value.toFixed(precision)).toString();
472
488
  };
473
489
  /** Convert the 0xTTBBGGRR color to a string of the form "rgba(r,g,b,a)" where the color components are specified in decimal and the alpha component is a fraction. */
474
490
  ColorValue.prototype.toRgbString = function (includeAlpha) {
@@ -477,7 +493,7 @@ var ColorValue = /** @class */ (function () {
477
493
  var rgbString = rgb.r + ", " + rgb.g + ", " + rgb.b;
478
494
  if (includeAlpha) {
479
495
  var alpha = (_a = rgb.a) !== null && _a !== void 0 ? _a : 1;
480
- return "rgba(" + rgbString + ", " + alpha.toFixed(2) + ")";
496
+ return "rgba(" + rgbString + ", " + ColorValue.getFormattedColorNumber(alpha, 2) + ")";
481
497
  }
482
498
  return "rgb(" + rgbString + ")";
483
499
  };
@@ -485,10 +501,10 @@ var ColorValue = /** @class */ (function () {
485
501
  ColorValue.prototype.toHslString = function (includeAlpha) {
486
502
  var _a, _b;
487
503
  var hsl = this.toHslColor();
488
- var hslString = ((_a = this._hue) !== null && _a !== void 0 ? _a : hsl.h) + ", " + hsl.s + "%, " + hsl.l + "%";
504
+ var hslString = ColorValue.getFormattedColorNumber((_a = this._hue) !== null && _a !== void 0 ? _a : hsl.h) + ", " + ColorValue.getFormattedColorNumber(hsl.s) + "%, " + ColorValue.getFormattedColorNumber(hsl.l) + "%";
489
505
  if (includeAlpha) {
490
506
  var alpha = (_b = hsl.a) !== null && _b !== void 0 ? _b : 1;
491
- return "hsla(" + hslString + ", " + alpha.toFixed(2) + ")";
507
+ return "hsla(" + hslString + ", " + ColorValue.getFormattedColorNumber(alpha, 2) + ")";
492
508
  }
493
509
  return "hsl(" + hslString + ")";
494
510
  };
@@ -499,7 +515,7 @@ var ColorValue = /** @class */ (function () {
499
515
  var hsvString = ((_a = this._hue) !== null && _a !== void 0 ? _a : hsv.h) + ", " + hsv.s + "%, " + hsv.v + "%";
500
516
  if (includeAlpha) {
501
517
  var alpha = (_b = hsv.a) !== null && _b !== void 0 ? _b : 1;
502
- return "hsva(" + hsvString + ", " + alpha.toFixed(2) + ")";
518
+ return "hsva(" + hsvString + ", " + ColorValue.getFormattedColorNumber(alpha, 2) + ")";
503
519
  }
504
520
  return "hsv(" + hsvString + ")";
505
521
  };
@@ -0,0 +1,21 @@
1
+ /// <reference types="react" />
2
+ import { CommonProps } from '../props';
3
+ export declare type MiddleTextTruncationProps = {
4
+ /**
5
+ * Text to truncate.
6
+ */
7
+ text: string;
8
+ /**
9
+ * Number of characters to leave at the end.
10
+ * @default 6
11
+ */
12
+ endCharsCount?: number;
13
+ } & CommonProps;
14
+ /**
15
+ * Truncates text with the ellipsis in the middle,
16
+ * leaving defined number of chars at the end.
17
+ * @example
18
+ * <MiddleTextTruncation text='ThisIsMyVeryLongFileName.dgn' />
19
+ */
20
+ export declare const MiddleTextTruncation: (props: MiddleTextTruncationProps) => JSX.Element;
21
+ export default MiddleTextTruncation;
@@ -0,0 +1,49 @@
1
+ var __assign = (this && this.__assign) || function () {
2
+ __assign = Object.assign || function(t) {
3
+ for (var s, i = 1, n = arguments.length; i < n; i++) {
4
+ s = arguments[i];
5
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
6
+ t[p] = s[p];
7
+ }
8
+ return t;
9
+ };
10
+ return __assign.apply(this, arguments);
11
+ };
12
+ var __rest = (this && this.__rest) || function (s, e) {
13
+ var t = {};
14
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
15
+ t[p] = s[p];
16
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
17
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
18
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
19
+ t[p[i]] = s[p[i]];
20
+ }
21
+ return t;
22
+ };
23
+ /*---------------------------------------------------------------------------------------------
24
+ * Copyright (c) Bentley Systems, Incorporated. All rights reserved.
25
+ * See LICENSE.md in the project root for license terms and full copyright notice.
26
+ *--------------------------------------------------------------------------------------------*/
27
+ import React from 'react';
28
+ import { useOverflow } from '../hooks/useOverflow';
29
+ var ELLIPSIS_CHAR = '…';
30
+ /**
31
+ * Truncates text with the ellipsis in the middle,
32
+ * leaving defined number of chars at the end.
33
+ * @example
34
+ * <MiddleTextTruncation text='ThisIsMyVeryLongFileName.dgn' />
35
+ */
36
+ export var MiddleTextTruncation = function (props) {
37
+ var text = props.text, _a = props.endCharsCount, endCharsCount = _a === void 0 ? 6 : _a, style = props.style, rest = __rest(props, ["text", "endCharsCount", "style"]);
38
+ var _b = useOverflow(text), ref = _b[0], visibleCount = _b[1];
39
+ var truncatedText = React.useMemo(function () {
40
+ if (visibleCount < text.length) {
41
+ return "" + text.substr(0, visibleCount - endCharsCount - ELLIPSIS_CHAR.length) + ELLIPSIS_CHAR + text.substr(text.length - endCharsCount);
42
+ }
43
+ else {
44
+ return text;
45
+ }
46
+ }, [endCharsCount, text, visibleCount]);
47
+ return (React.createElement("span", __assign({ style: __assign({ display: 'flex', minWidth: 0, flexGrow: 1, whiteSpace: 'nowrap' }, style), ref: ref }, rest), truncatedText));
48
+ };
49
+ export default MiddleTextTruncation;
@@ -3,3 +3,4 @@ export * from './FocusTrap';
3
3
  export * from './InputContainer';
4
4
  export * from './icons';
5
5
  export * from './WithCSSTransition';
6
+ export * from './MiddleTextTruncation';
@@ -7,3 +7,4 @@ export * from './FocusTrap';
7
7
  export * from './InputContainer';
8
8
  export * from './icons';
9
9
  export * from './WithCSSTransition';
10
+ export * from './MiddleTextTruncation';
@@ -2,5 +2,6 @@ export * from './useEventListener';
2
2
  export * from './useMergedRefs';
3
3
  export * from './useOverflow';
4
4
  export * from './useResizeObserver';
5
+ export * from './useContainerWidth';
5
6
  export * from './useTheme';
6
7
  export * from './useIntersection';
@@ -6,5 +6,6 @@ export * from './useEventListener';
6
6
  export * from './useMergedRefs';
7
7
  export * from './useOverflow';
8
8
  export * from './useResizeObserver';
9
+ export * from './useContainerWidth';
9
10
  export * from './useTheme';
10
11
  export * from './useIntersection';
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Hook that returns the width of an element in three stages:
3
+ * - initialized with 0
4
+ * - immediately set to element's initial width as soon as it's mounted
5
+ * - update to new width every time it changes (using `useResizeObserver` hook)
6
+ *
7
+ * @private
8
+ * @param watchResizes If false, ResizeObserver will not be connected and only the initial width will be returned
9
+ * @returns [ref to attach to the element, stateful width of the element]
10
+ *
11
+ * @example
12
+ * const [ref, width] = useContainerWidth();
13
+ * ... // do something with width
14
+ * return <div ref={ref}>...</div>;
15
+ */
16
+ export declare const useContainerWidth: <T extends HTMLElement>(watchResizes?: boolean) => readonly [(instance: HTMLElement | null) => void, number];
17
+ export default useContainerWidth;
@@ -0,0 +1,43 @@
1
+ /*---------------------------------------------------------------------------------------------
2
+ * Copyright (c) Bentley Systems, Incorporated. All rights reserved.
3
+ * See LICENSE.md in the project root for license terms and full copyright notice.
4
+ *--------------------------------------------------------------------------------------------*/
5
+ import React from 'react';
6
+ import { useMergedRefs } from './useMergedRefs';
7
+ import { useResizeObserver } from './useResizeObserver';
8
+ /**
9
+ * Hook that returns the width of an element in three stages:
10
+ * - initialized with 0
11
+ * - immediately set to element's initial width as soon as it's mounted
12
+ * - update to new width every time it changes (using `useResizeObserver` hook)
13
+ *
14
+ * @private
15
+ * @param watchResizes If false, ResizeObserver will not be connected and only the initial width will be returned
16
+ * @returns [ref to attach to the element, stateful width of the element]
17
+ *
18
+ * @example
19
+ * const [ref, width] = useContainerWidth();
20
+ * ... // do something with width
21
+ * return <div ref={ref}>...</div>;
22
+ */
23
+ export var useContainerWidth = function (watchResizes) {
24
+ if (watchResizes === void 0) { watchResizes = true; }
25
+ var _a = React.useState(0), contentWidth = _a[0], setContentWidth = _a[1];
26
+ var ref = React.useCallback(function (element) {
27
+ if (!element) {
28
+ return;
29
+ }
30
+ setContentWidth(element.getBoundingClientRect().width);
31
+ }, []);
32
+ var updateWidth = React.useCallback(function (_a) {
33
+ var width = _a.width;
34
+ return setContentWidth(width);
35
+ }, []);
36
+ var _b = useResizeObserver(updateWidth), resizeRef = _b[0], resizeObserver = _b[1];
37
+ if (!watchResizes) {
38
+ resizeObserver === null || resizeObserver === void 0 ? void 0 : resizeObserver.disconnect();
39
+ }
40
+ var refs = useMergedRefs(ref, watchResizes ? resizeRef : undefined);
41
+ return [refs, contentWidth];
42
+ };
43
+ export default useContainerWidth;
@@ -20,4 +20,4 @@ import React from 'react';
20
20
  * </div>
21
21
  * );
22
22
  */
23
- export declare const useOverflow: <T extends HTMLElement>(items: React.ReactNode[], disabled?: boolean) => readonly [(instance: T | null) => void, number];
23
+ export declare const useOverflow: <T extends HTMLElement>(items: React.ReactNode[] | string, disabled?: boolean) => readonly [(instance: T | null) => void, number];
@@ -5,6 +5,7 @@
5
5
  import React from 'react';
6
6
  import { useMergedRefs } from './useMergedRefs';
7
7
  import { useResizeObserver } from './useResizeObserver';
8
+ var STARTING_MAX_ITEMS_COUNT = 20;
8
9
  /**
9
10
  * Hook that observes the size of an element and returns the number of items
10
11
  * that should be visible based on the width of the container element.
@@ -29,19 +30,27 @@ import { useResizeObserver } from './useResizeObserver';
29
30
  export var useOverflow = function (items, disabled) {
30
31
  if (disabled === void 0) { disabled = false; }
31
32
  var containerRef = React.useRef(null);
32
- var _a = React.useState(items.length), visibleCount = _a[0], setVisibleCount = _a[1];
33
- var overflowBreakpoints = React.useRef([]);
34
- React.useLayoutEffect(function () {
35
- setVisibleCount(items.length);
36
- overflowBreakpoints.current = [];
37
- }, [items]);
33
+ var _a = React.useState(function () {
34
+ return disabled ? items.length : Math.min(items.length, STARTING_MAX_ITEMS_COUNT);
35
+ }), visibleCount = _a[0], setVisibleCount = _a[1];
36
+ var needsFullRerender = React.useRef(true);
38
37
  var _b = React.useState(0), containerWidth = _b[0], setContainerWidth = _b[1];
38
+ var previousContainerWidth = React.useRef(0);
39
39
  var updateContainerWidth = React.useCallback(function (_a) {
40
40
  var width = _a.width;
41
41
  return setContainerWidth(width);
42
42
  }, []);
43
43
  var _c = useResizeObserver(updateContainerWidth), resizeRef = _c[0], observer = _c[1];
44
44
  var resizeObserverRef = React.useRef(observer);
45
+ React.useLayoutEffect(function () {
46
+ if (disabled) {
47
+ setVisibleCount(items.length);
48
+ }
49
+ else {
50
+ setVisibleCount(Math.min(items.length, STARTING_MAX_ITEMS_COUNT));
51
+ needsFullRerender.current = true;
52
+ }
53
+ }, [containerWidth, disabled, items]);
45
54
  var mergedRefs = useMergedRefs(containerRef, resizeRef);
46
55
  React.useLayoutEffect(function () {
47
56
  var _a;
@@ -51,18 +60,22 @@ export var useOverflow = function (items, disabled) {
51
60
  }
52
61
  var availableWidth = containerRef.current.offsetWidth;
53
62
  var requiredWidth = containerRef.current.scrollWidth;
54
- // hide items when there's no space available
55
- if (availableWidth < requiredWidth && visibleCount > 1) {
56
- setVisibleCount(function (count) { return count - 1; });
57
- overflowBreakpoints.current.push(availableWidth);
63
+ if (availableWidth < requiredWidth) {
64
+ var avgItemWidth = requiredWidth / visibleCount;
65
+ var visibleItems = Math.floor(availableWidth / avgItemWidth);
66
+ setVisibleCount(visibleItems);
58
67
  }
59
- // restore items when there's enough space again
60
- else if (overflowBreakpoints.current.length > 0 &&
61
- availableWidth >
62
- overflowBreakpoints.current[overflowBreakpoints.current.length - 1]) {
63
- setVisibleCount(function (count) { return count + 1; });
64
- overflowBreakpoints.current.pop();
68
+ else if (needsFullRerender.current) {
69
+ var childrenWidth = Array.from(containerRef.current.children).reduce(function (sum, child) { return sum + child.offsetWidth; }, 0);
70
+ var avgItemWidth = childrenWidth / visibleCount;
71
+ var visibleItems = Math.floor(availableWidth / avgItemWidth);
72
+ // Doubling the visible items to overflow the container. Just to be safe.
73
+ setVisibleCount(Math.min(items.length, visibleItems * 2));
65
74
  }
66
- }, [containerWidth, visibleCount, disabled]);
75
+ needsFullRerender.current = false;
76
+ }, [containerWidth, visibleCount, disabled, items.length]);
77
+ React.useLayoutEffect(function () {
78
+ previousContainerWidth.current = containerWidth;
79
+ }, [containerWidth]);
67
80
  return [mergedRefs, visibleCount];
68
81
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@itwin/itwinui-react",
3
- "version": "1.23.2",
3
+ "version": "1.26.1",
4
4
  "author": "Bentley Systems",
5
5
  "license": "MIT",
6
6
  "main": "cjs/index.js",
@@ -40,7 +40,7 @@
40
40
  "build-storybook": "build-storybook"
41
41
  },
42
42
  "dependencies": {
43
- "@itwin/itwinui-css": "^0.38.0",
43
+ "@itwin/itwinui-css": "^0.39.1",
44
44
  "@itwin/itwinui-icons-react": "^1.1.1",
45
45
  "@itwin/itwinui-illustrations-react": "^1.0.1",
46
46
  "@tippyjs/react": "^4.2.5",