Updated tabs to work with multiple tabs on same page and nested tabs

Updated modal to be able to close other modals when opening a second modal
updated group in docs
This commit is contained in:
Yohn 2025-01-11 00:03:47 -05:00
parent 8533005d9b
commit 857d526b91
3 changed files with 65 additions and 96 deletions

View file

@ -690,16 +690,6 @@
<li>Colors New</li> <li>Colors New</li>
</ul> </ul>
</details> </details>
<details class="dropdown">
<summary class="contrast">Layout</summary>
<ul>
<li><a class="load-page" href="data/Container.json">Container</a></li>
<li><a class="load-page" href="data/Landmarks.json">Landmarks &amp; Section</a></li>
<li><a class="load-page" href="data/Grid.json">Grid</a></li>
<li><a class="load-page" href="data/Row.json">Row</a></li>
<li><a class="load-page" href="data/Overflow.json">Overflow</a></li>
</ul>
</details>
<details class="dropdown"> <details class="dropdown">
<summary>Content</summary> <summary>Content</summary>
<ul> <ul>
@ -708,40 +698,6 @@
<li><a class="load-page" href="data/Table.json">Table</a></li> <li><a class="load-page" href="data/Table.json">Table</a></li>
</ul> </ul>
</details> </details>
<details class="dropdown">
<summary>Form</summary>
<ul>
<li><a class="load-page" href="data/Overview.json">Overview</a></li>
<li><a class="load-page" href="data/Button.json">Button</a></li>
<li><a class="load-page" href="data/Checkboxes.json">Checkboxes</a></li>
<li><a class="load-page" href="data/File.json">File</a></li>
<li><a class="load-page" href="data/Floating.json">Floating Labels</a></li>
<li><a class="load-page" href="data/Input.json">Input</a></li>
<li><a class="load-page" href="data/Select.json">Select</a></li>
<li><a class="load-page" href="data/Switch.json">Switch</a></li>
<li><a class="load-page" href="data/Radios.json">Radios</a></li>
<li><a class="load-page" href="data/Range.json">Range</a></li>
<li><a class="load-page" href="data/Textarea.json">Textarea</a></li>
<li><a class="load-page" href="data/Validation.json">Validation</a></li>
</ul>
</details>
<details class="dropdown">
<summary>Components</summary>
<ul>
<li><a class="load-page" href="data/Accordion.json">Accordion</a></li>
<li><a class="load-page" href="data/Card.json">Card</a></li>
<li><a class="load-page" href="data/Dropdown.json">Dropdown</a></li>
<li><a class="load-page" href="data/Group.json">Group</a></li>
<li><a class="load-page" href="data/Loading.json">Loading</a></li>
<li><a class="load-page" href="data/Modal.json">Modal</a></li>
<li><a class="load-page" href="data/Nav.json">Nav</a></li>
<li><a class="load-page" href="data/Popover.json">Popover</a></li>
<li><a class="load-page" href="data/Progress.json">Progress</a></li>
<li><a class="load-page" href="data/Tabs.json">Tabs</a></li>
<li><a class="load-page" href="data/Timeline.json">Timeline</a></li>
<li><a class="load-page" href="data/Tooltip.json">Tooltip</a></li>
</ul>
</details>
</div> </div>
<hr> <hr>
<h3>form > [role=group]</h3> <h3>form > [role=group]</h3>
@ -767,22 +723,20 @@
</div> </div>
</form> </form>
<hr> <hr>
<h3>fieldset[role=group] with > legend</h3> <h3>form > [role=group] > label + input + select</h3>
<fieldset role="group"> <form action="javascript:void(0);" novalidate>
<legend>Sort By</legend> <div role="group">
<button class="outline secondary">Availability</button> <label for="fl3-search">Search:</label>
<button class="outline">Relative Profit</button> <input name="fl3-search" type="text" placeholder="Find" />
<button class="outline secondary">Absolute Profit</button> <label for="fl3-section">In:</label>
</fieldset> <select id="fl3-section" name="fl3-section">
<hr> <option value="Customers">Customers</option>
<h3>div[role=group] with > legend</h3> <option value="Employees">Employees</option>
<div role="group"> <option value="Vendors">Vendors</option>
<legend>Sort By</legend> </select>
<button class="outline secondary">Availability</button> <input type="submit" value="Save" />
<button>Relative Profit</button> </div>
<button class="outline secondary">Absolute Profit</button> </form>
</div>
</div> </div>
</article> </article>
<!-- ./ Group --> <!-- ./ Group -->

View file

@ -2,9 +2,10 @@
* Modal * Modal
* *
* Pico.css - https://picocss.com * Pico.css - https://picocss.com
* Copyright 2019-2024 - Licensed under MIT * Copyright 2019-2025 - Licensed under MIT
* Modified by Yohn https://github.com/Yohn/PicoCSS
*/ */
//document.addEventListener("DOMContentLoaded", () => { document.addEventListener("DOMContentLoaded", () => {
// Config // Config
const isOpenClass = "modal-is-open"; const isOpenClass = "modal-is-open";
const openingClass = "modal-is-opening"; const openingClass = "modal-is-opening";
@ -18,7 +19,15 @@
event.preventDefault(); event.preventDefault();
const modal = document.getElementById(event.currentTarget.dataset.target); const modal = document.getElementById(event.currentTarget.dataset.target);
if (!modal) return; if (!modal) return;
modal && (modal.open ? closeModal(modal) : openModal(modal)); if(event.currentTarget.dataset.close) {
const modalClose = document.getElementById(event.currentTarget.dataset.close);
if(modalClose){
closeModal(modalClose);
setTimeout(() => modal && (modal.open ? closeModal(modal) : openModal(modal)), animationDuration);
}
} else {
modal && (modal.open ? closeModal(modal) : openModal(modal));
}
}; };
// Open modal // Open modal
@ -73,4 +82,4 @@
const isScrollbarVisible = () => { const isScrollbarVisible = () => {
return document.body.scrollHeight > screen.height; return document.body.scrollHeight > screen.height;
}; };
//}) })

