maverick-wave 3.10.0 → 4.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. package/.claude/skills/maverick-wave/SKILL.md +62 -30
  2. package/.claude/skills/maverick-wave/examples/angular-form.md +1 -1
  3. package/.claude/skills/maverick-wave/examples/angular-services.md +15 -8
  4. package/.claude/skills/maverick-wave/examples/static-landing-page.md +4 -4
  5. package/.claude/skills/maverick-wave/references/components.md +416 -27
  6. package/.claude/skills/maverick-wave/references/forms.md +8 -4
  7. package/.claude/skills/maverick-wave/references/javascript.md +32 -18
  8. package/.claude/skills/maverick-wave/references/layout.md +48 -3
  9. package/.claude/skills/maverick-wave/references/theming.md +34 -24
  10. package/CHANGELOG.md +56 -0
  11. package/index.html +25 -0
  12. package/maverick-wave.min.css +2 -2
  13. package/maverick-wave.min.js +1 -1
  14. package/package.json +2 -2
  15. package/src/js/main.js +314 -20
  16. package/src/partials/accordions-container.html +2 -2
  17. package/src/partials/button-bar-container.html +4 -2
  18. package/src/partials/buttons-container.html +35 -0
  19. package/src/partials/calendar-container.html +205 -0
  20. package/src/partials/cards-container.html +43 -0
  21. package/src/partials/documentation-container.html +3 -0
  22. package/src/partials/form-container.html +1 -1
  23. package/src/partials/get-started-container.html +2 -2
  24. package/src/partials/kanban-container.html +680 -715
  25. package/src/partials/modals-container.html +5 -5
  26. package/src/partials/pagination-container.html +50 -13
  27. package/src/partials/segmented-container.html +66 -0
  28. package/src/partials/tables-container.html +96 -24
  29. package/src/partials/tabs-container.html +16 -6
  30. package/src/partials/tags-container.html +15 -0
  31. package/src/partials/timelines-container.html +2 -2
  32. package/src/partials/utilities-container.html +81 -0
  33. package/src/scss/abstracts/_mixins.scss +34 -0
  34. package/src/scss/abstracts/_variables.scss +6 -2
  35. package/src/scss/base/_base.scss +21 -0
  36. package/src/scss/components/_accordions.scss +2 -0
  37. package/src/scss/components/_alerts.scss +5 -19
  38. package/src/scss/components/_button-bar.scss +6 -0
  39. package/src/scss/components/_buttons.scss +67 -0
  40. package/src/scss/components/_calendar.scss +290 -0
  41. package/src/scss/components/_content-slider.scss +1 -0
  42. package/src/scss/components/_index.scss +2 -0
  43. package/src/scss/components/_kanban.scss +2 -6
  44. package/src/scss/components/_modals.scss +15 -4
  45. package/src/scss/components/_pagination.scss +68 -64
  46. package/src/scss/components/_segmented.scss +85 -0
  47. package/src/scss/components/_tables.scss +16 -0
  48. package/src/scss/components/_tabs.scss +15 -0
  49. package/src/scss/components/_tags.scss +16 -0
  50. package/src/scss/components/_theme-toggle.scss +2 -0
  51. package/src/scss/components/_timelines.scss +3 -0
  52. package/src/scss/form-elements/_form.scss +13 -7
  53. package/src/scss/layout/_header.scss +3 -0
  54. package/src/scss/layout/_main.scss +5 -1
  55. package/src/scss/layout/_section.scss +1 -1
  56. package/src/scss/utilities/_accessibility.scss +14 -0
  57. package/src/scss/utilities/_flex.scss +17 -0
  58. package/src/scss/utilities/_index.scss +2 -0
  59. package/src/scss/utilities/_text.scss +17 -5
  60. package/src/scss/utilities/_touch-targets.scss +54 -0
