maverick-wave 4.27.0 → 5.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.
- package/.claude/settings.local.json +29 -1
- package/.claude/skills/mw-maverick-wave/SKILL.md +42 -25
- package/.claude/skills/mw-maverick-wave/examples/angular-services.md +16 -4
- package/.claude/skills/mw-maverick-wave/examples/static-landing-page.md +13 -4
- package/.claude/skills/mw-maverick-wave/references/components.md +90 -5
- package/.claude/skills/mw-maverick-wave/references/forms.md +14 -2
- package/.claude/skills/mw-maverick-wave/references/javascript.md +18 -4
- package/.claude/skills/mw-maverick-wave/references/layout.md +53 -19
- package/.claude/skills/mw-maverick-wave/references/theming.md +38 -1
- package/.impeccable/config.local.json +5 -0
- package/.impeccable/hook.cache.json +1 -0
- package/CHANGELOG.md +17 -0
- package/CLAUDE.md +5 -5
- package/README.md +48 -4
- package/index.html +19 -38
- package/maverick-wave.min.css +14 -12
- package/maverick-wave.min.js +1 -1
- package/package.json +2 -2
- package/scripts/verify.js +27 -2
- package/src/js/main.js +266 -75
- package/src/partials/accordions-container.html +6 -10
- package/src/partials/alerts-container.html +6 -6
- package/src/partials/announcement-container.html +5 -5
- package/src/partials/avatars-container.html +85 -17
- package/src/partials/badges-container.html +6 -6
- package/src/partials/blog-posts-container.html +11 -12
- package/src/partials/buttons-container.html +3 -3
- package/src/partials/cards-container.html +26 -9
- package/src/partials/code-container.html +5 -5
- package/src/partials/content-slider-container.html +5 -4
- package/src/partials/divider-container.html +7 -7
- package/src/partials/dropdown-container.html +2 -2
- package/src/partials/empty-state-container.html +5 -5
- package/src/partials/footer-container.html +21 -18
- package/src/partials/form-elements-container.html +14 -14
- package/src/partials/gallery-container.html +16 -8
- package/src/partials/get-started-container.html +4 -8
- package/src/partials/header-container.html +18 -7
- package/src/partials/header-utilities-container.html +192 -5
- package/src/partials/home-container.html +10 -20
- package/src/partials/input-group-container.html +11 -2
- package/src/partials/kbd-container.html +1 -1
- package/src/partials/login-container.html +5 -1
- package/src/partials/media-container.html +2 -2
- package/src/partials/modals-container.html +22 -32
- package/src/partials/pricing-container.html +9 -9
- package/src/partials/skeleton-container.html +6 -6
- package/src/partials/stepper-container.html +2 -2
- package/src/partials/tables-container.html +12 -12
- package/src/partials/tabs-container.html +17 -27
- package/src/partials/tags-container.html +23 -17
- package/src/partials/techstack-bucket-container.html +13 -0
- package/src/partials/tiles-container.html +26 -9
- package/src/partials/typography-container.html +7 -6
- package/src/partials/utilities-container.html +35 -15
- package/src/scss/_layers.scss +10 -0
- package/src/scss/abstracts/_index.scss +6 -0
- package/src/scss/abstracts/_mixins.scss +61 -153
- package/src/scss/abstracts/_variables.scss +123 -319
- package/src/scss/base/_base.scss +170 -190
- package/src/scss/base/_reset.scss +106 -104
- package/src/scss/base/_typography.scss +153 -151
- package/src/scss/components/_accordions.scss +97 -97
- package/src/scss/components/_alerts.scss +71 -70
- package/src/scss/components/_announcement.scss +71 -70
- package/src/scss/components/_avatars.scss +130 -142
- package/src/scss/components/_badge.scss +131 -132
- package/src/scss/components/_blog-post.scss +223 -220
- package/src/scss/components/_breadcrumbs.scss +93 -92
- package/src/scss/components/_button-bar.scss +102 -110
- package/src/scss/components/_buttons.scss +319 -324
- package/src/scss/components/_calendar.scss +251 -252
- package/src/scss/components/_cards.scss +359 -386
- package/src/scss/components/_code.scss +190 -194
- package/src/scss/components/_coming-soon.scss +77 -75
- package/src/scss/components/_content-slider.scss +90 -89
- package/src/scss/components/_divider.scss +55 -53
- package/src/scss/components/_dropdown.scss +179 -185
- package/src/scss/components/_empty-state.scss +57 -57
- package/src/scss/components/_flag.scss +325 -0
- package/src/scss/components/_gallery.scss +131 -133
- package/src/scss/components/_index.scss +2 -0
- package/src/scss/components/_info.scss +151 -167
- package/src/scss/components/_kanban.scss +332 -341
- package/src/scss/components/_kbd.scss +40 -38
- package/src/scss/components/_lang-switch.scss +108 -0
- package/src/scss/components/_links.scss +21 -28
- package/src/scss/components/_lists.scss +510 -514
- package/src/scss/components/_localhost-indicator.scss +26 -24
- package/src/scss/components/_media.scss +22 -20
- package/src/scss/components/_meta-info.scss +35 -33
- package/src/scss/components/_modals.scss +277 -186
- package/src/scss/components/_pagination.scss +81 -87
- package/src/scss/components/_panels.scss +99 -97
- package/src/scss/components/_pricing.scss +183 -241
- package/src/scss/components/_progress.scss +112 -89
- package/src/scss/components/_prose.scss +35 -33
- package/src/scss/components/_ratings.scss +40 -38
- package/src/scss/components/_segmented.scss +82 -84
- package/src/scss/components/_skeleton.scss +66 -72
- package/src/scss/components/_spinners.scss +155 -159
- package/src/scss/components/_stepper.scss +116 -116
- package/src/scss/components/_tables.scss +155 -148
- package/src/scss/components/_tabs.scss +232 -141
- package/src/scss/components/_tags.scss +109 -107
- package/src/scss/components/_techstack-bucket.scss +123 -122
- package/src/scss/components/_testimonial.scss +72 -70
- package/src/scss/components/_theme-toggle.scss +53 -51
- package/src/scss/components/_tiles.scss +174 -174
- package/src/scss/components/_timelines.scss +282 -280
- package/src/scss/components/_toasts.scss +66 -72
- package/src/scss/form-elements/_checkbox.scss +117 -132
- package/src/scss/form-elements/_form.scss +149 -115
- package/src/scss/form-elements/_input-group.scss +99 -103
- package/src/scss/form-elements/_input.scss +74 -74
- package/src/scss/form-elements/_login.scss +48 -48
- package/src/scss/form-elements/_prefilled.scss +53 -51
- package/src/scss/form-elements/_radio.scss +95 -107
- package/src/scss/form-elements/_select.scss +42 -42
- package/src/scss/form-elements/_slider.scss +117 -132
- package/src/scss/form-elements/_textarea.scss +68 -54
- package/src/scss/form-elements/_toggle.scss +127 -140
- package/src/scss/layout/_footer.scss +172 -171
- package/src/scss/layout/_grid.scss +268 -302
- package/src/scss/layout/_header.scss +426 -427
- package/src/scss/layout/_home.scss +28 -27
- package/src/scss/layout/_main.scss +275 -238
- package/src/scss/layout/_page-header.scss +38 -36
- package/src/scss/layout/_section.scss +150 -124
- package/src/scss/main.scss +1 -1
- package/src/scss/utilities/_accessibility.scss +46 -45
- package/src/scss/utilities/_aspect.scss +22 -20
- package/src/scss/utilities/_corner.scss +23 -5
- package/src/scss/utilities/_display.scss +76 -70
- package/src/scss/utilities/_elevation.scss +13 -11
- package/src/scss/utilities/_flex.scss +83 -85
- package/src/scss/utilities/_reveal.scss +40 -63
- package/src/scss/utilities/_spacing.scss +63 -64
- package/src/scss/utilities/_text.scss +139 -141
- package/src/scss/utilities/_touch-targets.scss +130 -147
package/maverick-wave.min.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
!function(){"use strict";function e(e,t){e&&(e.classList.toggle("mw-active",t),t||e.classList.remove("active"))}function t(e){return!!e&&(e.classList.contains("mw-active")||e.classList.contains("active"))}function n(){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 a(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"),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 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"):"",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"),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,s.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,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 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()}const h=["mw-kanban-card-moved-forward","mw-kanban-card-moved-back"];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),e.classList.remove.apply(e.classList,h),e.offsetWidth,e.classList.add(n>0?h[0]:h[1]),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 c(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 s=e.dataset.calendarDate?new Date(e.dataset.calendarDate+"T00:00:00"):new Date(r),l=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 s.toLocaleDateString(o,{month:"long",year:"numeric"});const e=i(s),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),s=document.createElement("button");s.type="button",s.className="mw-calendar-day",s.tabIndex=-1,s.dataset.calendarDay=n,s.setAttribute("aria-pressed",n===l?"true":"false"),s.setAttribute("aria-label",e.toLocaleDateString(o,{weekday:"long",day:"numeric",month:"long",year:"numeric"})),m(e)&&s.classList.add("mw-calendar-weekend"),a||e.getMonth()===t||s.classList.add("mw-calendar-adjacent"),n===d(r)&&(s.classList.add("mw-calendar-today"),s.setAttribute("aria-current","date")),n===l&&s.classList.add("mw-selected");const i=document.createElement("span");i.className="mw-calendar-date",i.textContent=e.getDate(),s.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)}),s.appendChild(e)}return s}function w(){const e=s.getMonth(),c=a?7:42,r=i(a?s:new Date(s.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?s.setDate(s.getDate()+7*o):s=new Date(s.getFullYear(),s.getMonth()+o,1),void w();var o;const r=n.target.closest(".mw-calendar-day");var i;r&&!r.disabled&&(i=r.dataset.calendarDay,l=i===l?"":i,t.querySelectorAll(".mw-calendar-day").forEach(function(e){const t=e.dataset.calendarDay===l;e.classList.toggle("mw-selected",t),e.setAttribute("aria-pressed",t?"true":"false")}),e.dispatchEvent(new CustomEvent("mw-calendar-select",{bubbles:!0,detail:{date:l}})))}),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||(s=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"),s=t.querySelector(".mw-gallery-navi-next");let l=0;function i(e){const t=a.length;l=(e+t)%t,n.style.transform=`translateX(-${100*l}%)`,c&&c.querySelectorAll(".mw-gallery-dot").forEach((e,t)=>{e.classList.toggle("mw-active",t===l)}),o&&(o.textContent=a[l].dataset.desc||"")}if(c)for(let e=0;e<a.length;e++){const t=document.createElement("button");t.type="button",t.className="mw-gallery-dot"+(0===e?" mw-active":""),t.setAttribute("aria-label","Go to slide "+(e+1)),t.addEventListener("click",()=>i(e)),c.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 a=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"),e(t,"light"===o),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&&a.classList.remove("mw-theme-light"));let r="light"===localStorage.getItem("mw-theme");const s=n=>{a.classList.toggle("mw-theme-light",n),e(t,n),c&&(c.className=n?"fas fa-sun":"fas fa-moon")};s(r),t.addEventListener("click",()=>{r=!r,s(r),localStorage.setItem("mw-theme",r?"light":"dark"),setTimeout(n,400)})}(),n(),document.querySelectorAll(".mw-accordion-header").forEach(n=>{const a="BUTTON"===n.tagName;a&&n.setAttribute("aria-expanded",String(t(n))),n.addEventListener("click",function(){const n=!t(this);e(this,n),e(this.nextElementSibling,n),a&&this.setAttribute("aria-expanded",String(n))})}),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;function a(){const e=parseFloat(getComputedStyle(document.documentElement).scrollPaddingTop);return(Number.isNaN(e)?0:e)+2}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 c="";const o=a();t.forEach(e=>{const t=e.offsetTop-o,n=e.clientHeight;scrollY>=t&&scrollY<t+n&&(c=e.getAttribute("id"))}),n.forEach(t=>{e(t,!1);const n=t.getAttribute("href");if(n){const a=n.indexOf("#");if(-1!==a){n.substring(a+1)===c&&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(a),document.querySelectorAll("[data-calendar]").forEach(c),function(){function e(e){document.querySelectorAll(".mw-dropdown[open]").forEach(t=>{t!==e&&t.removeAttribute("open")})}document.addEventListener("click",function(t){const n=t.target.closest(".mw-dropdown");e(n),n&&t.target.closest(".mw-dropdown-item")&&n.removeAttribute("open")}),document.addEventListener("keydown",function(e){if("Escape"!==e.key)return;const t=document.querySelector(".mw-dropdown[open]");if(!t)return;t.removeAttribute("open");const n=t.querySelector("summary");n&&n.focus()})}()}),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(e){return!!e&&(e.classList.contains("mw-active")||e.classList.contains("active"))}function n(){const e=Array.from(document.querySelectorAll(".color-swatch")),t=e.map(e=>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 o="#"+t(a[1])+t(a[2])+t(a[3]),r=void 0===a[4]?1:parseFloat(a[4]);return(r<1?`${o} / ${r}`:o).toUpperCase()}(window.getComputedStyle(e).backgroundColor));e.forEach((e,n)=>{const a=e.parentElement.querySelector(".mw-text-muted");a&&(a.textContent=t[n])})}function a(e){const t=e.querySelector(".mw-tabs-nav-item.mw-active, .mw-tabs-nav-item.active");t?(e.style.setProperty("--mw-tabs-marker-x",t.offsetLeft+"px"),e.style.setProperty("--mw-tabs-marker-w",t.offsetWidth),e.style.setProperty("--mw-tabs-marker-y",t.offsetTop+"px"),e.style.setProperty("--mw-tabs-marker-h",t.offsetHeight),e.setAttribute("data-mw-tabs-marker","")):e.removeAttribute("data-mw-tabs-marker")}function o(e){const t=e.getAttribute("data-tab");return t?document.getElementById(t):null}function r(e){const n=t(e);e.setAttribute("aria-selected",String(n)),e.tabIndex=n?0:-1}function c(t,n){t.forEach(t=>{const a=t===n;e(t,a),e(o(t),a),r(t)});const c=n.closest(".mw-tabs-nav");c&&a(c)}function s(e){e&&("DIALOG"===e.tagName?e.showModal():e.classList.add("mw-modal-open"))}function l(e){const t=Array.from(e.querySelectorAll(".mw-kanban-column")),n=e.querySelector(".mw-kanban-composer"),a=e.querySelector(".mw-kanban-card-template"),o=e.dataset.kanbanPrefix||"MW",r=n.querySelector(".mw-kanban-composer-title"),c=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 a=e.querySelectorAll(".mw-kanban-card"),o=e.querySelector(".mw-kanban-count");o&&(o.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){w(),i=t||null,r.value=t?u(t,".mw-kanban-card-title"):"",c.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"),r.focus()}function w(){n.classList.remove("mw-active"),i&&i.classList.remove("mw-kanban-editing"),i=null}function f(){const t=r.value.trim();if(!t)return void r.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=c.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,s.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 o=a||document.createElement("div");o.className="mw-avatar mw-avatar-xs mw-avatar-initials",o.textContent=t,a||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)}w(),d()}const g=["mw-kanban-card-moved-forward","mw-kanban-card-moved-back"];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"),o=t[t.indexOf(a)+n];o&&(o.querySelector(".mw-kanban-column-body").appendChild(e),e.classList.remove.apply(e.classList,g),e.offsetWidth,e.classList.add(n>0?g[0]:g[1]),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 o=e.target.closest(".mw-kanban-delete");if(o){const e=o.closest(".mw-kanban-card");return e===i&&w(),e.remove(),void d()}const r=e.target.closest(".mw-kanban-add");r?m(r.closest(".mw-kanban-column"),null):e.target.closest(".mw-kanban-composer-cancel")&&w()}),n.addEventListener("submit",function(e){e.preventDefault(),f()}),n.addEventListener("keydown",function(e){"Escape"===e.key&&w()}),d()}function i(e){const t=e.querySelector(".mw-calendar-grid"),n=e.querySelector(".mw-calendar-title");if(!t)return;const a="week"===e.dataset.calendar,o=function(e){if(!e)return{};try{return JSON.parse(e)}catch(e){return{}}}(e.dataset.calendarMarkers),r=e.dataset.calendarLocale||document.documentElement.lang||void 0,c=new Date;c.setHours(0,0,0,0);let s=e.dataset.calendarDate?new Date(e.dataset.calendarDate+"T00:00:00"):new Date(c),l=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 s.toLocaleDateString(r,{month:"long",year:"numeric"});const e=i(s),t=new Date(e);t.setDate(t.getDate()+6);const n=e.toLocaleDateString(r,{day:"numeric",month:e.getMonth()===t.getMonth()?void 0:"short"}),o=t.toLocaleDateString(r,{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+" - "+o}function m(e){const t=e.getDay();return 0===t||6===t}function w(e,t){const n=d(e),s=document.createElement("button");s.type="button",s.className="mw-calendar-day",s.tabIndex=-1,s.dataset.calendarDay=n,s.setAttribute("aria-pressed",n===l?"true":"false"),s.setAttribute("aria-label",e.toLocaleDateString(r,{weekday:"long",day:"numeric",month:"long",year:"numeric"})),m(e)&&s.classList.add("mw-calendar-weekend"),a||e.getMonth()===t||s.classList.add("mw-calendar-adjacent"),n===d(c)&&(s.classList.add("mw-calendar-today"),s.setAttribute("aria-current","date")),n===l&&s.classList.add("mw-selected");const i=document.createElement("span");i.className="mw-calendar-date",i.textContent=e.getDate(),s.appendChild(i);const u=[].concat(o[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)}),s.appendChild(e)}return s}function f(){const e=s.getMonth(),o=a?7:42,c=i(a?s:new Date(s.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(r,{weekday:"short"}),t.appendChild(n),e.setDate(e.getDate()+1)}}();for(let n=0;n<o;n++)t.appendChild(w(c,e)),c.setDate(c.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 o=n.target.closest("[data-calendar-nav]");if(o)return r=parseInt(o.dataset.calendarNav,10),a?s.setDate(s.getDate()+7*r):s=new Date(s.getFullYear(),s.getMonth()+r,1),void f();var r;const c=n.target.closest(".mw-calendar-day");var i;c&&!c.disabled&&(i=c.dataset.calendarDay,l=i===l?"":i,t.querySelectorAll(".mw-calendar-day").forEach(function(e){const t=e.dataset.calendarDay===l;e.classList.toggle("mw-selected",t),e.setAttribute("aria-pressed",t?"true":"false")}),e.dispatchEvent(new CustomEvent("mw-calendar-select",{bubbles:!0,detail:{date:l}})))}),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 o=new Date(a.dataset.calendarDay+"T00:00:00");o.setDate(o.getDate()+n),function(e){const n=d(e);let a=t.querySelector('[data-calendar-day="'+n+'"]');a||(s=new Date(e),f(),a=t.querySelector('[data-calendar-day="'+n+'"]')),a&&(t.querySelectorAll(".mw-calendar-day").forEach(function(e){e.tabIndex=-1}),a.tabIndex=0,a.focus())}(o)}),f()}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,o=e.querySelector(".mw-gallery-dots"),r=e.querySelector(".mw-gallery-desc"),c=t.querySelector(".mw-gallery-navi-prev"),s=t.querySelector(".mw-gallery-navi-next");let l=0;function i(e){const t=a.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)}),r&&(r.textContent=a[l].dataset.desc||"")}if(o)for(let e=0;e<a.length;e++){const t=document.createElement("button");t.type="button",t.className="mw-gallery-dot"+(0===e?" mw-active":""),t.setAttribute("aria-label","Go to slide "+(e+1)),t.addEventListener("click",()=>i(e)),o.appendChild(t)}c&&c.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 a=document.body,o=document.documentElement,r=t.querySelector(".mw-theme-toggle-slider i"),c=getComputedStyle(document.documentElement).getPropertyValue("--mw-internal-theme-mode").trim()||"switchable";if("switchable"!==c)return console.log(`Theme mode fixed to: ${c}. Disabling toggle.`),r&&(r.className="light"===c?"fas fa-sun":"fas fa-moon"),e(t,"light"===c),t.style.opacity="0.4",t.style.pointerEvents="none",t.style.cursor="default",t.setAttribute("aria-disabled","true"),localStorage.removeItem("mw-theme"),void("dark"===c&&a.classList.remove("mw-theme-light"));let s="light"===localStorage.getItem("mw-theme");const l=n=>{o.classList.add("mw-theme-switching"),a.classList.toggle("mw-theme-light",n),o.offsetHeight,o.classList.remove("mw-theme-switching"),e(t,n),r&&(r.className=n?"fas fa-sun":"fas fa-moon")};l(s),t.addEventListener("click",()=>{s=!s,l(s),localStorage.setItem("mw-theme",s?"light":"dark"),n()})}(),n(),document.querySelectorAll(".mw-accordion-header").forEach(n=>{const a="BUTTON"===n.tagName;a&&n.setAttribute("aria-expanded",String(t(n))),n.addEventListener("click",function(){const n=!t(this);e(this,n),e(this.nextElementSibling,n),a&&this.setAttribute("aria-expanded",String(n))})}),function(){const e=document.querySelector(".mw-menu-btn"),t=document.querySelector(".mw-navbar");if(!e||!t)return;const n="BUTTON"===e.tagName;function a(a){e.classList.toggle("open",a),t.classList.toggle("open",a),n&&e.setAttribute("aria-expanded",String(a))}function o(e){e.preventDefault(),e.stopPropagation(),a(!t.classList.contains("open"))}e.addEventListener("click",o),e.addEventListener("touchstart",o,{passive:!1}),document.addEventListener("click",function(n){t.classList.contains("open")&&(t.contains(n.target)||e.contains(n.target)||a(!1))}),document.addEventListener("keydown",function(n){"Escape"===n.key&&t.classList.contains("open")&&(a(!1),e.focus())})}(),function(){const e=document.querySelectorAll(".mw-progress-fill");if(!e.length)return;const t=CSS.supports("animation-timeline","view()"),n=e=>e.dataset.value?e.dataset.value+"%":e.style.width,a=[];if(e.forEach(e=>{const o=n(e);o&&(e.style.setProperty("--mw-progress-value",o),t?e.classList.add("mw-progress-driven"):a.push(e))}),t)return;const o=new IntersectionObserver((e,t)=>{e.forEach(e=>{e.isIntersecting&&(e.target.style.width=n(e.target),t.unobserve(e.target))})},{root:null,threshold:.2});a.forEach(e=>o.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;function a(){const e=parseFloat(getComputedStyle(document.documentElement).scrollPaddingTop);return(Number.isNaN(e)?0:e)+2}window.addEventListener("scroll",function(e,t){let n;return function(){const a=this,o=arguments;clearTimeout(n),n=setTimeout(()=>e.apply(a,o),t)}}(function(){let o="";const r=a();t.forEach(e=>{const t=e.offsetTop-r,n=e.clientHeight;scrollY>=t&&scrollY<t+n&&(o=e.getAttribute("id"))}),n.forEach(t=>{e(t,!1);const n=t.getAttribute("href");if(n){const a=n.indexOf("#");if(-1!==a){n.substring(a+1)===o&&e(t,!0)}}})},100))}(),document.querySelectorAll(".mw-tabs-nav").forEach(e=>{const t=Array.from(e.querySelectorAll(".mw-tabs-nav-item"));if(!t.length)return;const n=!!e.closest(".mw-tabs-vertical");e.setAttribute("role","tablist"),n&&e.setAttribute("aria-orientation","vertical"),t.forEach((e,a)=>{const s=o(e);e.setAttribute("role","tab"),e.id||(e.id=(s?s.id:"mw-tab-"+a)+"-tab"),s&&(e.setAttribute("aria-controls",s.id),s.setAttribute("role","tabpanel"),s.setAttribute("aria-labelledby",e.id)),r(e),e.addEventListener("click",()=>c(t,e)),e.addEventListener("keydown",e=>{const o=function(e,t,n,a){const o=t?"ArrowUp":"ArrowLeft",r=t?"ArrowDown":"ArrowRight";return e.key===o?(a-1+n)%n:e.key===r?(a+1)%n:"Home"===e.key?0:"End"===e.key?n-1:null}(e,n,t.length,a);null!==o&&(e.preventDefault(),c(t,t[o]),t[o].focus())})}),a(e);const s=new ResizeObserver(()=>a(e));s.observe(e),t.forEach(e=>s.observe(e))}),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,o=Math.round(e/a*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",a),a()}),document.addEventListener("click",e=>{const t=e.target.closest(".mw-modal-close");if(t){const e=t.closest("dialog.mw-modal");if(e)return void e.close();const n=t.closest(".mw-modal-overlay");return void(n&&n.classList.remove("mw-modal-open"))}const n=e.target.closest("[data-mw-modal]");var a;n?s(document.getElementById(n.dataset.mwModal)):e.target.matches("dialog.mw-modal[open]")&&(!("closedBy"in(a=e.target))||null===a.getAttribute("closedby"))&&e.target.close()}),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 o=0;function r(){n.forEach(t=>{e(t,parseInt(t.dataset.index)===o)}),a.forEach(t=>{e(t,parseInt(t.dataset.index)===o)})}function c(e){o=e,r()}a.forEach(e=>{e.addEventListener("click",()=>{c(parseInt(e.dataset.index))})}),r()}),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(l),document.querySelectorAll("[data-calendar]").forEach(i),function(){function e(e){document.querySelectorAll(".mw-dropdown[open]").forEach(t=>{t!==e&&t.removeAttribute("open")})}document.addEventListener("click",function(t){const n=t.target.closest(".mw-dropdown");e(n),n&&t.target.closest(".mw-dropdown-item")&&n.removeAttribute("open")}),document.addEventListener("keydown",function(e){if("Escape"!==e.key)return;const t=document.querySelector(".mw-dropdown[open]");if(!t)return;t.removeAttribute("open");const n=t.querySelector("summary");n&&n.focus()})}(),document.querySelectorAll(".mw-lang-switch").forEach(t=>{const n=t.querySelectorAll("[data-mw-lang]"),a=t.querySelector("summary"),o=t.querySelector("summary .mw-flag"),r=t.querySelector("summary .mw-lang-switch-code");n.forEach(c=>{c.addEventListener("click",function(){const s=c.dataset.mwLang,l=c.querySelector(".mw-lang-switch-name"),i=l?l.textContent.trim():s;n.forEach(t=>{e(t,t===c),t===c?t.setAttribute("aria-current","true"):t.removeAttribute("aria-current")}),r&&(r.textContent=s);const d=c.querySelector(".mw-flag");o&&d&&(o.className=d.className),a&&a.setAttribute("aria-label","Language: "+i),t.dispatchEvent(new CustomEvent("mw-language-change",{bubbles:!0,detail:{lang:s,name:i}}))})})})}),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}}))},window.mwOpenModal=e=>s(document.getElementById(e)),window.mwCloseModal=e=>{var t;(t=document.getElementById(e))&&("DIALOG"===t.tagName?t.close():t.classList.remove("mw-modal-open"))}}();
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "maverick-wave",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "5.0.0",
|
|
4
4
|
"config": {
|
|
5
|
-
"version_short": "
|
|
5
|
+
"version_short": "5.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/scripts/verify.js
CHANGED
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
* 2. every --mw-* definition is used somewhere
|
|
8
8
|
* 3. every mw-* class in the markup exists in the built CSS
|
|
9
9
|
* 4. the committed root release files exist and are not empty
|
|
10
|
+
* 5. the CDN version pinned in the docs matches package.json
|
|
10
11
|
*
|
|
11
12
|
* Sources are scanned rather than hard-coded so a new partial is covered
|
|
12
13
|
* automatically. Exits 1 on any error; warnings never fail the build.
|
|
@@ -72,9 +73,12 @@ const docs = DOCS.map(read).filter(Boolean).map(stripFrontmatter).join('\n');
|
|
|
72
73
|
// --- 1 + 2: custom properties ---------------------------------------------
|
|
73
74
|
|
|
74
75
|
const tokensDefined = new Set(all(css, /(--mw-[a-z0-9-]+)\s*:/g));
|
|
76
|
+
// `\s*` after the paren: a long declaration wrapped by Prettier keeps its
|
|
77
|
+
// newline inside var() all the way through the minifier, and a token used only
|
|
78
|
+
// there would otherwise read as unused.
|
|
75
79
|
const tokensUsed = new Set([
|
|
76
|
-
...all(css, /var\((--mw-[a-z0-9-]+)/g),
|
|
77
|
-
...all(html, /var\((--mw-[a-z0-9-]+)/g),
|
|
80
|
+
...all(css, /var\(\s*(--mw-[a-z0-9-]+)/g),
|
|
81
|
+
...all(html, /var\(\s*(--mw-[a-z0-9-]+)/g),
|
|
78
82
|
...all(js, /(--mw-[a-z0-9-]+)/g),
|
|
79
83
|
]);
|
|
80
84
|
|
|
@@ -136,6 +140,27 @@ for (const f of ['maverick-wave.min.css', 'maverick-wave.min.js']) {
|
|
|
136
140
|
}
|
|
137
141
|
}
|
|
138
142
|
|
|
143
|
+
// --- 5: pinned CDN version -------------------------------------------------
|
|
144
|
+
// Every jsDelivr snippet in the docs pins a version, which is the right advice
|
|
145
|
+
// and the reason it goes stale: 5.0.0 shipped with six snippets still on 4.28.0.
|
|
146
|
+
|
|
147
|
+
const { version } = require(path.join(ROOT, 'package.json'));
|
|
148
|
+
|
|
149
|
+
for (const p of [path.join(ROOT, 'README.md'), ...DOCS]) {
|
|
150
|
+
const md = read(p);
|
|
151
|
+
if (!md) continue;
|
|
152
|
+
const stale = new Set(
|
|
153
|
+
all(md, /maverick-wave@([0-9]+\.[0-9]+\.[0-9]+)/g).filter(
|
|
154
|
+
(v) => v !== version
|
|
155
|
+
)
|
|
156
|
+
);
|
|
157
|
+
for (const v of stale) {
|
|
158
|
+
errors.push(
|
|
159
|
+
`stale CDN pin in ${path.relative(ROOT, p)}: maverick-wave@${v} - package.json is ${version}`
|
|
160
|
+
);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
139
164
|
// Informational: framework classes the showcase never demonstrates
|
|
140
165
|
const undocumented = [...classesInCss].filter(
|
|
141
166
|
(c) => !classesInMarkup.has(c) && !classesInJs.has(c)
|
package/src/js/main.js
CHANGED
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
(function () {
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
// to clear both - otherwise a stale `active` from the HTML would keep a
|
|
7
|
-
// second tab lit.
|
|
4
|
+
// Both spellings are styled, so turning a state off has to clear both or a
|
|
5
|
+
// stale `active` in the HTML keeps a second tab lit
|
|
8
6
|
function setActive(el, on) {
|
|
9
7
|
if (!el) return;
|
|
10
8
|
el.classList.toggle('mw-active', on);
|
|
@@ -40,17 +38,11 @@
|
|
|
40
38
|
initKanbanBoards();
|
|
41
39
|
initCalendars();
|
|
42
40
|
initDropdowns();
|
|
41
|
+
initLangSwitches();
|
|
43
42
|
});
|
|
44
43
|
|
|
45
|
-
//
|
|
46
|
-
//
|
|
47
|
-
// The menu is a <details>, so opening, closing, the keyboard and the state a
|
|
48
|
-
// screen reader reads out are all the browser's job already. Two things it
|
|
49
|
-
// does not do, because no markup can express them: close when the click lands
|
|
50
|
-
// somewhere else, and close on Escape.
|
|
51
|
-
//
|
|
52
|
-
// Delegated to the document rather than bound per dropdown, so a menu added
|
|
53
|
-
// to the page later works without being initialised.
|
|
44
|
+
// The menu is a <details>, so only two things are left: close on an outside
|
|
45
|
+
// click and close on Escape. Delegated, so a menu added later works too.
|
|
54
46
|
function initDropdowns() {
|
|
55
47
|
function closeAll(except) {
|
|
56
48
|
document.querySelectorAll('.mw-dropdown[open]').forEach((dropdown) => {
|
|
@@ -88,6 +80,50 @@
|
|
|
88
80
|
});
|
|
89
81
|
}
|
|
90
82
|
|
|
83
|
+
// Keeps the trigger in step with the choice and announces it - which language
|
|
84
|
+
// actually loads is the application's business, usually the URL or the server:
|
|
85
|
+
// document.addEventListener('mw-language-change', (e) => e.detail.lang)
|
|
86
|
+
function initLangSwitches() {
|
|
87
|
+
document.querySelectorAll('.mw-lang-switch').forEach((languageSwitch) => {
|
|
88
|
+
const items = languageSwitch.querySelectorAll('[data-mw-lang]');
|
|
89
|
+
const summary = languageSwitch.querySelector('summary');
|
|
90
|
+
const triggerFlag = languageSwitch.querySelector('summary .mw-flag');
|
|
91
|
+
const triggerCode = languageSwitch.querySelector(
|
|
92
|
+
'summary .mw-lang-switch-code'
|
|
93
|
+
);
|
|
94
|
+
|
|
95
|
+
items.forEach((item) => {
|
|
96
|
+
item.addEventListener('click', function () {
|
|
97
|
+
const lang = item.dataset.mwLang;
|
|
98
|
+
const nameElement = item.querySelector('.mw-lang-switch-name');
|
|
99
|
+
const label = nameElement ? nameElement.textContent.trim() : lang;
|
|
100
|
+
|
|
101
|
+
items.forEach((other) => {
|
|
102
|
+
setActive(other, other === item);
|
|
103
|
+
if (other === item) other.setAttribute('aria-current', 'true');
|
|
104
|
+
else other.removeAttribute('aria-current');
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
if (triggerCode) triggerCode.textContent = lang;
|
|
108
|
+
|
|
109
|
+
const itemFlag = item.querySelector('.mw-flag');
|
|
110
|
+
if (triggerFlag && itemFlag) {
|
|
111
|
+
triggerFlag.className = itemFlag.className;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
if (summary) summary.setAttribute('aria-label', 'Language: ' + label);
|
|
115
|
+
|
|
116
|
+
languageSwitch.dispatchEvent(
|
|
117
|
+
new CustomEvent('mw-language-change', {
|
|
118
|
+
bubbles: true,
|
|
119
|
+
detail: { lang, name: label },
|
|
120
|
+
})
|
|
121
|
+
);
|
|
122
|
+
});
|
|
123
|
+
});
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
|
|
91
127
|
// ===== Checkbox Lists =====
|
|
92
128
|
function initCheckboxLists() {
|
|
93
129
|
const checkboxLists = document.querySelectorAll(
|
|
@@ -269,6 +305,7 @@
|
|
|
269
305
|
if (!themeToggle) return;
|
|
270
306
|
|
|
271
307
|
const body = document.body;
|
|
308
|
+
const root = document.documentElement;
|
|
272
309
|
const icon = themeToggle.querySelector('.mw-theme-toggle-slider i');
|
|
273
310
|
|
|
274
311
|
const computedStyle = getComputedStyle(document.documentElement);
|
|
@@ -307,8 +344,12 @@
|
|
|
307
344
|
|
|
308
345
|
// Function to apply theme styles and icon
|
|
309
346
|
const applyTheme = (lightMode) => {
|
|
310
|
-
//
|
|
347
|
+
// The forced reflow is the point: the new colours land while transitions are off
|
|
348
|
+
root.classList.add('mw-theme-switching');
|
|
311
349
|
body.classList.toggle('mw-theme-light', lightMode);
|
|
350
|
+
void root.offsetHeight;
|
|
351
|
+
root.classList.remove('mw-theme-switching');
|
|
352
|
+
|
|
312
353
|
setActive(themeToggle, lightMode);
|
|
313
354
|
if (icon) {
|
|
314
355
|
icon.className = lightMode ? 'fas fa-sun' : 'fas fa-moon';
|
|
@@ -324,8 +365,8 @@
|
|
|
324
365
|
applyTheme(isLight);
|
|
325
366
|
localStorage.setItem('mw-theme', isLight ? 'light' : 'dark'); // Save
|
|
326
367
|
|
|
327
|
-
//
|
|
328
|
-
|
|
368
|
+
// No transition left to wait out, so the swatches can read the new values now
|
|
369
|
+
updateColorSwatchHexValues();
|
|
329
370
|
});
|
|
330
371
|
}
|
|
331
372
|
|
|
@@ -335,14 +376,20 @@
|
|
|
335
376
|
}
|
|
336
377
|
|
|
337
378
|
function updateColorSwatchHexValues() {
|
|
338
|
-
const colorSwatches =
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
379
|
+
const colorSwatches = Array.from(
|
|
380
|
+
document.querySelectorAll('.color-swatch')
|
|
381
|
+
);
|
|
382
|
+
|
|
383
|
+
// All reads before the first write - a write between two reads forces a recalc
|
|
384
|
+
const hexValues = colorSwatches.map((swatch) =>
|
|
385
|
+
rgbToHex(window.getComputedStyle(swatch).backgroundColor)
|
|
386
|
+
);
|
|
387
|
+
|
|
388
|
+
colorSwatches.forEach((swatch, index) => {
|
|
342
389
|
const hexTextElement =
|
|
343
390
|
swatch.parentElement.querySelector('.mw-text-muted');
|
|
344
391
|
if (hexTextElement) {
|
|
345
|
-
hexTextElement.textContent =
|
|
392
|
+
hexTextElement.textContent = hexValues[index];
|
|
346
393
|
}
|
|
347
394
|
});
|
|
348
395
|
}
|
|
@@ -406,16 +453,19 @@
|
|
|
406
453
|
|
|
407
454
|
if (!menuBtn || !navbar) return;
|
|
408
455
|
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
456
|
+
// aria-expanded only on a real control - on a <div> it claims a state for nothing
|
|
457
|
+
const announces = menuBtn.tagName === 'BUTTON';
|
|
458
|
+
|
|
459
|
+
function setOpen(open) {
|
|
460
|
+
menuBtn.classList.toggle('open', open);
|
|
461
|
+
navbar.classList.toggle('open', open);
|
|
462
|
+
if (announces) menuBtn.setAttribute('aria-expanded', String(open));
|
|
412
463
|
}
|
|
413
464
|
|
|
414
465
|
function toggleMenu(e) {
|
|
415
466
|
e.preventDefault();
|
|
416
467
|
e.stopPropagation();
|
|
417
|
-
|
|
418
|
-
navbar.classList.toggle('open');
|
|
468
|
+
setOpen(!navbar.classList.contains('open'));
|
|
419
469
|
}
|
|
420
470
|
|
|
421
471
|
// Add multiple event listeners for better iOS compatibility
|
|
@@ -426,38 +476,58 @@
|
|
|
426
476
|
document.addEventListener('click', function (e) {
|
|
427
477
|
if (!navbar.classList.contains('open')) return;
|
|
428
478
|
if (navbar.contains(e.target) || menuBtn.contains(e.target)) return;
|
|
429
|
-
|
|
479
|
+
setOpen(false);
|
|
430
480
|
});
|
|
431
481
|
|
|
482
|
+
// Or Escape strands the keyboard user in a drawer that is no longer there
|
|
432
483
|
document.addEventListener('keydown', function (e) {
|
|
433
|
-
if (e.key
|
|
484
|
+
if (e.key !== 'Escape') return;
|
|
485
|
+
if (!navbar.classList.contains('open')) return;
|
|
486
|
+
setOpen(false);
|
|
487
|
+
menuBtn.focus();
|
|
434
488
|
});
|
|
435
489
|
}
|
|
436
490
|
|
|
437
491
|
// ===== Progress Bars =====
|
|
492
|
+
|
|
493
|
+
// The fill is driven from CSS where the browser can do it (_progress.scss), so
|
|
494
|
+
// this only hands the target width over and switches the animation on
|
|
438
495
|
function initProgressBars() {
|
|
439
496
|
const fills = document.querySelectorAll('.mw-progress-fill');
|
|
440
497
|
if (!fills.length) return;
|
|
441
498
|
|
|
499
|
+
const scrollDriven = CSS.supports('animation-timeline', 'view()');
|
|
500
|
+
|
|
501
|
+
// Two spellings in the wild: data-value="75" and style="width: 75%".
|
|
502
|
+
const targetWidth = (bar) =>
|
|
503
|
+
bar.dataset.value ? bar.dataset.value + '%' : bar.style.width;
|
|
504
|
+
|
|
505
|
+
const driven = [];
|
|
506
|
+
fills.forEach((bar) => {
|
|
507
|
+
const target = targetWidth(bar);
|
|
508
|
+
if (!target) return;
|
|
509
|
+
bar.style.setProperty('--mw-progress-value', target);
|
|
510
|
+
if (scrollDriven) bar.classList.add('mw-progress-driven');
|
|
511
|
+
else driven.push(bar);
|
|
512
|
+
});
|
|
513
|
+
|
|
514
|
+
if (scrollDriven) return;
|
|
515
|
+
|
|
516
|
+
// Fallback: set the width once, when the bar comes into view, and let the
|
|
517
|
+
// transition in _progress.scss animate it. Only bars whose target is known -
|
|
518
|
+
// a bar already carrying its width in the markup is left alone.
|
|
442
519
|
const obs = new IntersectionObserver(
|
|
443
520
|
(entries, observer) => {
|
|
444
521
|
entries.forEach((entry) => {
|
|
445
522
|
if (!entry.isIntersecting) return;
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
// trigger the CSS transition
|
|
449
|
-
bar.style.width = pct + '%';
|
|
450
|
-
// stop observing this one
|
|
451
|
-
observer.unobserve(bar);
|
|
523
|
+
entry.target.style.width = targetWidth(entry.target);
|
|
524
|
+
observer.unobserve(entry.target);
|
|
452
525
|
});
|
|
453
526
|
},
|
|
454
|
-
{
|
|
455
|
-
root: null,
|
|
456
|
-
threshold: 0.2,
|
|
457
|
-
}
|
|
527
|
+
{ root: null, threshold: 0.2 }
|
|
458
528
|
);
|
|
459
529
|
|
|
460
|
-
|
|
530
|
+
driven.forEach((bar) => obs.observe(bar));
|
|
461
531
|
}
|
|
462
532
|
|
|
463
533
|
// ===== Smooth Scrolling =====
|
|
@@ -487,10 +557,8 @@
|
|
|
487
557
|
|
|
488
558
|
if (sections.length === 0 || navLinks.length === 0) return;
|
|
489
559
|
|
|
490
|
-
//
|
|
491
|
-
//
|
|
492
|
-
// target as soon as an announcement ribbon raises the padding. Read per
|
|
493
|
-
// run: the ribbon grows on small screens and can be dismissed at runtime.
|
|
560
|
+
// Measured against scroll-padding-top, the same value an anchor jump lands on,
|
|
561
|
+
// and read per run - the ribbon grows on small screens and can be dismissed
|
|
494
562
|
function scrollOffset() {
|
|
495
563
|
const padding = parseFloat(
|
|
496
564
|
getComputedStyle(document.documentElement).scrollPaddingTop
|
|
@@ -532,35 +600,109 @@
|
|
|
532
600
|
);
|
|
533
601
|
}
|
|
534
602
|
|
|
535
|
-
//
|
|
603
|
+
// The strip draws the marker, this only hands over position and length as custom
|
|
604
|
+
// properties. Both axes every time - which pair the bar uses is the stylesheet's
|
|
605
|
+
// decision, at a breakpoint this file knows nothing of. The attribute switches
|
|
606
|
+
// the bar on and is set after the first measurement, so a page without script
|
|
607
|
+
// keeps the plain border and still looks finished.
|
|
608
|
+
function measureTabsMarker(nav) {
|
|
609
|
+
const active = nav.querySelector(
|
|
610
|
+
'.mw-tabs-nav-item.mw-active, .mw-tabs-nav-item.active'
|
|
611
|
+
);
|
|
612
|
+
if (!active) {
|
|
613
|
+
nav.removeAttribute('data-mw-tabs-marker');
|
|
614
|
+
return;
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
// Unitless for the scale factors: the bar is 1px long and scaled up.
|
|
618
|
+
nav.style.setProperty('--mw-tabs-marker-x', active.offsetLeft + 'px');
|
|
619
|
+
nav.style.setProperty('--mw-tabs-marker-w', active.offsetWidth);
|
|
620
|
+
nav.style.setProperty('--mw-tabs-marker-y', active.offsetTop + 'px');
|
|
621
|
+
nav.style.setProperty('--mw-tabs-marker-h', active.offsetHeight);
|
|
622
|
+
nav.setAttribute('data-mw-tabs-marker', '');
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
// Set here and not in the markup, so a page that already ships .mw-tabs gets the
|
|
626
|
+
// tablist semantics by loading the script
|
|
536
627
|
function initTabs() {
|
|
537
|
-
|
|
628
|
+
document.querySelectorAll('.mw-tabs-nav').forEach((nav) => {
|
|
629
|
+
const items = Array.from(nav.querySelectorAll('.mw-tabs-nav-item'));
|
|
630
|
+
if (!items.length) return;
|
|
538
631
|
|
|
539
|
-
|
|
540
|
-
item.addEventListener('click', function () {
|
|
541
|
-
const tabsContainer = this.closest('.mw-tabs');
|
|
542
|
-
if (!tabsContainer) return;
|
|
632
|
+
const vertical = !!nav.closest('.mw-tabs-vertical');
|
|
543
633
|
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
.forEach((navItem) => {
|
|
547
|
-
setActive(navItem, false);
|
|
548
|
-
});
|
|
634
|
+
nav.setAttribute('role', 'tablist');
|
|
635
|
+
if (vertical) nav.setAttribute('aria-orientation', 'vertical');
|
|
549
636
|
|
|
550
|
-
|
|
637
|
+
items.forEach((item, index) => {
|
|
638
|
+
const panel = tabPanelOf(item);
|
|
551
639
|
|
|
552
|
-
|
|
553
|
-
if (!
|
|
640
|
+
item.setAttribute('role', 'tab');
|
|
641
|
+
if (!item.id) item.id = (panel ? panel.id : 'mw-tab-' + index) + '-tab';
|
|
554
642
|
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
643
|
+
if (panel) {
|
|
644
|
+
item.setAttribute('aria-controls', panel.id);
|
|
645
|
+
panel.setAttribute('role', 'tabpanel');
|
|
646
|
+
panel.setAttribute('aria-labelledby', item.id);
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
syncTabState(item);
|
|
650
|
+
|
|
651
|
+
item.addEventListener('click', () => selectTab(items, item));
|
|
558
652
|
|
|
559
|
-
|
|
653
|
+
item.addEventListener('keydown', (event) => {
|
|
654
|
+
const target = tabKeyTarget(event, vertical, items.length, index);
|
|
655
|
+
if (target === null) return;
|
|
656
|
+
event.preventDefault();
|
|
657
|
+
selectTab(items, items[target]);
|
|
658
|
+
items[target].focus();
|
|
659
|
+
});
|
|
560
660
|
});
|
|
661
|
+
|
|
662
|
+
measureTabsMarker(nav);
|
|
663
|
+
|
|
664
|
+
// The items are watched too: a web font arriving moves the label the bar is
|
|
665
|
+
// parked under without the strip itself changing size
|
|
666
|
+
const observer = new ResizeObserver(() => measureTabsMarker(nav));
|
|
667
|
+
observer.observe(nav);
|
|
668
|
+
items.forEach((item) => observer.observe(item));
|
|
561
669
|
});
|
|
562
670
|
}
|
|
563
671
|
|
|
672
|
+
function tabPanelOf(item) {
|
|
673
|
+
const id = item.getAttribute('data-tab');
|
|
674
|
+
return id ? document.getElementById(id) : null;
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
function syncTabState(item) {
|
|
678
|
+
const on = isActive(item);
|
|
679
|
+
item.setAttribute('aria-selected', String(on));
|
|
680
|
+
item.tabIndex = on ? 0 : -1;
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
function selectTab(items, item) {
|
|
684
|
+
items.forEach((other) => {
|
|
685
|
+
const on = other === item;
|
|
686
|
+
setActive(other, on);
|
|
687
|
+
setActive(tabPanelOf(other), on);
|
|
688
|
+
syncTabState(other);
|
|
689
|
+
});
|
|
690
|
+
|
|
691
|
+
const nav = item.closest('.mw-tabs-nav');
|
|
692
|
+
if (nav) measureTabsMarker(nav);
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
function tabKeyTarget(event, vertical, count, index) {
|
|
696
|
+
const back = vertical ? 'ArrowUp' : 'ArrowLeft';
|
|
697
|
+
const forward = vertical ? 'ArrowDown' : 'ArrowRight';
|
|
698
|
+
|
|
699
|
+
if (event.key === back) return (index - 1 + count) % count;
|
|
700
|
+
if (event.key === forward) return (index + 1) % count;
|
|
701
|
+
if (event.key === 'Home') return 0;
|
|
702
|
+
if (event.key === 'End') return count - 1;
|
|
703
|
+
return null;
|
|
704
|
+
}
|
|
705
|
+
|
|
564
706
|
// ===== Alerts =====
|
|
565
707
|
function initAlerts() {
|
|
566
708
|
const alertCloseButtons = document.querySelectorAll('.mw-alert-close');
|
|
@@ -640,17 +782,71 @@
|
|
|
640
782
|
}
|
|
641
783
|
|
|
642
784
|
// ===== Modals =====
|
|
785
|
+
|
|
786
|
+
// Two shapes: the older `mw-modal-overlay` div toggled by class, and `<dialog>`,
|
|
787
|
+
// where focus trap, Escape and the inert background are the browser's job.
|
|
788
|
+
// Delegated, so a modal added later works too.
|
|
643
789
|
function initModals() {
|
|
644
|
-
document.
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
790
|
+
document.addEventListener('click', (e) => {
|
|
791
|
+
const closer = e.target.closest('.mw-modal-close');
|
|
792
|
+
if (closer) {
|
|
793
|
+
const dialog = closer.closest('dialog.mw-modal');
|
|
794
|
+
if (dialog) {
|
|
795
|
+
dialog.close();
|
|
796
|
+
return;
|
|
649
797
|
}
|
|
650
|
-
|
|
798
|
+
const overlay = closer.closest('.mw-modal-overlay');
|
|
799
|
+
if (overlay) overlay.classList.remove('mw-modal-open');
|
|
800
|
+
return;
|
|
801
|
+
}
|
|
802
|
+
|
|
803
|
+
const opener = e.target.closest('[data-mw-modal]');
|
|
804
|
+
if (opener) {
|
|
805
|
+
openModal(document.getElementById(opener.dataset.mwModal));
|
|
806
|
+
return;
|
|
807
|
+
}
|
|
808
|
+
|
|
809
|
+
// Light dismiss for a dialog the browser does not dismiss itself. A click
|
|
810
|
+
// that lands on the dialog element is a click on the backdrop - the
|
|
811
|
+
// content sits in .mw-modal-header/body/footer inside it.
|
|
812
|
+
if (
|
|
813
|
+
e.target.matches('dialog.mw-modal[open]') &&
|
|
814
|
+
!dismissesItself(e.target)
|
|
815
|
+
) {
|
|
816
|
+
e.target.close();
|
|
817
|
+
}
|
|
651
818
|
});
|
|
652
819
|
}
|
|
653
820
|
|
|
821
|
+
// True when `closedby` is on the element *and* understood, which is the only
|
|
822
|
+
// case where the browser closes the dialog on a backdrop click by itself.
|
|
823
|
+
function dismissesItself(dialog) {
|
|
824
|
+
return 'closedBy' in dialog && dialog.getAttribute('closedby') !== null;
|
|
825
|
+
}
|
|
826
|
+
|
|
827
|
+
// Opens either shape. Exposed, because which modal opens when is the
|
|
828
|
+
// application's decision and not something markup can express on its own.
|
|
829
|
+
function openModal(modal) {
|
|
830
|
+
if (!modal) return;
|
|
831
|
+
if (modal.tagName === 'DIALOG') {
|
|
832
|
+
modal.showModal();
|
|
833
|
+
} else {
|
|
834
|
+
modal.classList.add('mw-modal-open');
|
|
835
|
+
}
|
|
836
|
+
}
|
|
837
|
+
|
|
838
|
+
function closeModal(modal) {
|
|
839
|
+
if (!modal) return;
|
|
840
|
+
if (modal.tagName === 'DIALOG') {
|
|
841
|
+
modal.close();
|
|
842
|
+
} else {
|
|
843
|
+
modal.classList.remove('mw-modal-open');
|
|
844
|
+
}
|
|
845
|
+
}
|
|
846
|
+
|
|
847
|
+
window.mwOpenModal = (id) => openModal(document.getElementById(id));
|
|
848
|
+
window.mwCloseModal = (id) => closeModal(document.getElementById(id));
|
|
849
|
+
|
|
654
850
|
// ===== Login Button =====
|
|
655
851
|
function initHeaderLoginButton() {
|
|
656
852
|
const loginButton = document.getElementById('login-button');
|
|
@@ -875,14 +1071,9 @@
|
|
|
875
1071
|
|
|
876
1072
|
target.querySelector('.mw-kanban-column-body').appendChild(card);
|
|
877
1073
|
|
|
878
|
-
//
|
|
879
|
-
//
|
|
880
|
-
//
|
|
881
|
-
//
|
|
882
|
-
// Both classes come off first and the reflow is forced in between: an
|
|
883
|
-
// element that already carries the class it is being given again keeps
|
|
884
|
-
// the finished animation and plays nothing, so a second push in the same
|
|
885
|
-
// direction would be the silent one.
|
|
1074
|
+
// Re-parenting alone makes the card blink into the other column, so it comes
|
|
1075
|
+
// in from the side it was pushed from. Both classes come off first with a
|
|
1076
|
+
// forced reflow between, or a second push in the same direction is silent.
|
|
886
1077
|
card.classList.remove.apply(card.classList, MOVE_CLASSES);
|
|
887
1078
|
void card.offsetWidth;
|
|
888
1079
|
card.classList.add(offset > 0 ? MOVE_CLASSES[0] : MOVE_CLASSES[1]);
|