1/** 2 * MMX / BUTTON 3 */ 4 5class MMX_Button extends MMX_Element { 6 7 static get props() { 8 return { 9 style: { 10 options: ['primary', 'secondary', 'display-link', 'primary-link', 'secondary-link', 'dark-primary', 'dark-secondary', 'dark-display-link', 'dark-primary-link', 'dark-secondary-link', 'pill', 'close'], 11 default: 'primary' 12 }, 13 size: { 14 options: ['xs', 's', 'm', 'l'], 15 default: 'm' 16 }, 17 theme: { 18 allowAny: true, 19 isBoolean: true, 20 default: false 21 }, 22 'theme-class': { 23 allowAny: true, 24 default: '' 25 }, 26 width: { 27 options: ['auto', 'full'], 28 default: 'auto' 29 }, 30 type: { 31 options: ['submit', 'reset', 'button', 'link'], 32 default: '' // Default can be either `button` or `link` and is determined in getType() 33 }, 34 shape: { 35 options: ['normal', 'round'], 36 default: 'normal' 37 } 38 }; 39 } 40 41 styleResourceCodes = ['mmx-base', 'mmx-button', 'mm-theme-styles']; 42 hideOnEmpty = true; 43 44 constructor() { 45 super(); 46 this.makeShadow(); 47 } 48 49 render() { 50 const tag = this.getTag(); 51 const theme = this.getPropValue('theme'); 52 53 if (theme) { 54 return this.#renderTheme({tag}); 55 } 56 57 return /*html*/` 58 <${tag} class="mmx-button ${this.getStyleClass()} mmx-button__size--${this.getPropValue('size')} mmx-button__width--${this.getPropValue('width')} mmx-button__shape--${this.getPropValue('shape')} ${this.darkClass()}" ${this.inheritAttrs()} part="button" data-mmx-button> 59 <slot></slot> 60 </${tag}> 61 `; 62 } 63 64 #renderTheme({tag} = {}) { 65 const theme_class = this.getPropValue('theme-class'); 66 67 return /*html*/` 68 ${this.#renderThemeStylesheet()} 69 <${tag} class="mmx-theme-button mmx-theme-button__width--${this.getPropValue('width')} ${MMX.encodeEntities(theme_class)}" ${this.inheritAttrs()} data-mmx-button> 70 <slot></slot> 71 </${tag}> 72 `; 73 } 74 75 #renderThemeStylesheet() { 76 const theme_stylesheet = this.querySelector(':scope > template[data-theme-stylesheet]'); 77 let variable_override_css = ''; 78 let variable_override_styles = new Array(); 79 80 if (getComputedStyle(this).getPropertyValue('--mmx-theme-button__height')?.length) variable_override_styles.push('height: var(--mmx-theme-button__height, auto) !important;'); 81 if (getComputedStyle(this).getPropertyValue('--mmx-theme-button__line-height')?.length) variable_override_styles.push('line-height: var(--mmx-theme-button__line-height, auto) !important;'); 82 if (getComputedStyle(this).getPropertyValue('--mmx-theme-button__padding-bottom')?.length) variable_override_styles.push('padding-bottom: var(--mmx-theme-button__padding-bottom, auto) !important;'); 83 if (getComputedStyle(this).getPropertyValue('--mmx-theme-button__padding-top')?.length) variable_override_styles.push('padding-top: var(--mmx-theme-button__padding-top, auto) !important;'); 84 85 if (variable_override_styles.length) { 86 variable_override_css = /*html*/` 87 .mmx-theme-button { 88 ${variable_override_styles.join('\n')} 89 } 90 `; 91 } 92 93 if (!theme_stylesheet && !variable_override_css.length) { 94 return ''; 95 } 96 97 return /*html*/` 98 <style type="text/css"> 99 ${theme_stylesheet?.content?.textContent ?? ''} 100 ${variable_override_css} 101 </style> 102 `; 103 } 104 105 afterRender() { 106 var type, button, listener; 107 108 if (!(button = this.getButton())) { 109 return; 110 } 111 112 for (type in this.#listeners) { 113 if (!this.#listeners.hasOwnProperty(type)) { 114 continue; 115 } 116 117 for (listener of this.#listeners[type]) { 118 button.addEventListener(type, listener.listener, listener.options); 119 } 120 } 121 122 switch (this.getType()) { 123 case 'submit' : button.addEventListener('click', MMX_Button.eventSubmitClick, false); break; 124 case 'reset' : button.addEventListener('click', MMX_Button.eventResetClick, false); break; 125 } 126 } 127 128 static eventSubmitClick(e) { 129 const form = MMX.closestElement('form', this); 130 131 if (form) { 132 form.addEventListener('submit', MMX_Button.eventSubmitClickForm, false); 133 if (form.reportValidity()) { 134 form.dispatchEvent(new Event('submit', { cancelable: true })); 135 } 136 } 137 } 138 139 static eventSubmitClickForm(e) { 140 if (!e.defaultPrevented) { 141 this.submit(); 142 } 143 144 this.removeEventListener('submit', MMX_Button.eventSubmitClickForm, false); 145 } 146 147 static eventResetClick(e) { 148 const form = MMX.closestElement('form', this); 149 150 if (form) { 151 form.addEventListener('reset', MMX_Button.eventResetClickForm, false); 152 form.dispatchEvent(new Event('reset')); 153 } 154 } 155 156 static eventResetClickForm(e) { 157 if (!e.defaultPrevented) { 158 this.reset(); 159 } 160 161 this.removeEventListener('reset', MMX_Button.eventResetClickForm, false); 162 } 163 164 getStyleClass() { 165 const style = this.getPropValue('style'); 166 let result = `mmx-button__${style}`; 167 168 if ( style.indexOf('close') > -1 ) { 169 result += ' mmx-button__close'; 170 } else if ( style.indexOf('pill') > -1 ) { 171 result += ' mmx-button__pill'; 172 } else if ( style.indexOf('link') > -1 ) { 173 result += ' mmx-button__link'; 174 } else { 175 result += ' mmx-button__button'; 176 } 177 178 return result; 179 } 180 181 getButton() { 182 return this.shadowRoot.querySelector('[data-mmx-button]'); 183 } 184 185 getTag() { 186 return this.hasAttribute('href') ? 'a' : 'button'; 187 } 188 189 getType() { 190 switch (this.getPropValue('type')) { 191 case 'submit' : return 'submit'; 192 case 'reset' : return 'reset'; 193 case 'button' : return 'button'; 194 case 'link' : return 'link'; 195 default: { 196 if (this.hasAttribute('href')) { 197 return 'link'; 198 } 199 200 return 'button'; 201 } 202 } 203 } 204 205 darkClass() { 206 return this.isDark() ? 'mmx-theme--dark' : ''; 207 } 208 209 isDark() { 210 return this.hasAttribute('data-dark') || this.getPropValue('style').indexOf('dark') === 0; 211 } 212 213 // 214 // Attributes 215 // 216 217 static get observedAttributes() { 218 return ['disabled', ...this.propsToAttributeNames]; 219 } 220 221 attributeChanged(name, oldValue, newValue) { 222 var button; 223 224 if (name === 'disabled') { 225 if (button = this.getButton()) { 226 if (MMX.getBooleanAttribute(this, 'disabled')) { 227 this.classList.add('disabled'); 228 button.disabled = true; 229 } 230 else { 231 this.classList.remove('disabled'); 232 button.disabled = false;
233 } 234 } 235 } 236 } 237 238 get disabled() { return MMX.getBooleanAttribute(this, 'disabled'); } 239 set disabled(disabled) { MMX.setBooleanAttribute(this, 'disabled', disabled); } 240 241 // 242 // Listeners 243 // 244 245 #listeners = new Object(); 246 247 addButtonEventListener(type, listener, options) { 248 var button; 249 250 if (!Array.isArray(this.#listeners[type])) { 251 this.#listeners[type] = new Array(); 252 } 253 254 if (this.#listeners[type].find(search_listener => search_listener.listener === listener && JSON.stringify(search_listener.options) === JSON.stringify(options))) { 255 return; 256 } 257 258 this.#listeners[type].push({listener: listener, options: options}); 259 260 if (button = this.getButton()) { 261 button.addEventListener(type, listener, options); 262 } 263 } 264 265 removeButtonEventListener(type, listener, options) { 266 var index, button; 267 268 if (!Array.isArray(this.#listeners[type])) { 269 return; 270 } 271 272 if ((index = this.#listeners[type].findIndex(search_listener => search_listener.listener === listener && JSON.stringify(search_listener.options) === JSON.stringify(options))) === -1) { 273 return; 274 } 275 276 this.#listeners[type].splice(index, 1); 277 278 if (button = this.getButton()) { 279 button.removeEventListener(type, listener, options); 280 } 281 } 282} 283 284if (!customElements.get('mmx-button')){ 285 customElements.define('mmx-button', MMX_Button); 286}
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.