tab.js code refactoring

This commit is contained in:
sairaj mote 2021-07-18 01:21:25 +05:30
parent 2d35ef8988
commit f9b2b79133
8 changed files with 118 additions and 177 deletions

View File

@ -250,7 +250,6 @@ customElements.define('sm-input',
this.focusIn = this.focusIn.bind(this) this.focusIn = this.focusIn.bind(this)
this.focusOut = this.focusOut.bind(this) this.focusOut = this.focusOut.bind(this)
this.fireEvent = this.fireEvent.bind(this) this.fireEvent = this.fireEvent.bind(this)
this.debounce = this.debounce.bind(this)
this.checkInput = this.checkInput.bind(this) this.checkInput = this.checkInput.bind(this)
} }
@ -339,15 +338,6 @@ customElements.define('sm-input',
}); });
this.dispatchEvent(event); this.dispatchEvent(event);
} }
debounce(callback, wait){
let timeoutId = null;
return (...args) => {
window.clearTimeout(timeoutId);
timeoutId = window.setTimeout(() => {
callback.apply(null, args);
}, wait);
};
}
checkInput(e){ checkInput(e){
if (!this.hasAttribute('readonly')) { if (!this.hasAttribute('readonly')) {

File diff suppressed because one or more lines are too long

View File

@ -243,7 +243,7 @@ customElements.define('sm-select', class extends HTMLElement {
handleOptionSelection(e) { handleOptionSelection(e) {
if (this.previousOption !== document.activeElement) { if (this.previousOption !== document.activeElement) {
this.value = document.activeElement.getAttribute('value') this.value = document.activeElement.getAttribute('value')
this.selectedOptionText.textContent = this.value; this.selectedOptionText.textContent = document.activeElement.textContent;
this.fireEvent() this.fireEvent()
if (this.previousOption) { if (this.previousOption) {
this.previousOption.classList.remove('check-selected') this.previousOption.classList.remove('check-selected')
@ -263,7 +263,7 @@ customElements.define('sm-select', class extends HTMLElement {
} }
handleKeydown(e) { handleKeydown(e) {
if (e.target === this) { if (e.target === this) {
if (e.code === 'ArrowDown') { if (this.isOpen && e.code === 'ArrowDown') {
e.preventDefault() e.preventDefault()
this.availableOptions[0].focus() this.availableOptions[0].focus()
this.handleOptionSelection(e) this.handleOptionSelection(e)

File diff suppressed because one or more lines are too long

View File

@ -101,66 +101,77 @@ customElements.define('sm-tab-header', class extends HTMLElement {
mode: 'open' mode: 'open'
}).append(smTabHeader.content.cloneNode(true)) }).append(smTabHeader.content.cloneNode(true))
this.prevTab
this.allTabs
this.activeTab
this.indicator = this.shadowRoot.querySelector('.indicator'); this.indicator = this.shadowRoot.querySelector('.indicator');
this.tabSlot = this.shadowRoot.querySelector('slot'); this.tabSlot = this.shadowRoot.querySelector('slot');
this.tabHeader = this.shadowRoot.querySelector('.tab-header'); this.tabHeader = this.shadowRoot.querySelector('.tab-header');
this.changeTab = this.changeTab.bind(this)
this.handleClick = this.handleClick.bind(this)
this.handlePanelChange = this.handlePanelChange.bind(this)
} }
sendDetails(element) { fireEvent(index) {
this.dispatchEvent( this.dispatchEvent(
new CustomEvent("switchtab", { new CustomEvent(`switchedtab${this.target}`, {
bubbles: true, bubbles: true,
detail: { detail: {
target: this.target, index: parseInt(index)
rank: parseInt(element.getAttribute('rank'))
} }
}) })
) )
} }
moveIndiactor(tabDimensions) { moveIndiactor(tabDimensions) {
//if(this.isTab)
this.indicator.setAttribute('style', `width: ${tabDimensions.width}px; transform: translateX(${tabDimensions.left - this.tabHeader.getBoundingClientRect().left + this.tabHeader.scrollLeft}px)`) this.indicator.setAttribute('style', `width: ${tabDimensions.width}px; transform: translateX(${tabDimensions.left - this.tabHeader.getBoundingClientRect().left + this.tabHeader.scrollLeft}px)`)
//else }
//this.indicator.setAttribute('style', `width: calc(${tabDimensions.width}px - 1.6rem); transform: translateX(calc(${ tabDimensions.left - this.tabHeader.getBoundingClientRect().left + this.tabHeader.scrollLeft}px + 0.8rem)`)
changeTab(target) {
if (target === this.prevTab || !target.closest('sm-tab'))
return
if (this.prevTab)
this.prevTab.classList.remove('active')
target.classList.add('active')
target.scrollIntoView({
behavior: 'smooth',
block: 'nearest',
inline: 'center'
})
this.moveIndiactor(target.getBoundingClientRect())
this.prevTab = target;
this.activeTab = target;
}
handleClick(e) {
if (e.target.closest('sm-tab')) {
this.changeTab(e.target)
this.fireEvent(e.target.dataset.index)
}
}
handlePanelChange(e) {
console.log(this.allTabs)
this.changeTab(this.allTabs[e.detail.index])
} }
connectedCallback() { connectedCallback() {
if (!this.hasAttribute('target') || this.getAttribute('target').value === '') return; if (!this.hasAttribute('target') || this.getAttribute('target').value === '') return;
this.prevTab
this.allTabs
this.activeTab
this.isTab = false
this.target = this.getAttribute('target') this.target = this.getAttribute('target')
if (this.hasAttribute('variant') && this.getAttribute('variant') === 'tab') {
this.isTab = true
}
this.tabSlot.addEventListener('slotchange', () => { this.tabSlot.addEventListener('slotchange', () => {
this.tabSlot.assignedElements().forEach((tab, index) => { this.allTabs = this.tabSlot.assignedElements();
tab.setAttribute('rank', index) this.allTabs.forEach((tab, index) => {
tab.dataset.index = index
}) })
}) })
this.allTabs = this.tabSlot.assignedElements();
this.tabSlot.addEventListener('click', e => { this.addEventListener('click', this.handleClick)
if (e.target === this.prevTab || !e.target.closest('sm-tab')) document.addEventListener(`switchedpanel${this.target}`, this.handlePanelChange)
return
if (this.prevTab)
this.prevTab.classList.remove('active')
e.target.classList.add('active')
e.target.scrollIntoView({
behavior: 'smooth',
block: 'nearest',
inline: 'center'
})
this.moveIndiactor(e.target.getBoundingClientRect())
this.sendDetails(e.target)
this.prevTab = e.target;
this.activeTab = e.target;
})
let resizeObserver = new ResizeObserver(entries => { let resizeObserver = new ResizeObserver(entries => {
entries.forEach((entry) => { entries.forEach((entry) => {
if (this.prevTab) { if (this.prevTab) {
@ -181,7 +192,7 @@ customElements.define('sm-tab-header', class extends HTMLElement {
this.allTabs[0].classList.add('active') this.allTabs[0].classList.add('active')
let tabDimensions = this.allTabs[0].getBoundingClientRect(); let tabDimensions = this.allTabs[0].getBoundingClientRect();
this.moveIndiactor(tabDimensions) this.moveIndiactor(tabDimensions)
this.sendDetails(this.allTabs[0]) this.fireEvent(0)
this.prevTab = this.tabSlot.assignedElements()[0]; this.prevTab = this.tabSlot.assignedElements()[0];
this.activeTab = this.prevTab; this.activeTab = this.prevTab;
} }
@ -192,6 +203,10 @@ customElements.define('sm-tab-header', class extends HTMLElement {
}) })
observer.observe(this) observer.observe(this)
} }
disconnectedCallback() {
this.removeEventListener('click', this.handleClick)
document.removeEventListener(`switchedpanel${this.target}`, this.handlePanelChange)
}
}) })
// tab // tab
@ -280,21 +295,27 @@ smTabPanels.innerHTML = `
display: flex; display: flex;
width: 100%; width: 100%;
height: 100%; height: 100%;
overflow: hidden auto; overflow: hidden;
scroll-snap-type: x mandatory;
content-visibility: auto;
} }
slot::slotted(.hide-completely){ ::slotted(*){
display: none; min-width: 100%;
scroll-snap-align: center;
} }
@media (hover: none){ @media (any-hover: none) {
.tab-header::-webkit-scrollbar-track { .panel-container{
-webkit-box-shadow: none !important; overflow-x: auto;
background-color: transparent !important; scrollbar-width: none;
} }
.tab-header::-webkit-scrollbar { .container {
overflow-y: scroll;
}
::-webkit-scrollbar {
width: 0;
height: 0; height: 0;
background-color: transparent;
} }
} }
</style> </style>
<div part="panel-container" class="panel-container"> <div part="panel-container" class="panel-container">
<slot>Nothing to see here.</slot> <slot>Nothing to see here.</slot>
@ -307,109 +328,56 @@ customElements.define('sm-tab-panels', class extends HTMLElement {
this.attachShadow({ this.attachShadow({
mode: 'open' mode: 'open'
}).append(smTabPanels.content.cloneNode(true)) }).append(smTabPanels.content.cloneNode(true))
this.isTransitioning = false
this.panelContainer = this.shadowRoot.querySelector('.panel-container');
this.panelSlot = this.shadowRoot.querySelector('slot'); this.panelSlot = this.shadowRoot.querySelector('slot');
this.handleTabChange = this.handleTabChange.bind(this)
}
handleTabChange(e) {
this.isTransitioning = true
this.panelContainer.scrollTo({
left: this.allPanels[e.detail.index].getBoundingClientRect().left - this.panelContainer.getBoundingClientRect().left + this.panelContainer.scrollLeft,
behavior: 'smooth'
})
setTimeout(() => {
this.isTransitioning = false
}, 300);
}
fireEvent(index) {
this.dispatchEvent(
new CustomEvent(`switchedpanel${this.id}`, {
bubbles: true,
detail: {
index: parseInt(index)
}
})
)
} }
connectedCallback() { connectedCallback() {
//animations
let flyInLeft = [{
opacity: 0,
transform: 'translateX(-1rem)'
},
{
opacity: 1,
transform: 'none'
}
],
flyInRight = [{
opacity: 0,
transform: 'translateX(1rem)'
},
{
opacity: 1,
transform: 'none'
}
],
flyOutLeft = [{
opacity: 1,
transform: 'none'
},
{
opacity: 0,
transform: 'translateX(-1rem)'
}
],
flyOutRight = [{
opacity: 1,
transform: 'none'
},
{
opacity: 0,
transform: 'translateX(1rem)'
}
],
animationOptions = {
duration: 300,
fill: 'forwards',
easing: 'ease'
}
this.prevPanel
this.allPanels
this.previousRank
this.panelSlot.addEventListener('slotchange', () => { this.panelSlot.addEventListener('slotchange', () => {
this.panelSlot.assignedElements().forEach((panel) => { this.allPanels = this.panelSlot.assignedElements()
panel.classList.add('hide-completely') this.allPanels.forEach((panel, index) => {
panel.dataset.index = index
intersectionObserver.observe(panel)
}) })
}) })
this.allPanels = this.panelSlot.assignedElements() document.addEventListener(`switchedtab${this.id}`, this.handleTabChange)
this._targetBodyFlyRight = (targetBody) => {
targetBody.classList.remove('hide-completely')
targetBody.animate(flyInRight, animationOptions)
}
this._targetBodyFlyLeft = (targetBody) => {
targetBody.classList.remove('hide-completely')
targetBody.animate(flyInLeft, animationOptions)
}
document.addEventListener('switchtab', e => {
if (e.detail.target !== this.id)
return
if (this.prevPanel) { const intersectionObserver = new IntersectionObserver(entries => {
let targetBody = this.allPanels[e.detail.rank],
currentBody = this.prevPanel; entries.forEach(entry => {
if (this.previousRank < e.detail.rank) { if (!this.isTransitioning && entry.isIntersecting) {
if (currentBody && !targetBody) this.fireEvent(entry.target.dataset.index), 3000
currentBody.animate(flyOutLeft, animationOptions).onfinish = () => {
currentBody.classList.add('hide-completely')
}
else if (targetBody && !currentBody) {
this._targetBodyFlyRight(targetBody)
} else if (currentBody && targetBody) {
currentBody.animate(flyOutLeft, animationOptions).onfinish = () => {
currentBody.classList.add('hide-completely')
this._targetBodyFlyRight(targetBody)
}
}
} else {
if (currentBody && !targetBody)
currentBody.animate(flyOutRight, animationOptions).onfinish = () => {
currentBody.classList.add('hide-completely')
}
else if (targetBody && !currentBody) {
this._targetBodyFlyLeft(targetBody)
} else if (currentBody && targetBody) {
currentBody.animate(flyOutRight, animationOptions).onfinish = () => {
currentBody.classList.add('hide-completely')
this._targetBodyFlyLeft(targetBody)
}
}
} }
} else { })
this.allPanels[e.detail.rank].classList.remove('hide-completely') }, {
} threshold: 0.9
this.previousRank = e.detail.rank
this.prevPanel = this.allPanels[e.detail.rank];
}) })
} }
disconnectedCallback() {
intersectionObserver.disconnect()
document.removeEventListener(`switchedtab${this.id}`, this.handleTabChange)
}
}) })

File diff suppressed because one or more lines are too long

View File

@ -871,7 +871,7 @@
also identical. also identical.
</p> </p>
<h2>Interactive demo</h2> <h2>Interactive demo</h2>
<sm-select id="my_select"> <sm-select>
<sm-option value="1">option1</sm-option> <sm-option value="1">option1</sm-option>
<sm-option value="2">option2</sm-option> <sm-option value="2">option2</sm-option>
<sm-option value="3">option3</sm-option> <sm-option value="3">option3</sm-option>
@ -1055,10 +1055,8 @@
To start using SM Components To start using SM Components
</p> </p>
<sm-tab-header variant="tab" target="tab1"> <sm-tab-header variant="tab" target="tab1">
<sm-tab>inbox</sm-tab> <sm-tab>Audio</sm-tab>
<sm-tab>sent</sm-tab> <sm-tab>Video</sm-tab>
<sm-tab>draft</sm-tab>
<sm-tab>spam</sm-tab>
</sm-tab-header> </sm-tab-header>
<sm-tab-panels id="tab1"> <sm-tab-panels id="tab1">
<sm-panel> <sm-panel>
@ -1070,21 +1068,6 @@
flkmgklfmzkl<br> flkmgklfmzkl<br>
hbdsfhb hbdsfhb
</sm-panel> </sm-panel>
<sm-panel>
Lorem ipsum dolor, sit amet consectetur adipisicing elit. Facere neque incidunt aut laudantium,
quam
id,
molestiae vero blanditiis nisi alias in magnam autem quasi cumque eveniet qui cupiditate nam
corrupti?
</sm-panel>
<sm-panel>
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Blanditiis fuga ipsam, explicabo, eius
accusamus
consectetur ex sunt soluta voluptatem iure totam nulla expedita suscipit minus molestiae
similique
odio optio
quibusdam.
</sm-panel>
</sm-tab-panels> </sm-tab-panels>
</section> </section>
<section id="tags_input_page" class="page hide-completely"> <section id="tags_input_page" class="page hide-completely">

View File

@ -92,7 +92,7 @@
&lt;div&gt;Disabled switch&lt;/div&gt; &lt;div&gt;Disabled switch&lt;/div&gt;
&lt;/sm-radio&gt; &lt;/sm-radio&gt;
</code> </code>
</pre><h2>Attributes</h2><p>All the native HTML radio attributes are valid</p><section class="table"><div class="tr"><h4 class="table__heading">Attribute</h4><h4 class="table__heading">Description</h4></div><div class="tr"><div><span class="highlight">checked</span> (boolean)</div><p>If present, radio button is set to checked state as default.</p></div><div class="tr"><div><span class="highlight">disabled</span> (boolean)</div><p>If present radio button is set to disabled state. all the interactions are disabled</p></div><div class="tr"><div><span class="highlight">name</span> (string)</div><p>Can be used to group radio buttons with same name. only one radio button will be active in a group.</p></div><div class="tr"><div><span class="highlight">value</span> (string)</div><p>Sets value of radio button which can be accessed by value property with JS</p></div></section></section><section id="select_page" class="page hide-completely"><h1 class="page__title">Select</h1><p><span class="highlight">&lt;sm-select&gt;</span> is very similar to starndatd HTML5 select and it's markup stucture is also identical.</p><h2>Interactive demo</h2><sm-select id="my_select"><sm-option value="1">option1</sm-option><sm-option value="2">option2</sm-option><sm-option value="3">option3</sm-option></sm-select><pre> </pre><h2>Attributes</h2><p>All the native HTML radio attributes are valid</p><section class="table"><div class="tr"><h4 class="table__heading">Attribute</h4><h4 class="table__heading">Description</h4></div><div class="tr"><div><span class="highlight">checked</span> (boolean)</div><p>If present, radio button is set to checked state as default.</p></div><div class="tr"><div><span class="highlight">disabled</span> (boolean)</div><p>If present radio button is set to disabled state. all the interactions are disabled</p></div><div class="tr"><div><span class="highlight">name</span> (string)</div><p>Can be used to group radio buttons with same name. only one radio button will be active in a group.</p></div><div class="tr"><div><span class="highlight">value</span> (string)</div><p>Sets value of radio button which can be accessed by value property with JS</p></div></section></section><section id="select_page" class="page hide-completely"><h1 class="page__title">Select</h1><p><span class="highlight">&lt;sm-select&gt;</span> is very similar to starndatd HTML5 select and it's markup stucture is also identical.</p><h2>Interactive demo</h2><sm-select><sm-option value="1">option1</sm-option><sm-option value="2">option2</sm-option><sm-option value="3">option3</sm-option></sm-select><pre>
<code> <code>
&lt;sm-select&gt; &lt;sm-select&gt;
&lt;sm-option value="1"&gt;option1&lt;/sm-option&gt; &lt;sm-option value="1"&gt;option1&lt;/sm-option&gt;
@ -146,7 +146,7 @@
<code> <code>
&lt;sm-spinner&gt;&lt;/sm-spinner&gt; &lt;sm-spinner&gt;&lt;/sm-spinner&gt;
</code> </code>
</pre></section><section id="strip_select_page" class="page hide-completely"><h1 class="page__title">Strip select</h1><p>To start using SM Components</p><strip-select id="browse_category_selector" multiline><strip-option value="movie" selected>Movie</strip-option><strip-option value="tv series">TV series</strip-option><strip-option value="video">Video</strip-option><strip-option value="music">Music</strip-option></strip-select></section><section id="tabs_page" class="page hide-completely"><h1 class="page__title">Tabs</h1><p>To start using SM Components</p><sm-tab-header variant="tab" target="tab1"><sm-tab>inbox</sm-tab><sm-tab>sent</sm-tab><sm-tab>draft</sm-tab><sm-tab>spam</sm-tab></sm-tab-header><sm-tab-panels id="tab1"><sm-panel>gjdhnsrfijbgn<br>bdfjnbj</sm-panel><sm-panel>jadifjoaijdiajdo dosfighjoi<br>flkmgklfmzkl<br>hbdsfhb</sm-panel><sm-panel>Lorem ipsum dolor, sit amet consectetur adipisicing elit. Facere neque incidunt aut laudantium, quam id, molestiae vero blanditiis nisi alias in magnam autem quasi cumque eveniet qui cupiditate nam corrupti?</sm-panel><sm-panel>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Blanditiis fuga ipsam, explicabo, eius accusamus consectetur ex sunt soluta voluptatem iure totam nulla expedita suscipit minus molestiae similique odio optio quibusdam.</sm-panel></sm-tab-panels></section><section id="tags_input_page" class="page hide-completely"><h1 class="page__title">Tags input</h1><p>To start using SM Components</p><tags-input placeholder="Add tags..."></tags-input></section><section id="textarea_page" class="page hide-completely"><h1 class="page__title">Textarea</h1><p>To start using SM Components</p><sm-textarea placeholder="Add some text here..." rows="4"></sm-textarea></section><section id="text_field_page" class="page hide-completely"><h1 class="page__title">Text field</h1><p>To start using SM Components</p><text-field value="Double click me!"></text-field></section><section id="theme_toggle_page" class="page hide-completely"><h1 class="page__title">Theme toggle</h1><p>Use <span class="highlight">theme-toggle</span> to create light/dark theme easily with CSS variables.</p><p>When this is toggled by user the component changes the custom data attribute <span class="highlight">data-theme=""</span> on HTML body tag to either <span class="highlight">light</span> or <span class="highlight">dark</span></p><p>By default theme is set to OS level preferred-color-scheme ( supported by Android, iOS, Windows and MacOS ).</p><h2>Interactive demo</h2><theme-toggle></theme-toggle><h2>HTML</h2><pre> </pre></section><section id="strip_select_page" class="page hide-completely"><h1 class="page__title">Strip select</h1><p>To start using SM Components</p><strip-select id="browse_category_selector" multiline><strip-option value="movie" selected>Movie</strip-option><strip-option value="tv series">TV series</strip-option><strip-option value="video">Video</strip-option><strip-option value="music">Music</strip-option></strip-select></section><section id="tabs_page" class="page hide-completely"><h1 class="page__title">Tabs</h1><p>To start using SM Components</p><sm-tab-header variant="tab" target="tab1"><sm-tab>Audio</sm-tab><sm-tab>Video</sm-tab></sm-tab-header><sm-tab-panels id="tab1"><sm-panel>gjdhnsrfijbgn<br>bdfjnbj</sm-panel><sm-panel>jadifjoaijdiajdo dosfighjoi<br>flkmgklfmzkl<br>hbdsfhb</sm-panel></sm-tab-panels></section><section id="tags_input_page" class="page hide-completely"><h1 class="page__title">Tags input</h1><p>To start using SM Components</p><tags-input placeholder="Add tags..."></tags-input></section><section id="textarea_page" class="page hide-completely"><h1 class="page__title">Textarea</h1><p>To start using SM Components</p><sm-textarea placeholder="Add some text here..." rows="4"></sm-textarea></section><section id="text_field_page" class="page hide-completely"><h1 class="page__title">Text field</h1><p>To start using SM Components</p><text-field value="Double click me!"></text-field></section><section id="theme_toggle_page" class="page hide-completely"><h1 class="page__title">Theme toggle</h1><p>Use <span class="highlight">theme-toggle</span> to create light/dark theme easily with CSS variables.</p><p>When this is toggled by user the component changes the custom data attribute <span class="highlight">data-theme=""</span> on HTML body tag to either <span class="highlight">light</span> or <span class="highlight">dark</span></p><p>By default theme is set to OS level preferred-color-scheme ( supported by Android, iOS, Windows and MacOS ).</p><h2>Interactive demo</h2><theme-toggle></theme-toggle><h2>HTML</h2><pre>
<code> <code>
&lt;theme-toggle&gt;&lt;/theme-toggle&gt; &lt;theme-toggle&gt;&lt;/theme-toggle&gt;
</code> </code>