@@ -1 +1 @@
1
- !function(){"use strict";function e(){document.querySelectorAll(".color-swatch").forEach(e=>{const t=function(e){if(!e||"transparent"===e)return"#000000";const t=e=>Math.max(0,Math.min(255,Math.round(e))).toString(16).padStart(2,"0"),n=e.match(/color\(srgb\s+([\d.]+)\s+([\d.]+)\s+([\d.]+)(?:\s*\/\s*([\d.]+))?\)/);if(n){const e="#"+t(255*n[1])+t(255*n[2])+t(255*n[3]),c=void 0===n[4]?1:parseFloat(n[4]);return(c<1?`${e} / ${c}`:e).toUpperCase()}const c=e.match(/rgba?\((\d+),\s*(\d+),\s*(\d+)(?:,\s*([\d.]+))?\)/);if(!c)return e;const o="#"+t(c[1])+t(c[2])+t(c[3]),a=void 0===c[4]?1:parseFloat(c[4]);return(a<1?`${o} / ${a}`:o).toUpperCase()}(window.getComputedStyle(e).backgroundColor),n=e.parentElement.querySelector(".mw-text-muted");n&&(n.textContent=t)})}function t(e){const t=Array.from(e.querySelectorAll(".mw-kanban-column")),n=e.querySelector(".mw-kanban-composer"),c=e.querySelector(".mw-kanban-card-template"),o=e.dataset.kanbanPrefix||"MW",a=n.querySelector(".mw-kanban-composer-title"),r=n.querySelector(".mw-kanban-composer-text"),s=n.querySelector(".mw-kanban-composer-priority"),l=n.querySelector(".mw-kanban-composer-assignee");let i=null;function d(){t.forEach(function(e,n){const c=e.querySelectorAll(".mw-kanban-card"),o=e.querySelector(".mw-kanban-count");o&&(o.textContent=c.length),e.querySelectorAll("[data-kanban-move]").forEach(function(e){const c=n+parseInt(e.dataset.kanbanMove,10);e.disabled=c<0||c>=t.length})})}function u(e,t){const n=e.querySelector(t);return n?n.textContent.replace(/\s+/g," ").trim():""}function m(e,t){f(),i=t||null,a.value=t?u(t,".mw-kanban-card-title"):"",r.value=t?u(t,".mw-kanban-card-text"):"",s.value=t?function(e){const t=e.querySelector(".mw-card-ribbon");if(!t)return"";const n=Array.from(t.classList).find(function(e){return 0===e.indexOf("mw-card-addon-")});return n?n.replace("mw-card-addon-",""):""}(t):"",l.value=t?function(e){const t=e.querySelector(".mw-avatar-initials");return t?t.textContent.trim():""}(t):"",t?(t.classList.add("mw-kanban-editing"),t.before(n)):e.querySelector(".mw-kanban-column-body").prepend(n),n.classList.add("mw-active"),a.focus()}function f(){n.classList.remove("mw-active"),i&&i.classList.remove("mw-kanban-editing"),i=null}function h(){const t=a.value.trim();if(!t)return void a.focus();const u=i||c.content.firstElementChild.cloneNode(!0);if(u.querySelector(".mw-kanban-card-title").textContent=t,u.querySelector(".mw-kanban-card-text").textContent=r.value.trim(),function(e,t){const n=e.querySelector(".mw-card-ribbon");if(n&&n.remove(),!t||!t.value)return;const c=document.createElement("div");c.className="mw-card-ribbon mw-card-addon-"+t.value,c.textContent=t.textContent,e.prepend(c)}(u,s.selectedOptions[0]),function(e,t){const n=e.querySelector(".mw-kanban-card-actions"),c=n.querySelector(".mw-avatar");if(!t)return void(c&&c.remove());const o=c||document.createElement("div");o.className="mw-avatar mw-avatar-xs mw-avatar-initials",o.textContent=t,c||n.prepend(o)}(u,l.value),!i){const t=function(){const t=Array.from(e.querySelectorAll(".mw-kanban-card-id")).map(function(e){return parseInt(e.textContent.split("-").pop(),10)||0});return o+"-"+(Math.max(0,...t)+1)}();u.classList.add("mw-kanban-card-in"),u.querySelector(".mw-kanban-card-id").textContent=t,u.querySelectorAll("[aria-label]").forEach(function(e){e.setAttribute("aria-label",e.getAttribute("aria-label").replace(/[A-Z]+-\d+/,t))}),n.before(u)}f(),d()}e.addEventListener("click",function(e){const n=e.target.closest("[data-kanban-move]");if(n){if(function(e,n){const c=e.closest(".mw-kanban-column"),o=t[t.indexOf(c)+n];o&&(o.querySelector(".mw-kanban-column-body").appendChild(e),d())}(n.closest(".mw-kanban-card"),parseInt(n.dataset.kanbanMove,10)),n.disabled){const e=n.parentElement.querySelector("[data-kanban-move]:not(:disabled)");e&&e.focus()}return}const c=e.target.closest(".mw-kanban-edit");if(c){const e=c.closest(".mw-kanban-card");return void m(e.closest(".mw-kanban-column"),e)}const o=e.target.closest(".mw-kanban-delete");if(o){const e=o.closest(".mw-kanban-card");return e===i&&f(),e.remove(),void d()}const a=e.target.closest(".mw-kanban-add");a?m(a.closest(".mw-kanban-column"),null):e.target.closest(".mw-kanban-composer-cancel")&&f()}),n.addEventListener("submit",function(e){e.preventDefault(),h()}),n.addEventListener("keydown",function(e){"Escape"===e.key&&f()}),d()}document.addEventListener("DOMContentLoaded",function(){document.querySelectorAll(".mw-gallery").forEach(e=>{const t=e.closest(".mw-gallery-container")||e.parentElement;t&&function(e,t){const n=t.querySelector(".mw-gallery-track");if(!n||!n.children.length)return;const c=n.children,o=e.querySelector(".mw-gallery-dots"),a=e.querySelector(".mw-gallery-desc"),r=t.querySelector(".mw-gallery-navi-prev"),s=t.querySelector(".mw-gallery-navi-next");let l=0;function i(e){const t=c.length;l=(e+t)%t,n.style.transform=`translateX(-${100*l}%)`,o&&o.querySelectorAll(".mw-gallery-dot").forEach((e,t)=>{e.classList.toggle("mw-active",t===l)}),a&&(a.textContent=c[l].dataset.desc||"")}if(o)for(let e=0;e<c.length;e++){const t=document.createElement("span");t.className="mw-gallery-dot"+(0===e?" mw-active":""),t.addEventListener("click",()=>i(e)),o.appendChild(t)}r&&r.addEventListener("click",()=>i(l-1)),s&&s.addEventListener("click",()=>i(l+1));let d=0;n.addEventListener("touchstart",e=>d=e.touches[0].clientX),n.addEventListener("touchend",e=>{const t=e.changedTouches[0].clientX-d;t>50&&i(l-1),t<-50&&i(l+1)}),i(0)}(t,e)}),function(){const t=document.querySelector(".mw-theme-toggle");if(!t)return;const n=document.body,c=t.querySelector(".mw-theme-toggle-slider i"),o=getComputedStyle(document.documentElement).getPropertyValue("--mw-internal-theme-mode").trim()||"switchable";if("switchable"!==o)return console.log(`Theme mode fixed to: ${o}. Disabling toggle.`),c&&(c.className="light"===o?"fas fa-sun":"fas fa-moon"),"light"===o?t.classList.add("active"):t.classList.remove("active"),t.style.opacity="0.4",t.style.pointerEvents="none",t.style.cursor="default",t.setAttribute("aria-disabled","true"),localStorage.removeItem("mw-theme"),void("dark"===o&&n.classList.remove("mw-theme-light"));let a="light"===localStorage.getItem("mw-theme");const r=e=>{n.classList.toggle("mw-theme-light",e),t.classList.toggle("active",e),c&&(c.className=e?"fas fa-sun":"fas fa-moon")};r(a),t.addEventListener("click",()=>{a=!a,r(a),localStorage.setItem("mw-theme",a?"light":"dark"),setTimeout(e,400)})}(),e(),document.querySelectorAll(".mw-accordion-header").forEach(e=>{e.addEventListener("click",function(){this.classList.toggle("active");const e=this.nextElementSibling;e&&e.classList.toggle("active")})}),function(){const e=document.querySelector(".mw-menu-btn"),t=document.querySelector(".mw-navbar");if(!e||!t)return;function n(){e.classList.remove("open"),t.classList.remove("open")}function c(n){n.preventDefault(),n.stopPropagation(),e.classList.toggle("open"),t.classList.toggle("open")}e.addEventListener("click",c),e.addEventListener("touchstart",c,{passive:!1}),document.addEventListener("click",function(c){t.classList.contains("open")&&(t.contains(c.target)||e.contains(c.target)||n())}),document.addEventListener("keydown",function(e){"Escape"===e.key&&n()})}(),function(){const e=document.querySelectorAll(".mw-progress-fill");if(!e.length)return;const t=new IntersectionObserver((e,t)=>{e.forEach(e=>{if(!e.isIntersecting)return;const n=e.target,c=n.dataset.value||0;n.style.width=c+"%",t.unobserve(n)})},{root:null,threshold:.2});e.forEach(e=>t.observe(e))}(),document.querySelectorAll('a[href^="#"]').forEach(e=>{e.addEventListener("click",function(e){const t=this.getAttribute("href");if("#"===t)return;if(!document.querySelector(t))return;const n=document.querySelector(".mw-menu-btn"),c=document.querySelector(".mw-navbar");n&&c&&(n.classList.remove("open"),c.classList.remove("open"))})}),function(){const e=document.querySelectorAll("section[id]"),t=document.querySelectorAll(".mw-navbar-link");if(0===e.length||0===t.length)return;window.addEventListener("scroll",function(e,t){let n;return function(){const c=this,o=arguments;clearTimeout(n),n=setTimeout(()=>e.apply(c,o),t)}}(function(){let n="";e.forEach(e=>{const t=e.offsetTop-100,c=e.clientHeight;scrollY>=t&&scrollY<t+c&&(n=e.getAttribute("id"))}),t.forEach(e=>{e.classList.remove("active");const t=e.getAttribute("href");if(t){const c=t.indexOf("#");if(-1!==c){t.substring(c+1)===n&&e.classList.add("active")}}})},100))}(),document.querySelectorAll(".mw-tabs-nav-item").forEach(e=>{e.addEventListener("click",function(){const e=this.closest(".mw-tabs");if(!e)return;e.querySelectorAll(".mw-tabs-nav-item").forEach(e=>{e.classList.remove("active")}),this.classList.add("active");const t=this.getAttribute("data-tab");if(!t)return;e.querySelectorAll(".mw-tabs-panel").forEach(e=>{e.classList.remove("active")});const n=document.getElementById(t);n&&n.classList.add("active")})}),document.querySelectorAll(".mw-alert-close").forEach(e=>{e.addEventListener("click",function(){const e=this.closest(".mw-alert");e&&(e.classList.add("mw-alert-closing"),setTimeout(()=>{e.classList.add("mw-alert-closed")},300))})}),function(){const e=document.querySelector(".mw-localhost-indicator-activated"),t=document.querySelector(".mw-header");if(e){if("localhost"===window.location.hostname||"127.0.0.1"===window.location.hostname||window.location.hostname.includes("192.168.")){const e=document.createElement("div");e.className="mw-localhost-indicator-pulse",t.prepend(e)}}}(),document.querySelectorAll(".mw-slider-container").forEach(e=>{const t=e.querySelector(".mw-slider"),n=e.querySelector(".mw-slider-value");if(!t||!n)return;const c=()=>{const e=Number(t.value),c=Number(t.max)||100,o=Math.round(e/c*100);t.style.setProperty("--value",o+"%"),n.classList.contains("mw-slider-numeric")?n.setAttribute("data-value",e):n.setAttribute("data-value",o)};t.addEventListener("input",c),c()}),document.querySelectorAll(".mw-modal-close").forEach(e=>{e.addEventListener("click",function(){const e=this.closest(".mw-modal-overlay");e&&e.classList.remove("mw-modal-open")})}),function(){const e=document.getElementById("login-button");e&&e.addEventListener("click",function(){const e=this.querySelector("i");e.classList.contains("fa-lock")?(e.classList.remove("fa-lock"),e.classList.add("fa-lock-open")):(e.classList.remove("fa-lock-open"),e.classList.add("fa-lock"))})}(),document.querySelectorAll(".mw-image-slider").forEach(e=>{const t=e.querySelectorAll(".mw-image-slider-overlay-image"),n=e.querySelectorAll("button[data-index]");if(!t.length||!n.length)return;let c=0;function o(){t.forEach(e=>{const t=parseInt(e.dataset.index);e.classList.toggle("active",t===c)}),n.forEach(e=>{const t=parseInt(e.dataset.index);e.classList.toggle("active",t===c)})}function a(e){c=e,o()}n.forEach(e=>{e.addEventListener("click",()=>{a(parseInt(e.dataset.index))})}),o()}),document.querySelectorAll(".mw-item-list-checkbox, .mw-item-list-checkbox-scroll").forEach(e=>{e.querySelectorAll("li").forEach(e=>{const t=e.querySelector('input[type="checkbox"]'),n=e.querySelector(".mw-checkbox");t&&n&&(t.checked&&e.classList.add("mw-selected"),e.addEventListener("click",function(e){e.target!==t&&e.target.closest(".mw-checkbox")!==n&&toggleCheckbox(this)}),t.addEventListener("change",function(){const e=this.closest("li");this.checked?e.classList.add("mw-selected"):e.classList.remove("mw-selected"),e.dispatchEvent(new CustomEvent("checkboxToggle",{detail:{checked:this.checked,item:e}}))}),n.addEventListener("click",function(e){setTimeout(()=>{const e=this.closest("li");this.querySelector('input[type="checkbox"]').checked?e.classList.add("mw-selected"):e.classList.remove("mw-selected")},0)}))})}),document.addEventListener("checkboxToggle",function(e){console.log("Checkbox toggled:",e.detail.checked,e.detail.item)}),document.querySelectorAll(".mw-kanban").forEach(t)}),window.toggleCheckbox=function(e){const t=e.querySelector('input[type="checkbox"]');if(!t)return;const n=t.checked;t.checked=!n,t.checked?e.classList.add("mw-selected"):e.classList.remove("mw-selected"),e.dispatchEvent(new CustomEvent("checkboxToggle",{detail:{checked:t.checked,item:e}}))}}();
1
+ !function(){"use strict";function e(e,t){e&&(e.classList.toggle("mw-active",t),t||e.classList.remove("active"))}function t(){document.querySelectorAll(".color-swatch").forEach(e=>{const t=function(e){if(!e||"transparent"===e)return"#000000";const t=e=>Math.max(0,Math.min(255,Math.round(e))).toString(16).padStart(2,"0"),n=e.match(/color\(srgb\s+([\d.]+)\s+([\d.]+)\s+([\d.]+)(?:\s*\/\s*([\d.]+))?\)/);if(n){const e="#"+t(255*n[1])+t(255*n[2])+t(255*n[3]),a=void 0===n[4]?1:parseFloat(n[4]);return(a<1?`${e} / ${a}`:e).toUpperCase()}const a=e.match(/rgba?\((\d+),\s*(\d+),\s*(\d+)(?:,\s*([\d.]+))?\)/);if(!a)return e;const c="#"+t(a[1])+t(a[2])+t(a[3]),o=void 0===a[4]?1:parseFloat(a[4]);return(o<1?`${c} / ${o}`:c).toUpperCase()}(window.getComputedStyle(e).backgroundColor),n=e.parentElement.querySelector(".mw-text-muted");n&&(n.textContent=t)})}function n(e){const t=Array.from(e.querySelectorAll(".mw-kanban-column")),n=e.querySelector(".mw-kanban-composer"),a=e.querySelector(".mw-kanban-card-template"),c=e.dataset.kanbanPrefix||"MW",o=n.querySelector(".mw-kanban-composer-title"),r=n.querySelector(".mw-kanban-composer-text"),l=n.querySelector(".mw-kanban-composer-priority"),s=n.querySelector(".mw-kanban-composer-assignee");let i=null;function d(){t.forEach(function(e,n){const a=e.querySelectorAll(".mw-kanban-card"),c=e.querySelector(".mw-kanban-count");c&&(c.textContent=a.length),e.querySelectorAll("[data-kanban-move]").forEach(function(e){const a=n+parseInt(e.dataset.kanbanMove,10);e.disabled=a<0||a>=t.length})})}function u(e,t){const n=e.querySelector(t);return n?n.textContent.replace(/\s+/g," ").trim():""}function m(e,t){f(),i=t||null,o.value=t?u(t,".mw-kanban-card-title"):"",r.value=t?u(t,".mw-kanban-card-text"):"",l.value=t?function(e){const t=e.querySelector(".mw-card-ribbon");if(!t)return"";const n=Array.from(t.classList).find(function(e){return 0===e.indexOf("mw-card-addon-")});return n?n.replace("mw-card-addon-",""):""}(t):"",s.value=t?function(e){const t=e.querySelector(".mw-avatar-initials");return t?t.textContent.trim():""}(t):"",t?(t.classList.add("mw-kanban-editing"),t.before(n)):e.querySelector(".mw-kanban-column-body").prepend(n),n.classList.add("mw-active"),o.focus()}function f(){n.classList.remove("mw-active"),i&&i.classList.remove("mw-kanban-editing"),i=null}function w(){const t=o.value.trim();if(!t)return void o.focus();const u=i||a.content.firstElementChild.cloneNode(!0);if(u.querySelector(".mw-kanban-card-title").textContent=t,u.querySelector(".mw-kanban-card-text").textContent=r.value.trim(),function(e,t){const n=e.querySelector(".mw-card-ribbon");if(n&&n.remove(),!t||!t.value)return;const a=document.createElement("div");a.className="mw-card-ribbon mw-card-addon-"+t.value,a.textContent=t.textContent,e.prepend(a)}(u,l.selectedOptions[0]),function(e,t){const n=e.querySelector(".mw-kanban-card-actions"),a=n.querySelector(".mw-avatar");if(!t)return void(a&&a.remove());const c=a||document.createElement("div");c.className="mw-avatar mw-avatar-xs mw-avatar-initials",c.textContent=t,a||n.prepend(c)}(u,s.value),!i){const t=function(){const t=Array.from(e.querySelectorAll(".mw-kanban-card-id")).map(function(e){return parseInt(e.textContent.split("-").pop(),10)||0});return c+"-"+(Math.max(0,...t)+1)}();u.classList.add("mw-kanban-card-in"),u.querySelector(".mw-kanban-card-id").textContent=t,u.querySelectorAll("[aria-label]").forEach(function(e){e.setAttribute("aria-label",e.getAttribute("aria-label").replace(/[A-Z]+-\d+/,t))}),n.before(u)}f(),d()}e.addEventListener("click",function(e){const n=e.target.closest("[data-kanban-move]");if(n){if(function(e,n){const a=e.closest(".mw-kanban-column"),c=t[t.indexOf(a)+n];c&&(c.querySelector(".mw-kanban-column-body").appendChild(e),d())}(n.closest(".mw-kanban-card"),parseInt(n.dataset.kanbanMove,10)),n.disabled){const e=n.parentElement.querySelector("[data-kanban-move]:not(:disabled)");e&&e.focus()}return}const a=e.target.closest(".mw-kanban-edit");if(a){const e=a.closest(".mw-kanban-card");return void m(e.closest(".mw-kanban-column"),e)}const c=e.target.closest(".mw-kanban-delete");if(c){const e=c.closest(".mw-kanban-card");return e===i&&f(),e.remove(),void d()}const o=e.target.closest(".mw-kanban-add");o?m(o.closest(".mw-kanban-column"),null):e.target.closest(".mw-kanban-composer-cancel")&&f()}),n.addEventListener("submit",function(e){e.preventDefault(),w()}),n.addEventListener("keydown",function(e){"Escape"===e.key&&f()}),d()}function a(e){const t=e.querySelector(".mw-calendar-grid"),n=e.querySelector(".mw-calendar-title");if(!t)return;const a="week"===e.dataset.calendar,c=function(e){if(!e)return{};try{return JSON.parse(e)}catch(e){return{}}}(e.dataset.calendarMarkers),o=e.dataset.calendarLocale||document.documentElement.lang||void 0,r=new Date;r.setHours(0,0,0,0);let l=e.dataset.calendarDate?new Date(e.dataset.calendarDate+"T00:00:00"):new Date(r),s=e.dataset.calendarSelected||"";function i(e){const t=new Date(e);return t.setDate(t.getDate()-(t.getDay()+6)%7),t}function d(e){return e.getFullYear()+"-"+String(e.getMonth()+1).padStart(2,"0")+"-"+String(e.getDate()).padStart(2,"0")}function u(){if(!a)return l.toLocaleDateString(o,{month:"long",year:"numeric"});const e=i(l),t=new Date(e);t.setDate(t.getDate()+6);const n=e.toLocaleDateString(o,{day:"numeric",month:e.getMonth()===t.getMonth()?void 0:"short"}),c=t.toLocaleDateString(o,{day:"numeric",month:"short",year:"numeric"});return"Week "+function(e){const t=i(e);t.setDate(t.getDate()+3);const n=i(new Date(t.getFullYear(),0,4));return n.setDate(n.getDate()+3),1+Math.round((t-n)/6048e5)}(e)+" · "+n+" - "+c}function m(e){const t=e.getDay();return 0===t||6===t}function f(e,t){const n=d(e),l=document.createElement("button");l.type="button",l.className="mw-calendar-day",l.tabIndex=-1,l.dataset.calendarDay=n,l.setAttribute("aria-pressed",n===s?"true":"false"),l.setAttribute("aria-label",e.toLocaleDateString(o,{weekday:"long",day:"numeric",month:"long",year:"numeric"})),m(e)&&l.classList.add("mw-calendar-weekend"),a||e.getMonth()===t||l.classList.add("mw-calendar-adjacent"),n===d(r)&&(l.classList.add("mw-calendar-today"),l.setAttribute("aria-current","date")),n===s&&l.classList.add("mw-selected");const i=document.createElement("span");i.className="mw-calendar-date",i.textContent=e.getDate(),l.appendChild(i);const u=[].concat(c[n]||[]);if(u.length){const e=document.createElement("span");e.className="mw-calendar-dots",u.forEach(function(t){const n=document.createElement("span");n.className=t?"mw-calendar-dot mw-calendar-dot-"+t:"mw-calendar-dot",e.appendChild(n)}),l.appendChild(e)}return l}function w(){const e=l.getMonth(),c=a?7:42,r=i(a?l:new Date(l.getFullYear(),e,1));t.innerHTML="",function(){const e=i(new Date);for(let n=0;n<7;n++){const n=document.createElement("div");n.className="mw-calendar-weekday",m(e)&&n.classList.add("mw-calendar-weekend"),n.setAttribute("aria-hidden","true"),n.textContent=e.toLocaleDateString(o,{weekday:"short"}),t.appendChild(n),e.setDate(e.getDate()+1)}}();for(let n=0;n<c;n++)t.appendChild(f(r,e)),r.setDate(r.getDate()+1);n&&(n.textContent=u()),function(){const e=t.querySelector(".mw-selected")||t.querySelector(".mw-calendar-today")||t.querySelector(".mw-calendar-day:not(.mw-calendar-adjacent)")||t.querySelector(".mw-calendar-day");e&&(e.tabIndex=0)}()}e.addEventListener("click",function(n){const c=n.target.closest("[data-calendar-nav]");if(c)return o=parseInt(c.dataset.calendarNav,10),a?l.setDate(l.getDate()+7*o):l=new Date(l.getFullYear(),l.getMonth()+o,1),void w();var o;const r=n.target.closest(".mw-calendar-day");var i;r&&!r.disabled&&(i=r.dataset.calendarDay,s=i===s?"":i,t.querySelectorAll(".mw-calendar-day").forEach(function(e){const t=e.dataset.calendarDay===s;e.classList.toggle("mw-selected",t),e.setAttribute("aria-pressed",t?"true":"false")}),e.dispatchEvent(new CustomEvent("mw-calendar-select",{bubbles:!0,detail:{date:s}})))}),t.addEventListener("keydown",function(e){const n={ArrowLeft:-1,ArrowRight:1,ArrowUp:-7,ArrowDown:7}[e.key];if(!n)return;const a=e.target.closest(".mw-calendar-day");if(!a)return;e.preventDefault();const c=new Date(a.dataset.calendarDay+"T00:00:00");c.setDate(c.getDate()+n),function(e){const n=d(e);let a=t.querySelector('[data-calendar-day="'+n+'"]');a||(l=new Date(e),w(),a=t.querySelector('[data-calendar-day="'+n+'"]')),a&&(t.querySelectorAll(".mw-calendar-day").forEach(function(e){e.tabIndex=-1}),a.tabIndex=0,a.focus())}(c)}),w()}document.addEventListener("DOMContentLoaded",function(){document.querySelectorAll(".mw-gallery").forEach(e=>{const t=e.closest(".mw-gallery-container")||e.parentElement;t&&function(e,t){const n=t.querySelector(".mw-gallery-track");if(!n||!n.children.length)return;const a=n.children,c=e.querySelector(".mw-gallery-dots"),o=e.querySelector(".mw-gallery-desc"),r=t.querySelector(".mw-gallery-navi-prev"),l=t.querySelector(".mw-gallery-navi-next");let s=0;function i(e){const t=a.length;s=(e+t)%t,n.style.transform=`translateX(-${100*s}%)`,c&&c.querySelectorAll(".mw-gallery-dot").forEach((e,t)=>{e.classList.toggle("mw-active",t===s)}),o&&(o.textContent=a[s].dataset.desc||"")}if(c)for(let e=0;e<a.length;e++){const t=document.createElement("span");t.className="mw-gallery-dot"+(0===e?" mw-active":""),t.addEventListener("click",()=>i(e)),c.appendChild(t)}r&&r.addEventListener("click",()=>i(s-1)),l&&l.addEventListener("click",()=>i(s+1));let d=0;n.addEventListener("touchstart",e=>d=e.touches[0].clientX),n.addEventListener("touchend",e=>{const t=e.changedTouches[0].clientX-d;t>50&&i(s-1),t<-50&&i(s+1)}),i(0)}(t,e)}),function(){const n=document.querySelector(".mw-theme-toggle");if(!n)return;const a=document.body,c=n.querySelector(".mw-theme-toggle-slider i"),o=getComputedStyle(document.documentElement).getPropertyValue("--mw-internal-theme-mode").trim()||"switchable";if("switchable"!==o)return console.log(`Theme mode fixed to: ${o}. Disabling toggle.`),c&&(c.className="light"===o?"fas fa-sun":"fas fa-moon"),e(n,"light"===o),n.style.opacity="0.4",n.style.pointerEvents="none",n.style.cursor="default",n.setAttribute("aria-disabled","true"),localStorage.removeItem("mw-theme"),void("dark"===o&&a.classList.remove("mw-theme-light"));let r="light"===localStorage.getItem("mw-theme");const l=t=>{a.classList.toggle("mw-theme-light",t),e(n,t),c&&(c.className=t?"fas fa-sun":"fas fa-moon")};l(r),n.addEventListener("click",()=>{r=!r,l(r),localStorage.setItem("mw-theme",r?"light":"dark"),setTimeout(t,400)})}(),t(),document.querySelectorAll(".mw-accordion-header").forEach(t=>{t.addEventListener("click",function(){const t=!((n=this)&&(n.classList.contains("mw-active")||n.classList.contains("active")));var n;e(this,t),e(this.nextElementSibling,t)})}),function(){const e=document.querySelector(".mw-menu-btn"),t=document.querySelector(".mw-navbar");if(!e||!t)return;function n(){e.classList.remove("open"),t.classList.remove("open")}function a(n){n.preventDefault(),n.stopPropagation(),e.classList.toggle("open"),t.classList.toggle("open")}e.addEventListener("click",a),e.addEventListener("touchstart",a,{passive:!1}),document.addEventListener("click",function(a){t.classList.contains("open")&&(t.contains(a.target)||e.contains(a.target)||n())}),document.addEventListener("keydown",function(e){"Escape"===e.key&&n()})}(),function(){const e=document.querySelectorAll(".mw-progress-fill");if(!e.length)return;const t=new IntersectionObserver((e,t)=>{e.forEach(e=>{if(!e.isIntersecting)return;const n=e.target,a=n.dataset.value||0;n.style.width=a+"%",t.unobserve(n)})},{root:null,threshold:.2});e.forEach(e=>t.observe(e))}(),document.querySelectorAll('a[href^="#"]').forEach(e=>{e.addEventListener("click",function(e){const t=this.getAttribute("href");if("#"===t)return;if(!document.querySelector(t))return;const n=document.querySelector(".mw-menu-btn"),a=document.querySelector(".mw-navbar");n&&a&&(n.classList.remove("open"),a.classList.remove("open"))})}),function(){const t=document.querySelectorAll("section[id]"),n=document.querySelectorAll(".mw-navbar-link");if(0===t.length||0===n.length)return;window.addEventListener("scroll",function(e,t){let n;return function(){const a=this,c=arguments;clearTimeout(n),n=setTimeout(()=>e.apply(a,c),t)}}(function(){let a="";t.forEach(e=>{const t=e.offsetTop-100,n=e.clientHeight;scrollY>=t&&scrollY<t+n&&(a=e.getAttribute("id"))}),n.forEach(t=>{e(t,!1);const n=t.getAttribute("href");if(n){const c=n.indexOf("#");if(-1!==c){n.substring(c+1)===a&&e(t,!0)}}})},100))}(),document.querySelectorAll(".mw-tabs-nav-item").forEach(t=>{t.addEventListener("click",function(){const t=this.closest(".mw-tabs");if(!t)return;t.querySelectorAll(".mw-tabs-nav-item").forEach(t=>{e(t,!1)}),e(this,!0);const n=this.getAttribute("data-tab");n&&(t.querySelectorAll(".mw-tabs-panel").forEach(t=>{e(t,!1)}),e(document.getElementById(n),!0))})}),document.querySelectorAll(".mw-alert-close").forEach(e=>{e.addEventListener("click",function(){const e=this.closest(".mw-alert");e&&(e.classList.add("mw-alert-closing"),setTimeout(()=>{e.classList.add("mw-alert-closed")},300))})}),function(){const e=document.querySelector(".mw-localhost-indicator-activated"),t=document.querySelector(".mw-header");if(e){if("localhost"===window.location.hostname||"127.0.0.1"===window.location.hostname||window.location.hostname.includes("192.168.")){const e=document.createElement("div");e.className="mw-localhost-indicator-pulse",t.prepend(e)}}}(),document.querySelectorAll(".mw-slider-container").forEach(e=>{const t=e.querySelector(".mw-slider"),n=e.querySelector(".mw-slider-value");if(!t||!n)return;const a=()=>{const e=Number(t.value),a=Number(t.max)||100,c=Math.round(e/a*100);t.style.setProperty("--value",c+"%"),n.classList.contains("mw-slider-numeric")?n.setAttribute("data-value",e):n.setAttribute("data-value",c)};t.addEventListener("input",a),a()}),document.querySelectorAll(".mw-modal-close").forEach(e=>{e.addEventListener("click",function(){const e=this.closest(".mw-modal-overlay");e&&e.classList.remove("mw-modal-open")})}),function(){const e=document.getElementById("login-button");e&&e.addEventListener("click",function(){const e=this.querySelector("i");e.classList.contains("fa-lock")?(e.classList.remove("fa-lock"),e.classList.add("fa-lock-open")):(e.classList.remove("fa-lock-open"),e.classList.add("fa-lock"))})}(),document.querySelectorAll(".mw-image-slider").forEach(t=>{const n=t.querySelectorAll(".mw-image-slider-overlay-image"),a=t.querySelectorAll("button[data-index]");if(!n.length||!a.length)return;let c=0;function o(){n.forEach(t=>{e(t,parseInt(t.dataset.index)===c)}),a.forEach(t=>{e(t,parseInt(t.dataset.index)===c)})}function r(e){c=e,o()}a.forEach(e=>{e.addEventListener("click",()=>{r(parseInt(e.dataset.index))})}),o()}),document.querySelectorAll(".mw-item-list-checkbox, .mw-item-list-checkbox-scroll").forEach(e=>{e.querySelectorAll("li").forEach(e=>{const t=e.querySelector('input[type="checkbox"]'),n=e.querySelector(".mw-checkbox");t&&n&&(t.checked&&e.classList.add("mw-selected"),e.addEventListener("click",function(e){e.target!==t&&e.target.closest(".mw-checkbox")!==n&&toggleCheckbox(this)}),t.addEventListener("change",function(){const e=this.closest("li");this.checked?e.classList.add("mw-selected"):e.classList.remove("mw-selected"),e.dispatchEvent(new CustomEvent("checkboxToggle",{detail:{checked:this.checked,item:e}}))}),n.addEventListener("click",function(e){setTimeout(()=>{const e=this.closest("li");this.querySelector('input[type="checkbox"]').checked?e.classList.add("mw-selected"):e.classList.remove("mw-selected")},0)}))})}),document.addEventListener("checkboxToggle",function(e){console.log("Checkbox toggled:",e.detail.checked,e.detail.item)}),document.querySelectorAll(".mw-kanban").forEach(n),document.querySelectorAll("[data-calendar]").forEach(a)}),window.toggleCheckbox=function(e){const t=e.querySelector('input[type="checkbox"]');if(!t)return;const n=t.checked;t.checked=!n,t.checked?e.classList.add("mw-selected"):e.classList.remove("mw-selected"),e.dispatchEvent(new CustomEvent("checkboxToggle",{detail:{checked:t.checked,item:e}}))}}();
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "maverick-wave",
3
- "version": "3.10.0",
3
+ "version": "4.0.0",
4
4
  "config": {
5
- "version_short": "3.10"
5
+ "version_short": "4.0"
6
6
  },
