forked from swiftlang/swift-docc-render
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathWordBreak.vue
114 lines (105 loc) · 3.95 KB
/
WordBreak.vue
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
<!--
This source file is part of the Swift.org open source project
Copyright (c) 2021 Apple Inc. and the Swift project authors
Licensed under Apache License v2.0 with Runtime Library Exception
See https://swift.org/LICENSE.txt for license information
See https://swift.org/CONTRIBUTORS.txt for Swift project authors
-->
<script>
/**
* Indicate safe places to break apart words across multiple lines when necessary.
*
* - Parameter safeBoundaryPattern: `Regexp` —
* A regular expression to be used to determine the character boundaries
* where the word break hints should be inserted.
* - Parameter tag: `String` —
* A tag to be used to wrap the resulting HTML string (default: `<span>`).
*
* This component can be used to inject `<wbr>` ("word break opportunity") HTML
* elements at safe and readable boundaries within a word, which indicate to web
* browsers where they can break a given word onto the next line. This is done
* to prevent long words from randomly getting cut off at arbitrary characters
* when they won't fit on a single line on a width constrainted viewport.
*
* > Warning:
* > Only raw text nodes may be provided as slotted content.
* >
* > ```xml
* > <WordBreak>fooBar</WordBreak> <!-- ✅ Good -->
* > <WordBreak><span>fooBar</span></WordBreak> <!-- ❌ Bad -->
* > ```
*
* Word break functionality is especially useful for very long symbol names that
* may not fit on a single line on smaller devices and even the page title for
* long symbols on larger devices.
*
* By _default_, the following patterns will be used to determine where to add
* word-break hints:
*
* * between lower/uppercase character pairs — **aA**
* * after colon characters — **a:b**
* * before dot characters — **a.b**
* * before underscore characters — **a_b**
*
* You can also provide a `RegExp` object that defines an alternate pattern if
* the default one doesn't fit your needs.
*
* ## Examples
*
* In the following examples, real space characters represent where the `<wbr>`
* tags would be injected in the resulting HTML.
*
* ```xml
* <WordBreak>fooBarBaz</WordBreak> <!-- 'foo Bar Baz' -->
* <WordBreak>foo:bar:baz:</WordBreak> <!-- 'foo: bar: baz:' -->
* <WordBreak>Foo.Bar.Baz</WordBreak> <!-- 'Foo .Bar .Baz' -->
* <WordBreak>foo_bar_baz</WordBreak> <!-- 'foo _bar _baz' -->
* <WordBreak>foobarbaz</WordBreak> <!-- 'foobarbaz' -->
* ```
*
* ```xml
* <WordBreak :safeBoundaryPattern="/(\w(?=/.\w)|\w(?=\/))/g">
* https://foo.bar/baz/qux
* </WordBreak>
*
* <!-- https://foo .bar /baz /qux -->
* ```
*/
export default {
functional: true,
name: 'WordBreak',
render(createElement, { props, slots, data }) {
const childNodes = (slots().default || []);
const textNodes = childNodes.filter(node => node.text && !node.tag);
// Don't attempt word breaking unless this component wraps raw strings
if (textNodes.length === 0 || textNodes.length !== childNodes.length) {
return createElement(props.tag, data, childNodes);
}
const word = textNodes.map(({ text }) => text).join();
const childrenWithBreaks = [];
let match = null;
let lastIndex = 0;
// Find each regex match in the wrapped string and create an array of each
// individual substring along with a corresponding <wbr> element.
// eslint-disable-next-line no-cond-assign
while ((match = props.safeBoundaryPattern.exec(word)) !== null) {
const nextIndex = match.index + 1;
childrenWithBreaks.push(word.slice(lastIndex, nextIndex));
childrenWithBreaks.push(createElement('wbr', { key: match.index }));
lastIndex = nextIndex;
}
childrenWithBreaks.push(word.slice(lastIndex, word.length));
return createElement(props.tag, data, childrenWithBreaks);
},
props: {
safeBoundaryPattern: {
type: RegExp,
default: () => /([a-z](?=[A-Z])|(:)\w|\w(?=[._]\w))/g,
},
tag: {
type: String,
default: () => 'span',
},
},
};
</script>