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.focusOut = this.focusOut.bind(this)
this.fireEvent = this.fireEvent.bind(this)
this.debounce = this.debounce.bind(this)
this.checkInput = this.checkInput.bind(this)
}
@ -339,15 +338,6 @@ customElements.define('sm-input',
});
this.dispatchEvent(event);
}
debounce(callback, wait){
let timeoutId = null;
return (...args) => {
window.clearTimeout(timeoutId);
timeoutId = window.setTimeout(() => {
callback.apply(null, args);
}, wait);
};
}
checkInput(e){
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) {
if (this.previousOption !== document.activeElement) {
this.value = document.activeElement.getAttribute('value')
this.selectedOptionText.textContent = this.value;
this.selectedOptionText.textContent = document.activeElement.textContent;
this.fireEvent()
if (this.previousOption) {
this.previousOption.classList.remove('check-selected')
@ -263,7 +263,7 @@ customElements.define('sm-select', class extends HTMLElement {
}
handleKeydown(e) {
if (e.target === this) {
if (e.code === 'ArrowDown') {
if (this.isOpen && e.code === 'ArrowDown') {
e.preventDefault()
this.availableOptions[0].focus()
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'
}).append(smTabHeader.content.cloneNode(true))
this.prevTab
this.allTabs
this.activeTab
this.indicator = this.shadowRoot.querySelector('.indicator');
this.tabSlot = this.shadowRoot.querySelector('slot');
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(
new CustomEvent("switchtab", {
new CustomEvent(`switchedtab${this.target}`, {
bubbles: true,
detail: {
target: this.target,
rank: parseInt(element.getAttribute('rank'))
index: parseInt(index)
}
})
)
}
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)`)
//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() {
if (!this.hasAttribute('target') || this.getAttribute('target').value === '') return;
this.prevTab
this.allTabs
this.activeTab
this.isTab = false
this.target = this.getAttribute('target')
if (this.hasAttribute('variant') && this.getAttribute('variant') === 'tab') {
this.isTab = true
}
this.tabSlot.addEventListener('slotchange', () => {
this.tabSlot.assignedElements().forEach((tab, index) => {
tab.setAttribute('rank', index)
this.allTabs = this.tabSlot.assignedElements();
this.allTabs.forEach((tab, index) => {
tab.dataset.index = index
})
})
this.allTabs = this.tabSlot.assignedElements();
this.tabSlot.addEventListener('click', e => {
if (e.target === this.prevTab || !e.target.closest('sm-tab'))
return
if (this.prevTab)
this.prevTab.classList.remove('active')
e.target.classList.add('active')
this.addEventListener('click', this.handleClick)
document.addEventListener(`switchedpanel${this.target}`, this.handlePanelChange)
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 => {
entries.forEach((entry) => {
if (this.prevTab) {
@ -181,7 +192,7 @@ customElements.define('sm-tab-header', class extends HTMLElement {
this.allTabs[0].classList.add('active')
let tabDimensions = this.allTabs[0].getBoundingClientRect();
this.moveIndiactor(tabDimensions)
this.sendDetails(this.allTabs[0])
this.fireEvent(0)
this.prevTab = this.tabSlot.assignedElements()[0];
this.activeTab = this.prevTab;
}
@ -192,6 +203,10 @@ customElements.define('sm-tab-header', class extends HTMLElement {
})
observer.observe(this)
}
disconnectedCallback() {
this.removeEventListener('click', this.handleClick)
document.removeEventListener(`switchedpanel${this.target}`, this.handlePanelChange)
}
})
// tab
@ -280,21 +295,27 @@ smTabPanels.innerHTML = `
display: flex;
width: 100%;
height: 100%;
overflow: hidden auto;
overflow: hidden;
scroll-snap-type: x mandatory;
content-visibility: auto;
}
slot::slotted(.hide-completely){
display: none;
::slotted(*){
min-width: 100%;
scroll-snap-align: center;
}
@media (hover: none){
.tab-header::-webkit-scrollbar-track {
-webkit-box-shadow: none !important;
background-color: transparent !important;
@media (any-hover: none) {
.panel-container{
overflow-x: auto;
scrollbar-width: none;
}
.tab-header::-webkit-scrollbar {
.container {
overflow-y: scroll;
}
::-webkit-scrollbar {
width: 0;
height: 0;
background-color: transparent;
}
}
}
</style>
<div part="panel-container" class="panel-container">
<slot>Nothing to see here.</slot>
@ -307,109 +328,56 @@ customElements.define('sm-tab-panels', class extends HTMLElement {
this.attachShadow({
mode: 'open'
}).append(smTabPanels.content.cloneNode(true))
this.isTransitioning = false
this.panelContainer = this.shadowRoot.querySelector('.panel-container');
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() {
//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.assignedElements().forEach((panel) => {
panel.classList.add('hide-completely')
this.allPanels = this.panelSlot.assignedElements()
this.allPanels.forEach((panel, index) => {
panel.dataset.index = index
intersectionObserver.observe(panel)
})
})
this.allPanels = this.panelSlot.assignedElements()
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
document.addEventListener(`switchedtab${this.id}`, this.handleTabChange)
if (this.prevPanel) {
let targetBody = this.allPanels[e.detail.rank],
currentBody = this.prevPanel;
if (this.previousRank < e.detail.rank) {
if (currentBody && !targetBody)
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)
}
}
const intersectionObserver = new IntersectionObserver(entries => {
entries.forEach(entry => {
if (!this.isTransitioning && entry.isIntersecting) {
this.fireEvent(entry.target.dataset.index), 3000
}
} else {
this.allPanels[e.detail.rank].classList.remove('hide-completely')
}
this.previousRank = e.detail.rank
this.prevPanel = this.allPanels[e.detail.rank];
})
}, {
threshold: 0.9
})
}
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.
</p>
<h2>Interactive demo</h2>
<sm-select id="my_select">
<sm-select>
<sm-option value="1">option1</sm-option>
<sm-option value="2">option2</sm-option>
<sm-option value="3">option3</sm-option>
@ -1055,10 +1055,8 @@
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>Audio</sm-tab>
<sm-tab>Video</sm-tab>
</sm-tab-header>
<sm-tab-panels id="tab1">
<sm-panel>
@ -1070,21 +1068,6 @@
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">

View File

@ -92,7 +92,7 @@
&lt;div&gt;Disabled switch&lt;/div&gt;
&lt;/sm-radio&gt;
</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>
&lt;sm-select&gt;
&lt;sm-option value="1"&gt;option1&lt;/sm-option&gt;
@ -146,7 +146,7 @@
<code>
&lt;sm-spinner&gt;&lt;/sm-spinner&gt;
</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>
&lt;theme-toggle&gt;&lt;/theme-toggle&gt;
</code>