7
7
  "description": "A lightweight, modern CSS framework for building responsive websites with elegance and speed.",
8
8
  "main": "src/js/main.js",
package/src/js/main.js CHANGED
@@ -1,6 +1,23 @@
1
1
  (function () {
2
2
  'use strict';
3
3
 
4
+ // State classes: `mw-active` is the documented spelling, plain `active` is
5
+ // the one older markup uses. Both are styled, so turning a state *off* has
6
+ // to clear both - otherwise a stale `active` from the HTML would keep a
7
+ // second tab lit.
8
+ function setActive(el, on) {
9
+ if (!el) return;
10
+ el.classList.toggle('mw-active', on);
11
+ if (!on) el.classList.remove('active');
12
+ }
13
+
14
+ function isActive(el) {
15
+ return (
16
+ !!el &&
17
+ (el.classList.contains('mw-active') || el.classList.contains('active'))
18
+ );
19
+ }
20
+
4
21
  // Initialize all components when DOM is ready
5
22
  document.addEventListener('DOMContentLoaded', function () {
6
23
  // Initialize all components
@@ -21,6 +38,7 @@
21
38
  initImageSliders();
22
39
  initCheckboxLists();
23
40
  initKanbanBoards();
41
+ initCalendars();
24
42
  });
25
43
 
26
44
  // ===== Checkbox Lists =====
@@ -213,11 +231,7 @@
213
231
  icon.className = themeMode === 'light' ? 'fas fa-sun' : 'fas fa-moon';
214
232
  }
215
233
  // Adjust toggle 'active' state if needed (assuming 'active' shows sun)
216
- if (themeMode === 'light') {
217
- themeToggle.classList.add('active');
218
- } else {
219
- themeToggle.classList.remove('active');
220
- }
234
+ setActive(themeToggle, themeMode === 'light');
221
235
 
222
236
  // Disable existing toggle visually and functionally
223
237
  themeToggle.style.opacity = '0.4';
@@ -243,7 +257,7 @@
243
257
  const applyTheme = (lightMode) => {
244
258
  // Use toggle's second argument for cleaner class switching
245
259
  body.classList.toggle('mw-theme-light', lightMode);
246
- themeToggle.classList.toggle('active', lightMode);
260
+ setActive(themeToggle, lightMode);
247
261
  if (icon) {
248
262
  icon.className = lightMode ? 'fas fa-sun' : 'fas fa-moon';
249
263
  }
@@ -318,9 +332,9 @@
318
332
  const accordionHeaders = document.querySelectorAll('.mw-accordion-header');
319
333
  accordionHeaders.forEach((header) => {
320
334
  header.addEventListener('click', function () {
321
- this.classList.toggle('active');
322
- const content = this.nextElementSibling;
323
- if (content) content.classList.toggle('active');
335
+ const open = !isActive(this);
336
+ setActive(this, open);
337
+ setActive(this.nextElementSibling, open);
324
338
  });
325
339
  });
326
340
  }
@@ -428,7 +442,7 @@
428
442
  });
