@getflip/swirl-components 0.107.0 → 0.108.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 (49) hide show
  1. package/components.json +19 -9
  2. package/dist/cjs/loader.cjs.js +1 -1
  3. package/dist/cjs/swirl-components.cjs.js +1 -1
  4. package/dist/cjs/swirl-heading.cjs.entry.js +3 -15
  5. package/dist/cjs/swirl-popover_2.cjs.entry.js +4 -2
  6. package/dist/cjs/swirl-text.cjs.entry.js +765 -8
  7. package/dist/cjs/swirl-tooltip.cjs.entry.js +2 -2
  8. package/dist/collection/assets/pdfjs/pdf.worker.min.js +1 -1
  9. package/dist/collection/components/swirl-heading/swirl-heading.css +4 -0
  10. package/dist/collection/components/swirl-heading/swirl-heading.js +2 -23
  11. package/dist/collection/components/swirl-heading/swirl-heading.spec.js +2 -2
  12. package/dist/collection/components/swirl-popover/swirl-popover.js +22 -2
  13. package/dist/collection/components/swirl-popover/swirl-popover.stories.js +3 -0
  14. package/dist/collection/components/swirl-resource-list-item/swirl-resource-list-item.stories.js +1 -0
  15. package/dist/collection/components/swirl-search/swirl-search.stories.js +0 -3
  16. package/dist/collection/components/swirl-theme-provider/swirl-theme-provider.stories.js +0 -3
  17. package/dist/collection/components/swirl-time-input/swirl-time-input.stories.js +0 -3
  18. package/dist/collection/components/swirl-tooltip/swirl-tooltip.css +1 -1
  19. package/dist/collection/components/swirl-tooltip/swirl-tooltip.js +1 -1
  20. package/dist/components/assets/pdfjs/pdf.worker.min.js +1 -1
  21. package/dist/components/swirl-heading2.js +4 -16
  22. package/dist/components/swirl-popover2.js +5 -2
  23. package/dist/components/swirl-text2.js +759 -2
  24. package/dist/components/swirl-tooltip2.js +2 -2
  25. package/dist/esm/loader.js +1 -1
  26. package/dist/esm/swirl-components.js +1 -1
  27. package/dist/esm/swirl-heading.entry.js +3 -15
  28. package/dist/esm/swirl-popover_2.entry.js +4 -2
  29. package/dist/esm/swirl-text.entry.js +759 -2
  30. package/dist/esm/swirl-tooltip.entry.js +2 -2
  31. package/dist/swirl-components/p-39cf2a0f.entry.js +8 -0
  32. package/dist/swirl-components/p-bd58af17.entry.js +1 -0
  33. package/dist/swirl-components/p-bff41b61.entry.js +1 -0
  34. package/dist/swirl-components/p-e2870d0c.entry.js +1 -0
  35. package/dist/swirl-components/swirl-components.esm.js +1 -1
  36. package/dist/types/components/swirl-heading/swirl-heading.d.ts +0 -4
  37. package/dist/types/components/swirl-popover/swirl-popover.d.ts +1 -0
  38. package/dist/types/components/swirl-popover/swirl-popover.stories.d.ts +3 -0
  39. package/dist/types/components.d.ts +2 -0
  40. package/package.json +2 -3
  41. package/vscode-data.json +4 -0
  42. package/dist/cjs/balancetext-562c7a48.js +0 -763
  43. package/dist/components/balancetext.js +0 -761
  44. package/dist/esm/balancetext-fa49c64f.js +0 -761
  45. package/dist/swirl-components/p-52282426.entry.js +0 -8
  46. package/dist/swirl-components/p-8d3d2f60.entry.js +0 -1
  47. package/dist/swirl-components/p-d7af31e3.entry.js +0 -1
  48. package/dist/swirl-components/p-f6698af0.entry.js +0 -1
  49. package/dist/swirl-components/p-f83a5757.js +0 -1
@@ -1,6 +1,763 @@
1
1
  import { proxyCustomElement, HTMLElement, h, Host } from '@stencil/core/internal/client';
