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