429
443
 
430
444
  navLinks.forEach((link) => {
431
- link.classList.remove('active');
445
+ setActive(link, false);
432
446
 
433
447
  const href = link.getAttribute('href');
434
448
  if (href) {
@@ -436,7 +450,7 @@
436
450
  if (hashIndex !== -1) {
437
451
  const linkTarget = href.substring(hashIndex + 1);
438
452
  if (linkTarget === current) {
439
- link.classList.add('active');
453
+ setActive(link, true);
440
454
  }
441
455
  }
442
456
  }
@@ -457,20 +471,19 @@
457
471
  tabsContainer
458
472
  .querySelectorAll('.mw-tabs-nav-item')
459
473
  .forEach((navItem) => {
460
- navItem.classList.remove('active');
474
+ setActive(navItem, false);
461
475
  });
462
476
 
463
- this.classList.add('active');
477
+ setActive(this, true);
464
478
 
465
479
  const tabId = this.getAttribute('data-tab');
466
480
  if (!tabId) return;
467
481
 
468
482
  tabsContainer.querySelectorAll('.mw-tabs-panel').forEach((panel) => {
469
- panel.classList.remove('active');
483
+ setActive(panel, false);
470
484
  });
471
485
 
472
- const targetPanel = document.getElementById(tabId);
473
- if (targetPanel) targetPanel.classList.add('active');
486
+ setActive(document.getElementById(tabId), true);
474
487
  });
