Skip to content

Commit 4d4a2dc

Browse files
authored
Merge pull request #5 from pepsico-ecommerce/AUTO-2254
Auto 2254
2 parents 5a6b29d + dcfbba1 commit 4d4a2dc

8 files changed

Lines changed: 230 additions & 6869 deletions

File tree

.gitignore

Lines changed: 0 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -2,103 +2,16 @@
22
logs
33
*.log
44
npm-debug.log*
5-
yarn-debug.log*
6-
yarn-error.log*
7-
lerna-debug.log*
8-
9-
# Diagnostic reports (https://nodejs.org/api/report.html)
10-
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
11-
12-
# Runtime data
13-
pids
14-
*.pid
15-
*.seed
16-
*.pid.lock
17-
18-
# Directory for instrumented libs generated by jscoverage/JSCover
19-
lib-cov
20-
21-
# Coverage directory used by tools like istanbul
22-
coverage
23-
*.lcov
24-
25-
# nyc test coverage
26-
.nyc_output
27-
28-
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
29-
.grunt
30-
31-
# Bower dependency directory (https://bower.io/)
32-
bower_components
33-
34-
# node-waf configuration
35-
.lock-wscript
36-
37-
# Compiled binary addons (https://nodejs.org/api/addons.html)
38-
build/Release
395

406
# Dependency directories
417
node_modules/
42-
jspm_packages/
43-
44-
# TypeScript v1 declaration files
45-
typings/
46-
47-
# TypeScript cache
48-
*.tsbuildinfo
498

509
# Optional npm cache directory
5110
.npm
5211

5312
# Optional eslint cache
5413
.eslintcache
5514

56-
# Microbundle cache
57-
.rpt2_cache/
58-
.rts2_cache_cjs/
59-
.rts2_cache_es/
60-
.rts2_cache_umd/
61-
62-
# Optional REPL history
63-
.node_repl_history
64-
65-
# Output of 'npm pack'
66-
*.tgz
67-
68-
# Yarn Integrity file
69-
.yarn-integrity
70-
7115
# dotenv environment variables file
7216
.env
7317
.env.test
74-
75-
# parcel-bundler cache (https://parceljs.org/)
76-
.cache
77-
78-
# Next.js build output
79-
.next
80-
81-
# Nuxt.js build / generate output
82-
.nuxt
83-
dist
84-
85-
# Gatsby files
86-
.cache/
87-
# Comment in the public line in if your project uses Gatsby and *not* Next.js
88-
# https://nextjs.org/blog/next-9-1#public-directory-support
89-
# public
90-
91-
# vuepress build output
92-
.vuepress/dist
93-
94-
# Serverless directories
95-
.serverless/
96-
97-
# FuseBox cache
98-
.fusebox/
99-
100-
# DynamoDB Local files
101-
.dynamodb/
102-
103-
# TernJS port file
104-
.tern-port

Makefile

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,10 @@
11
.PHONY: build clean lint demos
22

33
demos: build
4-
npm run start:demo
4+
npx http-server
55

66
build: node_modules/
7-
# cp src/styles.css dist/styles.css
8-
# npx ascjs src esm
9-
# npx rollup --config rollup/es.config.js
10-
# npx rollup --config rollup/babel.config.js
11-
npx webpack --mode=development
7+
npx rollup --config rollup/es.config.js
128