View file

@ -29,76 +29,82 @@ document.addEventListener("DOMContentLoaded", () => {
class PicoTabs { class PicoTabs {
constructor(tabListContainerSelector) { constructor(tabListContainerSelector) {
this.tabListContainer = document.querySelector(tabListContainerSelector); this.tabLists = document.querySelectorAll(tabListContainerSelector);
// Check if tablist element exists on the page
if (!this.tabListContainer) { // Proceed only if tablists are found
console.warn( if (this.tabLists.length === 0) {
`No element with ${tabListContainerSelector} found on the page.` console.warn(`No elements with ${tabListContainerSelector} found on the page.`);
);
return; return;
} }
this.tabs = this.tabListContainer.querySelectorAll('[role="tab"]'); this.tabLists.forEach((tabList) => {
this.panels = document.querySelectorAll('[role="tabpanel"]'); const tabs = Array.from(tabList.querySelectorAll('[role="tab"]'));
const panels = Array.from(tabList.querySelectorAll('[role="tabpanel"]'));
// Proceed only if tabs and panels are found // Filter out nested tabs and panels
if (this.tabs.length === 0 || this.panels.length === 0) { const rootTabs = tabs.filter((tab) => tab.closest(tabListContainerSelector) === tabList);
console.warn("No tabs or panels found, initialization aborted."); const rootPanels = panels.filter((panel) => panel.closest(tabListContainerSelector) === tabList);
return;
}
this.init(); // Proceed only if root tabs and panels are found
if (rootTabs.length === 0 || rootPanels.length === 0) {
console.warn("No root tabs or panels found in a tablist, skipping initialization.");
return;
}
this.init(tabList, rootTabs, rootPanels);
});
} }
init() { init(tabList, tabs, panels) {
this.tabs.forEach((tab, index) => { tabs.forEach((tab, index) => {
tab.addEventListener("click", () => this.activateTab(index)); tab.addEventListener("click", () => this.activateTab(tabs, panels, index));
tab.addEventListener("keydown", (e) => this.handleKeyDown(e, index)); tab.addEventListener("keydown", (e) => this.handleKeyDown(e, tabs, panels, index));
}); });
} }
// Activate a tab and corresponding panel // Activate a tab and corresponding panel
activateTab(index) { activateTab(tabs, panels, index) {
// Reset all tabs and panels // Reset all tabs and panels within the current tablist
this.tabs.forEach((tab, i) => { tabs.forEach((tab, i) => {
tab.setAttribute("aria-selected", "false"); tab.setAttribute("aria-selected", "false");
tab.setAttribute("tabindex", "-1"); tab.setAttribute("tabindex", "-1");
this.panels[i].setAttribute("hidden", "true"); panels[i].setAttribute("hidden", "true");
}); });
// Activate the specified tab // Activate the specified tab
this.tabs[index].setAttribute("aria-selected", "true"); tabs[index].setAttribute("aria-selected", "true");
this.tabs[index].setAttribute("tabindex", "0"); tabs[index].setAttribute("tabindex", "0");
this.panels[index].removeAttribute("hidden"); panels[index].removeAttribute("hidden");
// Focus the activated tab // Focus the activated tab
this.tabs[index].focus(); tabs[index].focus();
} }
// Handle keyboard navigation // Handle keyboard navigation
handleKeyDown(event, currentIndex) { handleKeyDown(event, tabs, panels, currentIndex) {
switch (event.key) { switch (event.key) {
case "ArrowLeft": case "ArrowLeft":
event.preventDefault(); event.preventDefault();
this.activateTab((currentIndex - 1 + this.tabs.length) % this.tabs.length); this.activateTab(tabs, panels, (currentIndex - 1 + tabs.length) % tabs.length);
break; break;
case "ArrowRight": case "ArrowRight":
event.preventDefault(); event.preventDefault();
this.activateTab((currentIndex + 1) % this.tabs.length); this.activateTab(tabs, panels, (currentIndex + 1) % tabs.length);
break; break;
case "Home": case "Home":
event.preventDefault(); event.preventDefault();
this.activateTab(0); this.activateTab(tabs, panels, 0);
break; break;
case "End": case "End":
event.preventDefault(); event.preventDefault();
this.activateTab(this.tabs.length - 1); this.activateTab(tabs, panels, tabs.length - 1);
break; break;
default: default:
break; break;
} }
} }
} }
//document.addEventListener("DOMContentLoaded", () => { //document.addEventListener("DOMContentLoaded", () => {
// new PicoTabs('[role="tablist"]'); // new PicoTabs('[role="tablist"]');
//}) //});