475
488
  });
476
489
  }
@@ -601,13 +614,11 @@
601
614
 
602
615
  function updateSliderView() {
603
616
  overlayImages.forEach((img) => {
604
- const imgIndex = parseInt(img.dataset.index);
605
- img.classList.toggle('active', imgIndex === current);
617
+ setActive(img, parseInt(img.dataset.index) === current);
606
618
  });
607
619
 
608
620
  buttons.forEach((btn) => {
609
- const btnIndex = parseInt(btn.dataset.index);
610
- btn.classList.toggle('active', btnIndex === current);
621
+ setActive(btn, parseInt(btn.dataset.index) === current);
611
622
  });
612
623
  }
613
624
 
@@ -841,4 +852,287 @@
841
852
 
842
853
  refresh();
843
854
  }
855
+ // ===== Calendars =====
856
+ function initCalendars() {
857
+ document.querySelectorAll('[data-calendar]').forEach(initCalendar);
858
+ }
859
+
860
+ // Status dots come in as {"2026-08-19": ["success", "warning"]}
861
+ function parseCalendarMarkers(raw) {
862
+ if (!raw) return {};
863
+
864
+ try {
865
+ return JSON.parse(raw);
866
+ } catch (error) {
867
+ return {};
868
+ }
869
+ }
870
+
871
+ function initCalendar(calendar) {
872
+ const grid = calendar.querySelector('.mw-calendar-grid');
873
+ const title = calendar.querySelector('.mw-calendar-title');
874
+ if (!grid) return;
875
+
876
+ const weekMode = calendar.dataset.calendar === 'week';
877
+ const markers = parseCalendarMarkers(calendar.dataset.calendarMarkers);
878
+ // Falls back to the document language, so a German page gets German day
879
+ // names without configuring anything
880
+ const locale =
881
+ calendar.dataset.calendarLocale ||
882
+ document.documentElement.lang ||
883
+ undefined;
884
+
885
+ const today = new Date();
886
+ today.setHours(0, 0, 0, 0);
887
+
888
+ let cursor = calendar.dataset.calendarDate
889
+ ? new Date(calendar.dataset.calendarDate + 'T00:00:00')
890
+ : new Date(today);
891
+ let selected = calendar.dataset.calendarSelected || '';
892
+
893
+ // Monday first: that is what ISO weeks use, and it keeps the weekend
894
+ // together as one block on the right
895
+ function startOfWeek(date) {
896
+ const result = new Date(date);
897
+ result.setDate(result.getDate() - ((result.getDay() + 6) % 7));
898
+ return result;
899
+ }
900
+
901
+ // Local date key - toISOString() would shift the day across a timezone
902
+ function dateKey(date) {
903
+ return (
904
+ date.getFullYear() +
905
+ '-' +
906
+ String(date.getMonth() + 1).padStart(2, '0') +
907
+ '-' +
908
+ String(date.getDate()).padStart(2, '0')
909
+ );
910
+ }
911
+
912
+ // ISO 8601: the week owning the Thursday owns the number
913
+ function weekNumber(date) {
914
+ const thursday = startOfWeek(date);
915
+ thursday.setDate(thursday.getDate() + 3);
916
+
917
+ const firstThursday = startOfWeek(new Date(thursday.getFullYear(), 0, 4));
918
+ firstThursday.setDate(firstThursday.getDate() + 3);
919
+
920
+ return 1 + Math.round((thursday - firstThursday) / 604800000);
921
+ }
922
+
923
+ function headline() {
924
+ if (!weekMode) {
925
+ return cursor.toLocaleDateString(locale, {
926
+ month: 'long',
927
+ year: 'numeric',
928
+ });
929
+ }
930
+
931
+ const from = startOfWeek(cursor);
932
+ const to = new Date(from);
933
+ to.setDate(to.getDate() + 6);
934
+
935
+ // The month is only spelled out twice when the week straddles two of them
936
+ const fromLabel = from.toLocaleDateString(locale, {
937
+ day: 'numeric',
938
+ month: from.getMonth() === to.getMonth() ? undefined : 'short',
939
+ });
940
+ const toLabel = to.toLocaleDateString(locale, {
941
+ day: 'numeric',
942
+ month: 'short',
943
+ year: 'numeric',
944
+ });
945
+
946
+ return 'Week ' + weekNumber(from) + ' · ' + fromLabel + ' - ' + toLabel;
947
+ }
948
+
949
+ function isWeekend(date) {
950
+ const weekday = date.getDay();
951
+ return weekday === 0 || weekday === 6;
952
+ }
953
+
954
+ function renderWeekdays() {
955
+ const day = startOfWeek(new Date());
956
+
957
+ for (let index = 0; index < 7; index++) {
958
+ const cell = document.createElement('div');
959
+ cell.className = 'mw-calendar-weekday';
960
+ if (isWeekend(day)) cell.classList.add('mw-calendar-weekend');
961
+ // Decorative: every day button already carries its weekday in the label
962
+ cell.setAttribute('aria-hidden', 'true');
963
+ cell.textContent = day.toLocaleDateString(locale, { weekday: 'short' });
964
+ grid.appendChild(cell);
965
+ day.setDate(day.getDate() + 1);
966
+ }
967
+ }
968
+
969
+ function renderDay(date, month) {
970
+ const key = dateKey(date);
971
+ const cell = document.createElement('button');
972
+
973
+ cell.type = 'button';
974
+ cell.className = 'mw-calendar-day';
975
+ cell.tabIndex = -1;
976
+ cell.dataset.calendarDay = key;
977
+ cell.setAttribute('aria-pressed', key === selected ? 'true' : 'false');
978
+ // The bare number is not an accessible name - the arrows only announce
979
+ // where you are going, not where you landed
980
+ cell.setAttribute(
981
+ 'aria-label',
982
+ date.toLocaleDateString(locale, {
983
+ weekday: 'long',
984
+ day: 'numeric',
985
+ month: 'long',
986
+ year: 'numeric',
987
+ })
988
+ );
989
+
990
+ if (isWeekend(date)) cell.classList.add('mw-calendar-weekend');
991
+ if (!weekMode && date.getMonth() !== month) {
992
+ cell.classList.add('mw-calendar-adjacent');
993
+ }
994
+ if (key === dateKey(today)) {
995
+ cell.classList.add('mw-calendar-today');
996
+ cell.setAttribute('aria-current', 'date');
997
+ }
998
+ if (key === selected) cell.classList.add('mw-selected');
999
+
1000
+ const number = document.createElement('span');
1001
+ number.className = 'mw-calendar-date';
1002
+ number.textContent = date.getDate();
1003
+ cell.appendChild(number);
1004
+
1005
+ const tones = [].concat(markers[key] || []);
1006
+ if (tones.length) {
1007
+ const dots = document.createElement('span');
1008
+ dots.className = 'mw-calendar-dots';
1009
+
1010
+ tones.forEach(function (tone) {
1011
+ const dot = document.createElement('span');
1012
+ dot.className = tone
1013
+ ? 'mw-calendar-dot mw-calendar-dot-' + tone
1014
+ : 'mw-calendar-dot';
1015
+ dots.appendChild(dot);
1016
+ });
1017
+
1018
+ cell.appendChild(dots);
1019
+ }
1020
+
1021
+ return cell;
1022
+ }
1023
+
1024
+ // A month always gets six rows. Rendering only the rows it needs would make
1025
+ // the calendar - and everything below it - jump on every month change.
1026
+ function render() {
1027
+ const month = cursor.getMonth();
1028
+ const cells = weekMode ? 7 : 42;
1029
+ const date = weekMode
1030
+ ? startOfWeek(cursor)
1031
+ : startOfWeek(new Date(cursor.getFullYear(), month, 1));
1032
+
1033
+ grid.innerHTML = '';
1034
+ renderWeekdays();
1035
+
1036
+ for (let index = 0; index < cells; index++) {
1037
+ grid.appendChild(renderDay(date, month));
1038
+ date.setDate(date.getDate() + 1);
1039
+ }
1040
+
1041
+ if (title) title.textContent = headline();
1042
+ setTabStop();
1043
+ }
1044
+
1045
+ // One tab stop for the whole grid; the arrow keys move inside it
1046
+ function setTabStop() {
1047
+ const cell =
1048
+ grid.querySelector('.mw-selected') ||
1049
+ grid.querySelector('.mw-calendar-today') ||
1050
+ grid.querySelector('.mw-calendar-day:not(.mw-calendar-adjacent)') ||
1051
+ grid.querySelector('.mw-calendar-day');
1052
+
1053
+ if (cell) cell.tabIndex = 0;
1054
+ }
1055
+
1056
+ function select(key) {
1057
+ selected = key === selected ? '' : key;
1058
+
1059
+ grid.querySelectorAll('.mw-calendar-day').forEach(function (cell) {
1060
+ const active = cell.dataset.calendarDay === selected;
1061
+ cell.classList.toggle('mw-selected', active);
1062
+ cell.setAttribute('aria-pressed', active ? 'true' : 'false');
1063
+ });
1064
+
1065
+ calendar.dispatchEvent(
1066
+ new CustomEvent('mw-calendar-select', {
1067
+ bubbles: true,
1068
+ detail: { date: selected },
1069
+ })
1070
+ );
1071
+ }
1072
+
1073
+ function step(offset) {
1074
+ if (weekMode) {
1075
+ cursor.setDate(cursor.getDate() + offset * 7);
1076
+ } else {
1077
+ // Snap to the first - stepping on from the 31st would skip February
1078
+ cursor = new Date(cursor.getFullYear(), cursor.getMonth() + offset, 1);
1079
+ }
1080
+
1081
+ render();
1082
+ }
1083
+
1084
+ function focusDate(date) {
1085
+ const key = dateKey(date);
1086
+ let cell = grid.querySelector('[data-calendar-day="' + key + '"]');
1087
+
1088
+ // Walked off the rendered range - turn the page and look again
1089
+ if (!cell) {
1090
+ cursor = new Date(date);
1091
+ render();
1092
+ cell = grid.querySelector('[data-calendar-day="' + key + '"]');
1093
+ }
1094
+
1095
+ if (!cell) return;
1096
+
1097
+ grid.querySelectorAll('.mw-calendar-day').forEach(function (other) {
1098
+ other.tabIndex = -1;
1099
+ });
1100
+ cell.tabIndex = 0;
1101
+ cell.focus();
1102
+ }
1103
+
1104
+ calendar.addEventListener('click', function (event) {
1105
+ const navButton = event.target.closest('[data-calendar-nav]');
1106
+ if (navButton) {
1107
+ step(parseInt(navButton.dataset.calendarNav, 10));
1108
+ return;
1109
+ }
1110
+
1111
+ const dayButton = event.target.closest('.mw-calendar-day');
1112
+ if (dayButton && !dayButton.disabled) {
1113
+ select(dayButton.dataset.calendarDay);
1114
+ }
1115
+ });
1116
+
1117
+ grid.addEventListener('keydown', function (event) {
1118
+ const offsets = {
1119
+ ArrowLeft: -1,
1120
+ ArrowRight: 1,
1121
+ ArrowUp: -7,
1122
+ ArrowDown: 7,
1123
+ };
1124
+ const offset = offsets[event.key];
1125
+ if (!offset) return;
1126
+
1127
+ const current = event.target.closest('.mw-calendar-day');
1128
+ if (!current) return;
1129
+
1130
+ event.preventDefault();
1131
+ const target = new Date(current.dataset.calendarDay + 'T00:00:00');
1132
+ target.setDate(target.getDate() + offset);
1133
+ focusDate(target);
1134
+ });
1135
+
1136
+ render();
1137
+ }
844
1138
  })();