139
lint: node_modules/
1410
npm run lint
@@ -17,6 +13,7 @@ clean:
1713
-rm -f package-lock.json
1814
-rm -r ./node_modules
1915
-npm cache verify
16+
-rm -r dist/*
2017

2118
node_modules/: package.json
2219
npm install

demo/index.html

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ <h1>Demos of pep-p</h1>
4242
</pep-p>
4343
</div>
4444

45-
<script src="./webpack.bundle.js"></script>
45+
<script type="module">
46+
import '../dist/pep-p.es.js';
47+
</script>
4648
</body>
4749
</html>

dist/pep-p.es.js

Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
import { define, css } from 'uce';
2+
import { ResizeObserver } from '@juggle/resize-observer';
3+
4+
/**
5+
* Removes the last word from text and returns the new string.
6+
* Trims text before starting.
7+
* A "word" is text seprated with one or more spaces.
8+
* @param {[type]} text [description]
9+
* @return {[type]} [description]
10+
*/
11+
function removeLastWord(text) {
12+
return text.trim().substring(0, text.lastIndexOf(' '));
13+
}
14+
15+
/**
16+
* <pep-p>PepsiCo Paragraph Custom Element.</pep-p>
17+
* Paragraph Element with multiline ellipse support.
18+
* Text is trimmed to fit inside the parent element. (via 100% width/height)
19+
*/
20+
define('pep-p', {
21+
style: (selector) => css`
22+
${selector} {
23+
/* Prevent the overflow from flashing */
24+
overflow: hidden;
25+
/* Need defined width/height, so use the parents values */
26+
/* height: 100%; */ /* removed height so text can center in parent. */
27+
width: 100%;
28+
display: block;
29+
}
30+
${selector} textarea {
31+
box-sizing: border-box;
32+
}
33+
`,
34+
init() {
35+
// Create a Resize Observer so we can re-adjust the length of the text content
36+
// when the element changes size.
37+
try {
38+
this._resizeObserver = new ResizeObserver((elms) => {
39+
this.render();
40+
});
41+
// Start observing.
42+
this._resizeObserver.observe(this);
43+
}
44+
catch(e) {
45+
console.log('<pep-p /> _resizeObserver error', e, this);
46+
}
47+
},
48+
connected() {
49+
// Create a copy of the children and text before we start modifying it.
50+
this.originalChildNodes = Array.from(this.childNodes).map(node => node.cloneNode(true));
51+
this.originalTextContent = this.textContent;
52+
// this.setAttribute('tooltip', this.originalTextContent.trim());
53+
this.trimTextContent();
54+
},
55+
disconnected() {
56+
try {
57+
this._resizeObserver.disconnect();
58+
this.restoreChildren();
59+
}
60+
catch(e) {
61+
console.log('<pep-p /> Disconnected error', e, this);
62+
}
63+
},
64+
65+
// Restores the original children
66+
restoreChildren() {
67+
this.innerHTML = ''; // clear out all the children
68+
// Create clones of the original children and put them back.
69+
this.originalChildNodes.forEach(child => this.appendChild(child.cloneNode(true)));
70+
},
71+
72+
// render by updating the trimmed text to match the current size.
73+
render() {
74+
// Clear the tooltip.
75+
this.removeAttribute('tooltip');
76+
// Find the minimum height needed to display text.
77+
this.innerHTML = 'ÀEIOUhy';
78+
this.minHeight = this.scrollHeight;
79+
// restore the children and then re-trim to the new size.
80+
this.restoreChildren();
81+
this.trimTextContent();
82+
83+
if (this.didTrim) {
84+
this.setAttribute('tooltip', this.originalTextContent.trim());
85+
}
86+
},
87+
88+
// Returns true if the content overflows.
89+
get hasOverflow() {
90+
if (this.scrollWidth <= this.clientWidth
91+
&& this.scrollHeight <= this.minHeight) {
92+
return false;
93+
}
94+
95+
return true;
96+
},
97+
// Returns true if the element has a size.
98+
get hasSize() {
99+
if (0 === this.scrollWidth || 0 === this.scrollHeight) {
100+
return false;
101+
}
102+
return true;
103+
},
104+
105+
// Trims the text content of the children to make them fit without overflowing.
106+
trimTextContent() {
107+
this.didTrim = false;
108+
109+
// Skip if the element has no size. We can't trim to an unknown.
110+
if (!this.hasSize) {
111+
return;
112+
}
113+
// Loop over each child starting with the last,
114+
// untill we are no longer overflowing, or we run out of children.
115+
for (let idx=(this.childNodes.length-1);
116+
idx >= 0 && this.hasOverflow;
117+
idx--) {
118+
119+
const childElm = this.childNodes[idx];
120+
121+
// We don't want to change user's input, so skip those elements.
122+
if (['TEXTAREA', 'INPUT', 'SELECT'].includes(childElm.nodeName)) {
123+
continue;
124+
}
125+
126+
// We can remove line breaks if we are trying to shrink the content.
127+
if (childElm.nodeName === 'BR') {
128+
childElm.remove();
129+
continue;
130+
}
131+
132+
// Remove one word at a time until either the content fits,
133+
// or we run out of text.
134+
let shorterText = childElm.textContent;
135+
do {
136+
this.didTrim = true;
137+
// Remove the last word.
138+
shorterText = removeLastWord(shorterText);
139+
// update the element so we can check the new size.
140+
childElm.textContent = shorterText;
141+
}
142+
// Stop when we run out of text, or we are no longer overflowing.
143+
while(this.hasOverflow && shorterText.length > 0);
144+
145+
// If the text is empty, remove the element,
146+
if ((!shorterText || shorterText.length === 0)) {
147+
childElm.remove();
148+
}
149+
}
150+
151+
// Check if we did anything.
152+
if (this.didTrim) {
153+
// Find the last text element so we can add ellipsis.
154+
let lastTextElm = this.childNodes[this.childNodes.length-1];
155+
while (lastTextElm && lastTextElm.nodeName !== '#text') {
156+
lastTextElm = lastTextElm.previousSibling;
157+
}
158+
// there is a chance there are no text elements left.
159+
if (lastTextElm) {
160+
lastTextElm.textContent = removeLastWord(lastTextElm.textContent) + ' ...';
161+
}
162+
}
163+
164+
}
165+
});

0 commit comments

Comments
 (0)