2
- import { c as classnames } from './index2.js';
3
- import { b as balancetext } from './balancetext.js';
2
+ import { a as createCommonjsModule, b as commonjsGlobal, c as classnames } from './index2.js';
3
+
4
+ var balancetext = createCommonjsModule(function (module) {
5
+ /*
6
+ * Copyright (c) 2012 Adobe Systems Incorporated. All rights reserved.
7
+ *
8
+ * Licensed under the Apache License, Version 2.0 (the "License");
9
+ * you may not use this file except in compliance with the License.
10
+ * You may obtain a copy of the License at
11
+ *
12
+ * http://www.apache.org/licenses/LICENSE-2.0
13
+ *
14
+ * Unless required by applicable law or agreed to in writing, software
15
+ * distributed under the License is distributed on an "AS IS" BASIS,
16
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17
+ * See the License for the specific language governing permissions and
18
+ * limitations under the License. *
19
+ */
20
+ /**
21
+ * balancetext.js
22
+ *
23
+ * Author: Randy Edmunds
24
+ */
25
+
26
+ /* global define, module */
27
+
28
+ /*
29
+ * Copyright (c) 2007-2009 unscriptable.com and John M. Hann
30
+ *
31
+ * Permission is hereby granted, free of charge, to any person
32
+ * obtaining a copy of this software and associated documentation
33
+ * files (the “Software”), to deal in the Software without
34
+ * restriction, including without limitation the rights to use,
35
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
36
+ * copies of the Software, and to permit persons to whom the
37
+ * Software is furnished to do so, subject to the following
38
+ * conditions:
39
+ *
40
+ * The above copyright notice and this permission notice shall be
41
+ * included in all copies or substantial portions of the Software.
42
+ *
43
+ * THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND,
44
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
45
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
46
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
47
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
48
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
49
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
50
+ * OTHER DEALINGS IN THE SOFTWARE.
51
+ *
52
+ * Except as contained in this notice, the name(s) of the above
53
+ * copyright holders (unscriptable.com and John M. Hann) shall not be
54
+ * used in advertising or otherwise to promote the sale, use or other
55
+ * dealings in this Software without prior written authorization.
56
+ *
57
+ * http://unscriptable.com/index.php/2009/03/20/debouncing-javascript-methods/
58
+ *
59
+ * Tested to work on (lowest browser):
60
+ * - Sarari 4
61
+ * - Chrome 16
62
+ * - Firefox 10
63
+ * - IE 9
64
+ * - Edge 13
65
+ */
66
+
67
+ (function (root, factory) {
68
+ if (module.exports) {
69
+ module.exports = factory();
70
+ } else {
71
+ root.balanceText = factory();
72
+ }
73
+ }(commonjsGlobal, () => {
74
+ /**
75
+ * Line breaking global vars
76
+ */
77
+ let breakMatches, wsnwMatches, wsnwOffset;
78
+
79
+ /**
80
+ * Selectors and elements to watch;
81
+ * calling $.balanceText(elements) adds "elements" to this list.
82
+ */
83
+ const watching = {
84
+ sel: [], // default class to watch
85
+ el: [],
86
+ };
87
+
88
+ /**
89
+ * Have handlers been initialized?
90
+ */
91
+ let handlersInitialized = false;
92
+
93
+ /**
94
+ * Is this a polyfill?
95
+ */
96
+ let polyfilled = false;
97
+
98
+
99
+ /**
100
+ * Do nothing
101
+ */
102
+ function noop() { }
103
+
104
+ /**
105
+ * Loop that works with array-likes
106
+ * @param {Array-like} elements - List of elements to run a function on
107
+ * @param {Function} callback - The function to call on each supplied element
108
+ */
109
+ function forEach(elements, callback) {
110
+ Array.prototype.forEach.call(elements, callback);
111
+ }
112
+
113
+ /**
114
+ * Polyfill for $(document).ready()
115
+ *
116
+ * @param {Function} fn - The function to execute when the document is ready
117
+ */
118
+ function ready(fn) {
119
+ if (document.readyState !== "loading") {
120
+ fn();
121
+ } else if (document.addEventListener) {
122
+ document.addEventListener("DOMContentLoaded", fn);
123
+ } else {
124
+ document.attachEvent("onreadystatechange", () => {
125
+ if (document.readyState !== "loading") {
126
+ fn();
127
+ }
128
+ });
129
+ }
130
+ }
131
+
132
+ /**
133
+ * Debounces a function over a threshold
134
+ *
135
+ * @param {Function} func - The function to debounce
136
+ * @param {number} threshold - time in ms
137
+ * @param {boolean} execAsap - when true, execute immediately
138
+ * @param args
139
+ * @return {Function} Debounced function
140
+ */
141
+ function debounce(func, threshold, execAsap, ...args) {
142
+ let timeout;
143
+
144
+ return function () {
145
+ const obj = this;
146
+
147
+ function delayed() {
148
+ if (!execAsap) {
149
+ func.apply(obj, args);
150
+ }
151
+ timeout = null;
152
+ }
153
+
154
+ if (timeout) {
155
+ clearTimeout(timeout);
156
+ } else if (execAsap) {
157
+ func.apply(obj, args);
158
+ }
159
+ timeout = setTimeout(delayed, threshold || 100);
160
+ };
161
+ }
162
+
163
+ /**
164
+ * Determine whether the document supports TextWrap
165
+ * @return {boolean}
166
+ */
167
+ function hasTextWrap() {
168
+ if (typeof window === "undefined") {
169
+ return false;
170
+ }
171
+ const { style } = document.documentElement;
172
+ return style.textWrap || style.WebkitTextWrap || style.MozTextWrap || style.MsTextWrap;
173
+ }
174
+
175
+ /**
176
+ * Object for tracking next whitespace params
177
+ */
178
+ // eslint-disable-next-line camelcase
179
+ function NextWS_params() {
180
+ this.reset();
181
+ }
182
+
183
+ NextWS_params.prototype.reset = function () {
184
+ this.index = 0;
185
+ this.width = 0;
186
+ };
187
+
188
+ /**
189
+ * Check if index is contained in previously calculated list of white-space:nowrap ranges
190
+ *
191
+ * @param {number} index - the index of the character to check
192
+ * @return {boolean}
193
+ */
194
+ function isWhiteSpaceNoWrap(index) {
195
+ // Is index inside 1 of the ranges?
196
+ // start and end are breakable, but not inside range
197
+ return wsnwMatches.some(range => (range.start < index && index < range.end));
198
+ }
199
+
200
+ /**
201
+ * Recursively calculate white-space:nowrap offsets for line.
202
+ *
203
+ * @param {Node} el - the element to act on
204
+ * @param {boolean} includeTag - include length of tag itself
205
+ */
206
+ function recursiveCalcNoWrapOffsetsForLine(el, includeTag) {
207
+ if (el.nodeType === el.ELEMENT_NODE) {
208
+ // Found an embedded tag
209
+ const style = window.getComputedStyle(el);
210
+ if (style.whiteSpace === "nowrap") {
211
+ // Tag with white-space:nowrap - add match, skip children
212
+ const len = el.outerHTML.length;
213
+ wsnwMatches.push({ start: wsnwOffset, end: wsnwOffset + len });
214
+ wsnwOffset += len;
215
+ } else {
216
+ // Tag without white-space:nowrap - recursively check children of tag
217
+ forEach(el.childNodes, (child) => {
218
+ recursiveCalcNoWrapOffsetsForLine(child, true);
219
+ });
220
+ if (includeTag) {
221
+ // Length of opening tag, attributes, and closing tag
222
+ wsnwOffset += (el.outerHTML.length - el.innerHTML.length);
223
+ }
224
+ }
225
+ } else if (el.nodeType === el.COMMENT_NODE) {
226
+ wsnwOffset += el.length + 7; // delimiter: <!-- -->
227
+ } else if (el.nodeType === el.PROCESSING_INSTRUCTION_NODE) {
228
+ wsnwOffset += el.length + 2; // delimiter: < >
229
+ } else {
230
+ // Text node: add length
231
+ wsnwOffset += el.length;
232
+ }
233
+ }
234
+
235
+ /**
236
+ * Calculate white-space:nowrap offsets for line.
237
+ *
238
+ * @param {Node} el - the element to act on
239
+ * @param {string} oldWS - "old" whitespace setting for temporarily resetting
240
+ * @param {number} lineCharOffset - char offset of current line from start of text
241
+ */
242
+ function calcNoWrapOffsetsForLine(el, oldWS, lineCharOffset) {
243
+ // For first line (lineCharOffset === 0), calculate start and end offsets for each
244
+ // white-space:nowrap element in the line.
245
+ if (lineCharOffset === 0) {
246
+ // Reset whiteSpace setting when breakMatches is being calculated
247
+ // so white-space:nowrap can be detected in text
248
+ el.style.whiteSpace = oldWS;
249
+
250
+ wsnwOffset = 0;
251
+ wsnwMatches = [];
252
+ recursiveCalcNoWrapOffsetsForLine(el, false);
253
+
254
+ // Restore temporary whitespace setting to recalc width
255
+ el.style.whiteSpace = "nowrap";
256
+ } else {
257
+ // For all other lines, update the offsets for current line
258
+ // 1. Ignore matches less than offset
259
+ // 2. Subtract offset from remaining matches
260
+ const newMatches = [];
261
+ wsnwMatches.forEach((match) => {
262
+ if (match.start > lineCharOffset) {
263
+ newMatches.push({ start: match.start - lineCharOffset, end: match.end - lineCharOffset });
264
+ }
265
+ });
266
+ wsnwMatches = newMatches;
267
+ }
268
+ }
269
+
270
+ /**
271
+ * Strip balance-text tags from an element inserted in previous run
272
+ *
273
+ * @param {Node} el - the element to act on
274
+ */
275
+ function removeTags(el) {
276
+ // Remove soft-hyphen breaks
277
+ let brs = el.querySelectorAll('br[data-owner="balance-text-hyphen"]');
278
+ forEach(brs, (br) => {
279
+ br.outerHTML = "";
280
+ });
281
+
282
+ // Replace other breaks with whitespace
283
+ brs = el.querySelectorAll('br[data-owner="balance-text"]');
284
+ forEach(brs, (br) => {
285
+ br.outerHTML = " ";
286
+ });
287
+
288
+ // Restore hyphens inserted for soft-hyphens
289
+ let spans = el.querySelectorAll('span[data-owner="balance-text-softhyphen"]');
290
+ if (spans.length > 0) {
291
+ forEach(spans, (span) => {
292
+ const textNode = document.createTextNode("\u00ad");
293
+ span.parentNode.insertBefore(textNode, span);
294
+ span.parentNode.removeChild(span);
295
+ });
296
+ }
297
+
298
+ // Remove spans inserted for justified text
299
+ spans = el.querySelectorAll('span[data-owner="balance-text-justify"]');
300
+ if (spans.length > 0) {
301
+ let txt = "";
302
+ forEach(spans, (span) => {
303
+ txt += span.textContent;
304
+ span.parentNode.removeChild(span);
305
+ });
306
+ el.innerHTML = txt;
307
+ }
308
+ }
309
+
310
+ /**
311
+ * Checks to see if we should justify the balanced text with the
312
+ * element based on the textAlign property in the computed CSS
313
+ *
314
+ * @param {Node} el - element to check
315
+ * @return {boolean}
316
+ */
317
+ const isJustified = function (el) {
318
+ const style = el.currentStyle || window.getComputedStyle(el, null);
319
+ return (style.textAlign === "justify");
320
+ };
321
+
322
+ /**
323
+ * Add whitespace after words in text to justify the string to
324
+ * the specified size.
325
+ * @param {Node} el - the element to justify
326
+ * @param {string} txt - text string
327
+ * @param {number} conWidth - container width
328
+ * @return {string} Justified text
329
+ */
330
+ function justify(el, txt, conWidth) {
331
+ txt = txt.trim();
332
+ const words = txt.split(" ").length;
333
+ txt = `${txt} `;
334
+
335
+ // if we don't have at least 2 words, no need to justify.
336
+ if (words < 2) {
337
+ return txt;
338
+ }
339
+
340
+ // Find width of text in the DOM
341
+ const tmp = document.createElement("span");
342
+ tmp.innerHTML = txt;
343
+ el.appendChild(tmp);
344
+ const size = tmp.offsetWidth;
345
+ tmp.parentNode.removeChild(tmp);
346
+
347
+ // Figure out our word spacing and return the element
348
+ const wordSpacing = Math.floor((conWidth - size) / (words - 1));
349
+ tmp.style.wordSpacing = `${wordSpacing}px`;
350
+ tmp.setAttribute("data-owner", "balance-text-justify");
351
+
352
+ const div = document.createElement("div");
353
+ div.appendChild(tmp);
354
+ return div.innerHTML;
355
+ }
356
+
357
+ /**
358
+ * Returns true iff char at index is a break char outside of HTML < > tags.
359
+ * Break char can be: whitespace (except non-breaking-space: u00a0),
360
+ * hypen, emdash (u2014), endash (u2013), or soft-hyphen (u00ad).
361
+ *
362
+ * @param {string} txt - the text to check
363
+ * @param {number} index - the index of the character to check
364
+ * @return {boolean}
365
+ */
366
+ function isBreakChar(txt, index) {
367
+ const re = /([^\S\u00a0]|-|\u2014|\u2013|\u00ad)(?![^<]*>)/g;
368
+ let match;
369
+
370
+ if (!breakMatches) {
371
+ // Only calc break matches once per line
372
+ breakMatches = [];
373
+ match = re.exec(txt);
374
+ while (match !== null) {
375
+ if (!isWhiteSpaceNoWrap(match.index)) {
376
+ breakMatches.push(match.index);
377
+ }
378
+ match = re.exec(txt);
379
+ }
380
+ }
381
+
382
+ return breakMatches.indexOf(index) !== -1;
383
+ }
384
+
385
+ /**
386
+ * In the current implementation, an index is a break
387
+ * opportunity in txt iff it is:
388
+ * - 0 or txt.length
389
+ * - index of a non-whitespace char immediately preceded by a
390
+ * whitespace, hyphen, soft-hyphen, em-dash, or en-dash char.
391
+ *
392
+ * Thus, it doesn't honour "white-space" or any other Unicode
393
+ * line-breaking classes.)
394
+ *
395
+ * @precondition 0 <= index && index <= txt.length
396
+ *
397
+ * @param {string} txt - the text to check
398
+ * @param {number} index - the index to check
399
+ * @return {boolean}
400
+ */
401
+ function isBreakOpportunity(txt, index) {
402
+ return ((index === 0) || (index === txt.length) ||
403
+ (isBreakChar(txt, index - 1) && !isBreakChar(txt, index)));
404
+ }
405
+
406
+ /**
407
+ * Finds the first break opportunity (@see isBreakOpportunity)
408
+ * in txt that's both after-or-equal-to index c in the direction dir
409
+ * and resulting in line width equal to or past clamp(desWidth,
410
+ * 0, conWidth) in direction dir. Sets ret.index and ret.width
411
+ * to the corresponding index and line width (from the start of
412
+ * txt to ret.index).
413
+ *
414
+ * @param {Node} el - element
415
+ * @param {string} txt - text string
416
+ * @param {number} conWidth - container width
417
+ * @param {number} desWidth - desired width
418
+ * @param {number} dir - direction (-1 or +1)
419
+ * @param {number} c - char index (0 <= c && c <= txt.length)
420
+ * @param {Object} ret - return {index: {number}, width: {number}} of previous/next break
421
+ */
422
+ function findBreakOpportunity(el, txt, conWidth, desWidth, dir, c, ret) {
423
+ let w;
424
+
425
+ if (txt && typeof txt === "string") {
426
+ for (;;) {
427
+ while (!isBreakOpportunity(txt, c)) {
428
+ c += dir;
429
+ }
430
+
431
+ el.innerHTML = txt.substr(0, c);
432
+ w = el.offsetWidth;
433
+
434
+ if (dir < 0) {
435
+ if ((w <= desWidth) || (w <= 0) || (c === 0)) {
436
+ break;
437
+ }
438
+ } else if ((desWidth <= w) || (conWidth <= w) || (c === txt.length)) {
439
+ break;
440
+ }
441
+
442
+ c += dir;
443
+ }
444
+ }
445
+ ret.index = c;
446
+ ret.width = w;
447
+ }
448
+
449
+ /**
450
+ * Detects the width of a non-breaking space character, given the height of
451
+ * the element with no-wrap applied.
452
+ *
453
+ * @param {Node} el - element
454
+ * @param {number} h - height
455
+ * @return {number}
456
+ */
457
+ function getSpaceWidth(el, h) {
458
+ const container = document.createElement("div");
459
+
460
+ container.style.display = "block";
461
+ container.style.position = "absolute";
462
+ container.style.bottom = 0;
463
+ container.style.right = 0;
464
+ container.style.width = 0;
465
+ container.style.height = 0;
466
+ container.style.margin = 0;
467
+ container.style.padding = 0;
468
+ container.style.visibility = "hidden";
469
+ container.style.overflow = "hidden";
470
+
471
+ const space = document.createElement("span");
472
+
473
+ space.style.fontSize = "2000px";
474
+ space.innerHTML = "&nbsp;";
475
+
476
+ container.appendChild(space);
477
+
478
+ el.appendChild(container);
479
+
480
+ const dims = space.getBoundingClientRect();
481
+ container.parentNode.removeChild(container);
482
+
483
+ const spaceRatio = dims.height / dims.width;
484
+
485
+ return (h / spaceRatio);
486
+ }
487
+
488
+ /**
489
+ * Get a list of elements regardless of input
490
+ *
491
+ * @param {string|Node|Array-like} elements - The selector to query, one or more elements
492
+ * @return {Array<{Node}>}
493
+ */
494
+ function getElementsList(elements) {
495
+ if (!elements) {
496
+ return [];
497
+ }
498
+
499
+ // is selector
500
+ if (typeof elements === "string") {
501
+ return document.querySelectorAll(elements);
502
+ }
503
+
504
+ // is single element
505
+ if (elements.tagName && elements.querySelectorAll) {
506
+ return [elements];
507
+ }
508
+
509
+ return elements;
510
+ }
511
+
512
+ /**
513
+ * When a browser has native support for the text-wrap property,
514
+ * the text balanceText plugin will let the browser handle it natively,
515
+ * otherwise it will apply its own text balancing code.
516
+ *
517
+ * @param {string|Node|Array-like} elements - the list of elements to balance
518
+ */
519
+ function balanceText(elements) {
520
+ forEach(getElementsList(elements), (el) => {
521
+ // In a lower level language, this algorithm takes time
522
+ // comparable to normal text layout other than the fact
523
+ // that we do two passes instead of one, so we should
524
+ // be able to do without this limit.
525
+ const maxTextWidth = 5000;
526
+
527
+ // strip balance-text generated tags
528
+ removeTags(el);
529
+
530
+ // save settings
531
+ const oldWS = el.style.whiteSpace;
532
+ const oldFloat = el.style.float;
533
+ const oldDisplay = el.style.display;
534
+ const oldPosition = el.style.position;
535
+ const oldLH = el.style.lineHeight;
536
+
537
+ // remove line height before measuring container size
538
+ el.style.lineHeight = "normal";
539
+
540
+ const containerWidth = el.offsetWidth;
541
+ const containerHeight = el.offsetHeight;
542
+
543
+ // temporary settings
544
+ el.style.whiteSpace = "nowrap";
545
+ el.style.float = "none";
546
+ el.style.display = "inline";
547
+ el.style.position = "static";
548
+
549
+ let nowrapWidth = el.offsetWidth;
550
+ const nowrapHeight = el.offsetHeight;
551
+
552
+ // An estimate of the average line width reduction due
553
+ // to trimming trailing space that we expect over all
554
+ // lines other than the last.
555
+ const spaceWidth = ((oldWS === "pre-wrap") ? 0 : getSpaceWidth(el, nowrapHeight));
556
+
557
+ if (containerWidth > 0 && // prevent divide by zero
558
+ nowrapWidth > containerWidth && // text is more than 1 line
559
+ nowrapWidth < maxTextWidth) { // text is less than arbitrary limit (make this a param?)
560
+ let remainingText = el.innerHTML;
561
+ let newText = "";
562
+ let lineText = "";
563
+ const shouldJustify = isJustified(el);
564
+ const totLines = Math.round(containerHeight / nowrapHeight);
565
+ let remLines = totLines;
566
+ let lineCharOffset = 0;
567
+
568
+ // loop vars
569
+ let desiredWidth, guessIndex, le, ge, splitIndex, isHyphen, isSoftHyphen;
570
+
571
+ // Determine where to break:
572
+ while (remLines > 1) {
573
+ // clear whitespace match cache for each line
574
+ breakMatches = null;
575
+
576
+ // Must calc white-space:nowrap offsets before first call to findBreakOpportunity()
577
+ calcNoWrapOffsetsForLine(el, oldWS, lineCharOffset);
578
+
579
+ desiredWidth = Math.round((nowrapWidth + spaceWidth) / remLines - spaceWidth);
580
+
581
+ // Guessed char index
582
+ guessIndex = Math.round((remainingText.length + 1) / remLines) - 1;
583
+
584
+ le = new NextWS_params();
585
+
586
+ // Find a breaking space somewhere before (or equal to) desired width,
587
+ // not necessarily the closest to the desired width.
588
+ findBreakOpportunity(el, remainingText, containerWidth, desiredWidth, -1, guessIndex, le);
589
+
590
+ // Find first breaking char after (or equal to) desired width.
591
+ ge = new NextWS_params();
592
+ guessIndex = le.index;
593
+ findBreakOpportunity(el, remainingText, containerWidth, desiredWidth, +1, guessIndex, ge);
594
+
595
+ // Find first breaking char before (or equal to) desired width.
596
+ le.reset();
597
+ guessIndex = ge.index;
598
+ findBreakOpportunity(el, remainingText, containerWidth, desiredWidth, -1, guessIndex, le);
599
+
600
+ // Find closest string to desired length
601
+ if (le.index === 0) {
602
+ splitIndex = ge.index;
603
+ } else if ((containerWidth < ge.width) || (le.index === ge.index)) {
604
+ splitIndex = le.index;
605
+ } else {
606
+ splitIndex = ((Math.abs(desiredWidth - le.width) < Math.abs(ge.width - desiredWidth))
607
+ ? le.index
608
+ : ge.index);
609
+ }
610
+
611
+ // Break string
612
+ lineText = remainingText.substr(0, splitIndex).replace(/\s$/, "");
613
+
614
+ isSoftHyphen = Boolean(lineText.match(/\u00ad$/));
615
+ if (isSoftHyphen) {
616
+ // Replace soft-hyphen causing break with explicit hyphen
617
+ lineText = lineText.replace(/\u00ad$/, '<span data-owner="balance-text-softhyphen">-</span>');
618
+ }
619
+
620
+ if (shouldJustify) {
621
+ newText += justify(el, lineText, containerWidth);
622
+ } else {
623
+ newText += lineText;
624
+ isHyphen = isSoftHyphen || Boolean(lineText.match(/(-|\u2014|\u2013)$/));
625
+ newText += isHyphen ? '<br data-owner="balance-text-hyphen" />'
626
+ : '<br data-owner="balance-text" aria-hidden="true" />';
627
+ }
628
+ remainingText = remainingText.substr(splitIndex);
629
+ lineCharOffset = splitIndex;
630
+
631
+ // update counters
632
+ remLines--;
633
+ el.innerHTML = remainingText;
634
+ nowrapWidth = el.offsetWidth;
635
+ }
636
+
637
+ if (shouldJustify) {
638
+ el.innerHTML = newText + justify(el, remainingText, containerWidth);
639
+ } else {
640
+ el.innerHTML = newText + remainingText;
641
+ }
642
+ }
643
+
644
+ // restore settings
645
+ el.style.whiteSpace = oldWS;
646
+ el.style.float = oldFloat;
647
+ el.style.display = oldDisplay;
648
+ el.style.position = oldPosition;
649
+ el.style.lineHeight = oldLH;
650
+ });
651
+ }
652
+
653
+ /**
654
+ * Call the balanceText plugin on elements that it's watching.
655
+ */
656
+ function updateWatched() {
657
+ const selectors = watching.sel.join(",");
658
+ const selectedElements = getElementsList(selectors);
659
+ const elements = Array.prototype.concat.apply(watching.el, selectedElements);
660
+ balanceText(elements);
661
+ }
662
+
663
+ /**
664
+ * Initialize the events for which to re-apply BalanceText. They are:
665
+ * - Document ready
666
+ * - Document full load
667
+ * - Window resize
668
+ */
669
+ function initHandlers() {
670
+ if (handlersInitialized) {
671
+ return;
672
+ }
673
+
674
+ // Apply on DOM ready
675
+ ready(updateWatched);
676
+
677
+ // Reapply on full load
678
+ window.addEventListener("load", updateWatched);
679
+
680
+ // Reapply on resize
681
+ window.addEventListener("resize", debounce(updateWatched));
682
+
683
+ handlersInitialized = true;
684
+ }
685
+
686
+ /**
687
+ * Apply the BalanceText routine on the document and watch the list
688
+ * of elements. On window resize, re-apply BalanceText to the given elements
689
+ *
690
+ * @param {string|Node|Array-like} elements - the elements to watch after applying BalanceText
691
+ */
692
+ function balanceTextAndWatch(elements) {
693
+ if (typeof elements === "string") {
694
+ watching.sel.push(elements);
695
+ } else {
696
+ forEach(getElementsList(elements), (el) => {
697
+ watching.el.push(el);
698
+ });
699
+ }
700
+
701
+ initHandlers();
702
+ updateWatched();
703
+ }
704
+
705
+ /**
706
+ * Stop watching elements
707
+ *
708
+ * @param {string|Node|Array-like} elements
709
+ */
710
+ function unwatch(elements) {
711
+ if (typeof elements === "string") {
712
+ watching.sel = watching.sel.filter(el => el !== elements);
713
+ } else {
714
+ elements = getElementsList(elements);
715
+ watching.el = watching.el.filter(el => elements.indexOf(el) === -1);
716
+ }
717
+ }
718
+
719
+ /**
720
+ * Treat this app as a polyfill. Watch for changes to the .balance-text selector
721
+ */
722
+ function polyfill() {
723
+ if (polyfilled) {
724
+ return;
725
+ }
726
+
727
+ watching.sel.push(".balance-text");
728
+ initHandlers();
729
+ polyfilled = true;
730
+ }
731
+
732
+ /**
733
+ * Public interface
734
+ *
735
+ * @param {string|Node|Array-like} elements - elements to balance
736
+ * @param {Object} options - processing options
737
+ * - {boolean} watch - watch elements for resize
738
+ */
739
+ function publicInterface(elements, options) {
740
+ if (!elements) {
741
+ // empty call means polyfill (watch for changes)
742
+ polyfill();
743
+ } else if (options && options.watch === true) {
744
+ balanceTextAndWatch(elements);
745
+ } else if (options && options.watch === false) {
746
+ unwatch(elements);
747
+ } else {
748
+ balanceText(elements);
749
+ }
750
+ }
751
+
752
+ publicInterface.updateWatched = updateWatched;
753
+
754
+ if (hasTextWrap()) {
755
+ noop.updateWatched = noop;
756
+ return noop;
757
+ }
758
+ return publicInterface;
759
+ }));
760
+ });
4
761
 
5
762
  /**
6
763
  shave - Shave is a javascript plugin that truncates multi-line text within a html element based on set max height