@@ -2,11 +2,11 @@
2
2
 
3
3
  <div class="mw-accordion">
4
4
  <div class="mw-accordion-item">
5
- <div class="mw-accordion-header active">
5
+ <div class="mw-accordion-header mw-active">
6
6
  <h3>What is MaverickWave?</h3>
7
7
  <i class="fas fa-chevron-down mw-accordion-icon"></i>
8
8
  </div>
9
- <div class="mw-accordion-content active">
9
+ <div class="mw-accordion-content mw-active">
10
10
  <div class="mw-accordion-content-inner">
11
11
  <p>
12
12
  MaverickWave is a lightweight, responsive CSS framework designed for
@@ -86,8 +86,10 @@
86
86
  </div>
87
87
  </div>
88
88
  <div>
89
- <p class="mw-mb-2"><strong>Center Aligned (default):</strong></p>
90
- <div class="mw-button-bar mw-button-bar-outline">
89
+ <p class="mw-mb-2">
90
+ <strong>Center Aligned (also the default):</strong>
91
+ </p>
92
+ <div class="mw-button-bar mw-button-bar-center mw-button-bar-outline">
91
93
  <button class="mw-btn">Left</button>
92
94
  <button class="mw-btn">Center</button>
93
95
  <button class="mw-btn">Right</button>
@@ -127,3 +127,38 @@
127
127
  </div>
128
128
  </div>
129
129
  </div>
130
+
131
+ <h3 class="mw-mb-4 mw-mt-6">Plain Buttons</h3>
132
+ <p class="mw-text-muted">
133
+ <code>mw-btn-plain</code> is for everywhere a <code>&lt;button&gt;</code> is
134
+ the right element and a button is the wrong look - a calendar day, a time in a
135
+ request row, a modal backdrop. It brings nothing but the focus ring and the
136
+ pointer; everything else it inherits. Not the same as
137
+ <code>mw-btn-link</code>, which is a button dressed as a link with a colour
138
+ and a minimum width of its own.
139
+ </p>
140
+ <div class="mw-card mw-card-simple">
141
+ <p class="mw-mb-4">
142
+ Booked for
143
+ <button type="button" class="mw-btn-plain mw-text-bold">14:30</button>
144
+ on
145
+ <button type="button" class="mw-btn-plain mw-text-bold">19.09.2026</button>
146
+ &ndash; both are real buttons, reachable by tab.
147
+ </p>
148
+ <div class="mw-d-flex mw-gap-4 mw-flex-wrap">
149
+ <button type="button" class="mw-btn mw-btn-link">mw-btn-link</button>
150
+ <button type="button" class="mw-btn-plain">mw-btn-plain</button>
151
+ <button type="button" class="mw-btn-plain" disabled>disabled</button>
152
+ </div>
153
+ </div>
154
+
155
+ <h3 class="mw-mb-4 mw-mt-6">Touch Targets</h3>
156
+ <p class="mw-text-muted">
157
+ On a coarse pointer or below 768px the compact controls grow to a size a thumb
158
+ can actually hit: <code>mw-btn-sm</code>, <code>mw-input-sm</code> and
159
+ <code>mw-select-sm</code> to 2.5rem, a tab to 2.75rem, a calendar day to 44px.
160
+ WCAG 2.5.8 puts the floor at 24px, and that is a floor, not a goal.
161
+ <code>mw-btn-mini</code> keeps its 18px circle - it sits in tag rows and table
162
+ cells where a bigger one would shift the layout - and grows its hit area to
163
+ 28px instead. Nothing to switch on; resize this page or open it on a phone.
164
+ </p>