semantic-forms 5.2.2 → 5.3.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/CHANGELOG.md CHANGED
@@ -1,3 +1,10 @@
1
+ ## 5.3.0
2
+
3
+ - Added `align-start`, `align-center`, and `align-end` classes that align form inputs within their available space.
4
+ - Added the ability to include individual buttons into the responsive form grid.
5
+ - Updated the preferred form markup to wrap each `<dt>` and `<dd>` pair in a `<div>`.
6
+ - Updated dependencies.
7
+
1
8
  ## 5.2.2
2
9
 
3
10
  - Fixed a bug in `data-auto-grow` fields that would apply a scrollbar inappropriately.
@@ -1,85 +1,66 @@
1
1
  (function(root,factory){if(typeof exports==="object"&&typeof module==="object")module.exports=factory();else if(typeof define==="function"&&define.amd)define("semanticForms",[],factory);else if(typeof exports==="object")exports["semanticForms"]=factory();else root["semanticForms"]=factory()})(this,()=>/******/(()=>{// webpackBootstrap
2
2
  /******/var __webpack_modules__={
3
- /***/"./semanticForms.js":
4
- /*!**************************!*\
5
- !*** ./semanticForms.js ***!
6
- \**************************/
7
- /***/module=>{const semanticForms=()=>{
8
- // do some feature detection so none of the JS executes if the browser is too old
9
- if(typeof document.getElementsByClassName!=="function"||typeof document.querySelector!=="function"||!document.body.classList||!window.MutationObserver){console.warn("semantic-forms was loaded into an unsupported browser and will not execute.");return}const passwordShow='<svg fill="none" height="256" viewBox="0 0 24 24" width="256" xmlns="http://www.w3.org/2000/svg"><g stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"><path d="m1 12s4-8 11-8 11 8 11 8"/><path d="m1 12s4 8 11 8 11-8 11-8"/><circle cx="12" cy="12" r="3"/></g></svg>';const passwordHide='<svg fill="none" height="256" viewBox="0 0 24 24" width="256" xmlns="http://www.w3.org/2000/svg"><g stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"><path d="m2 2 20 20"/><path d="m6.71277 6.7226c-3.04798 2.07267-4.71277 5.2774-4.71277 5.2774s3.63636 7 10 7c2.0503 0 3.8174-.7266 5.2711-1.7116m-6.2711-12.23018c.3254-.03809.6588-.05822 1-.05822 6.3636 0 10 7 10 7s-.6918 1.3317-2 2.8335"/><path d="m14 14.2362c-.5308.475-1.2316.7639-2 .7639-1.6569 0-3-1.3431-3-3 0-.8237.33193-1.5698.86932-2.11192"/></g></svg>';const helpTextIcon='<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="16" height="16" viewBox="0 0 16 16" version="1.1" style="overflow:visible;"><rect width="16" height="16" fill="none"/><path fill="currentColor" d="M8,10.5c-0.552,0-1,0.448-1,1c0,0.552,0.448,1,1,1c0.552,0,1-0.448,1-1C9,10.948,8.552,10.5,8,10.5z M8,0 C3.582,0,0,3.582,0,8c0,4.418,3.582,8,8,8s8-3.582,8-8C16,3.582,12.418,0,8,0z M12.243,12.243C11.109,13.376,9.603,14,8,14 s-3.109-0.624-4.243-1.757C2.624,11.109,2,9.603,2,8s0.624-3.109,1.757-4.243C4.891,2.624,6.397,2,8,2s3.109,0.624,4.243,1.757 C13.376,4.891,14,6.397,14,8C14,9.603,13.376,11.109,12.243,12.243z M7.927,3.755c-2.248,0-2.76,1.695-2.802,2.906h1.571 c0.028-0.256,0.101-1.418,1.221-1.418c0.672,0,1.206,0.406,1.206,1.175c0,0.695-0.724,1.155-1.303,1.711 C7.241,8.685,7.168,9.325,7.168,9.824V10c0.146,0,1.615,0,1.615,0V9.824c0-1.256,1.967-1.594,1.967-3.541 C10.75,5.059,9.874,3.755,7.927,3.755z"/></svg>';const nodeNameLookup=["TEXTAREA","SELECT"];const inputTypeLookup=["checkbox","color","date","datetime-local","email","file","image","month","number","password","radio","range","search","tel","text","time","url","week"];const keyboardShortcuts=[];
10
- // custom keyboard shortcut listener
11
- document.addEventListener("keydown",e=>{const specialCharMap={Minus:"-",Equal:"=",BracketLeft:"[",BracketRight:"]",Backslash:"\\",Semicolon:";",Quote:"'",Comma:",",Period:".",Slash:"/",Backquote:"`"};const shiftSpecialCharMap={1:"!",2:"@",3:"#",4:"$",5:"%",6:"^",7:"&",8:"*",9:"(",0:")",Minus:"_",Equal:"+",BracketLeft:"{",BracketRight:"}",Backslash:"|",Semicolon:":",Quote:'"',Comma:"<",Period:">",Slash:"?",Backquote:"~"};const shortcut=keyboardShortcuts.find(shortcut=>{let matchesKey=false;if(e.altKey&&!e.shiftKey)
12
- // mac adjusts the key value if altKey is pressed
13
- matchesKey="Key"+shortcut.key.toUpperCase()===e.code||"Digit"+shortcut.key.toUpperCase()===e.code||shortcut.key===e.key||specialCharMap[e.code]===shortcut.key;else if(e.shiftKey){
14
- // check shift special character map
15
- const code=e.code.replace(/Key|Digit/,"");matchesKey=(shiftSpecialCharMap[code]||shiftSpecialCharMap[e.key])&&(shiftSpecialCharMap[code]===shortcut.key||shiftSpecialCharMap[e.key]===shortcut.key)}else matchesKey=shortcut.key.toUpperCase()===e.key.toUpperCase();if(!matchesKey)return false;let matchesModifier;if(shortcut.modifier){if(shortcut.modifier===shortcut.defaultModifier)matchesModifier=shortcut.os==="windows"||shortcut.os==="linux"?e.ctrlKey:e.metaKey;if(shortcut.modifier==="meta")matchesModifier=e.metaKey;if(shortcut.modifier==="alt")matchesModifier=e.altKey;if(shortcut.modifier==="ctrl")matchesModifier=e.ctrlKey}return matchesModifier});if(shortcut){e.preventDefault();shortcut.input.focus()}});
16
- // progressively enhance form elements that have the semanticForms class
17
- const forms=document.querySelectorAll("form.semanticForms:not(.semanticFormsActive), table.semanticForms:not(.semanticFormsActive)");for(const form of forms){form.classList.add("semanticFormsActive");if(form.classList.contains("lowFlow"))continue;
18
- // update each input in the semantic form
19
- const inputs=Array.from(form.querySelectorAll("input, textarea, select"));for(let input of inputs){
3
+ /***/"./lib/helpers.js":
4
+ /*!************************!*\
5
+ !*** ./lib/helpers.js ***!
6
+ \************************/
7
+ /***/module=>{
8
+ /**
9
+ * Uses the navigator to best determine the clients operating system.
10
+ * @returns Operating system string (`mac`, `windows`, `linux`)
11
+ */
12
+ const getOS=()=>{const userAgent=window.navigator.userAgent;const platform=window.navigator.platform;let os=null;if(platform.includes("Win"))os="windows";else if(platform.includes("Mac")||/iPhone|iPad|iPod/.test(userAgent))os="mac";else if(platform.includes("Linux")||/Android/.test(userAgent))os="linux";return os}
13
+ /**
14
+ * Places an element immediately after another element
15
+ * @param {Object} newNode element being placed after the reference node
16
+ * @param {*} referenceNode element to be used as reference for new node
17
+ */;const insertAfter=(newNode,referenceNode)=>{if(referenceNode.nextSibling)referenceNode.parentNode.insertBefore(newNode,referenceNode.nextSibling);else referenceNode.parentNode.appendChild(newNode)};module.exports={getOS,insertAfter}
18
+ /***/},
19
+ /***/"./lib/inputEnhancements.js":
20
+ /*!**********************************!*\
21
+ !*** ./lib/inputEnhancements.js ***!
22
+ \**********************************/
23
+ /***/(module,__unused_webpack_exports,__webpack_require__)=>{const{insertAfter}=__webpack_require__(/*! ./helpers.js */"./lib/helpers.js");const icons={passwordShow:'<svg fill="none" height="256" viewBox="0 0 24 24" width="256" xmlns="http://www.w3.org/2000/svg"><g stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"><path d="m1 12s4-8 11-8 11 8 11 8"/><path d="m1 12s4 8 11 8 11-8 11-8"/><circle cx="12" cy="12" r="3"/></g></svg>',passwordHide:'<svg fill="none" height="256" viewBox="0 0 24 24" width="256" xmlns="http://www.w3.org/2000/svg"><g stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"><path d="m2 2 20 20"/><path d="m6.71277 6.7226c-3.04798 2.07267-4.71277 5.2774-4.71277 5.2774s3.63636 7 10 7c2.0503 0 3.8174-.7266 5.2711-1.7116m-6.2711-12.23018c.3254-.03809.6588-.05822 1-.05822 6.3636 0 10 7 10 7s-.6918 1.3317-2 2.8335"/><path d="m14 14.2362c-.5308.475-1.2316.7639-2 .7639-1.6569 0-3-1.3431-3-3 0-.8237.33193-1.5698.86932-2.11192"/></g></svg>',helpIcon:'<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="16" height="16" viewBox="0 0 16 16" version="1.1" style="overflow:visible;"><rect width="16" height="16" fill="none"/><path fill="currentColor" d="M8,10.5c-0.552,0-1,0.448-1,1c0,0.552,0.448,1,1,1c0.552,0,1-0.448,1-1C9,10.948,8.552,10.5,8,10.5z M8,0 C3.582,0,0,3.582,0,8c0,4.418,3.582,8,8,8s8-3.582,8-8C16,3.582,12.418,0,8,0z M12.243,12.243C11.109,13.376,9.603,14,8,14 s-3.109-0.624-4.243-1.757C2.624,11.109,2,9.603,2,8s0.624-3.109,1.757-4.243C4.891,2.624,6.397,2,8,2s3.109,0.624,4.243,1.757 C13.376,4.891,14,6.397,14,8C14,9.603,13.376,11.109,12.243,12.243z M7.927,3.755c-2.248,0-2.76,1.695-2.802,2.906h1.571 c0.028-0.256,0.101-1.418,1.221-1.418c0.672,0,1.206,0.406,1.206,1.175c0,0.695-0.724,1.155-1.303,1.711 C7.241,8.685,7.168,9.325,7.168,9.824V10c0.146,0,1.615,0,1.615,0V9.824c0-1.256,1.967-1.594,1.967-3.541 C10.75,5.059,9.874,3.755,7.927,3.755z"/></svg>'};const lookups={nodeName:["TEXTAREA","SELECT"],inputType:["checkbox","color","date","datetime-local","email","file","image","month","number","password","radio","range","search","tel","text","time","url","week"]};let lastFocusedInput;let lastClearFieldPressed;const enhanceInput=(input,form)=>{
20
24
  // ignore input if it has previously been formatted
21
- if(input.classList.contains("semanticform")||!input.id)continue;const type=input.getAttribute("type");if(nodeNameLookup.includes(input.nodeName)||inputTypeLookup.includes(type)){
25
+ if(input.classList.contains("semanticform")||!input.id)return;const type=input.getAttribute("type");if(!lookups.nodeName.includes(input.nodeName)&&!lookups.inputType.includes(type))return;
22
26
  // recursively find <dl> element
23
- let dl=input.parentNode;while(dl&&dl.nodeName!=="DL")dl=dl.parentNode;if(!dl)continue;if(!dl.classList.contains("floatLabelForm"))dl.classList.add("floatLabelForm");const label=input.parentNode.parentNode.id&&(type==="checkbox"||type==="radio")?document.querySelector("label[data-for="+input.parentNode.parentNode.id.replace(/\./g,"\\.")+"]"):document.querySelector("label[for="+input.id.replace(/\./g,"\\.")+"]");if(!label)console.error(`semantic-forms: Found an input (${input.id||input.getAttribute("name")}) without a properly associated label. Make sure there is a label for it and the label has a matching "for" attribute.`);input.classList.add("semanticform");
27
+ let dl=input.parentNode;while(dl&&dl.nodeName!=="DL")dl=dl.parentNode;if(!dl)return;if(!dl.classList.contains("floatLabelForm"))dl.classList.add("floatLabelForm");const label=input.parentNode.parentNode.id&&(type==="checkbox"||type==="radio")?document.querySelector("label[data-for="+input.parentNode.parentNode.id.replace(/\./g,"\\.")+"]"):document.querySelector("label[for="+input.id.replace(/\./g,"\\.")+"]");if(!label)console.error(`semantic-forms: Found an input (${input.id||input.getAttribute("name")}) without a properly associated label. Make sure there is a label for it and the label has a matching "for" attribute.`);input.classList.add("semanticform");
24
28
  // #region create labels
25
29
  const newLabel=document.createElement("label");newLabel.className="floatLabelFormAnimatedLabel";if(type==="checkbox"||type==="radio"){
26
30
  // recursively find <dd> element
27
- let dd=input.parentNode;while(dd&&dd.nodeName!=="DD")dd=dd.parentNode;if(!dd){console.error(`semantic-forms: Found an input (${input.id||input.getAttribute("name")}) that is not inside a <dd> element.`);continue}if(dd.firstChild.nodeName!=="LABEL"){if(type==="checkbox"&&input.parentNode.nodeName==="DD"){newLabel.setAttribute("for",input.id);input.parentNode.classList.add("singleCheckbox");newLabel.className="";label.setAttribute("hidden","hidden");insertAfter(newLabel,input)}if(type==="radio"&&input.parentNode.nodeName==="DD"){newLabel.setAttribute("for",input.id);input.parentNode.classList.add("singleRadio");newLabel.className="";label.setAttribute("hidden","hidden");insertAfter(newLabel,input)}newLabel.innerHTML=label.innerHTML;if(label.hasAttribute("title")&&label.getAttribute("data-show-help-icon")!==null&&!label.querySelector("span.help")){const text=label.getAttribute("title");label.innerHTML+=` <span title="${text}" class="help">${helpTextIcon}</span>`;newLabel.innerHTML+=` <span title="${text}" class="help">${helpTextIcon}</span>`}if(dd.querySelector(":required")&&label.getAttribute("data-no-asterisk")===null&&!label.querySelector("span.required")){const text=label.getAttribute("data-asterisk-text")||"This field is required.";label.innerHTML+=` <span title="${text}" class="required">*</span>`;newLabel.innerHTML+=` <span title="${text}" class="required">*</span>`}if(!dd.querySelector("label"))dd.append(newLabel)}
31
+ let dd=input.parentNode;while(dd&&dd.nodeName!=="DD")dd=dd.parentNode;if(!dd){console.error(`semantic-forms: Found an input (${input.id||input.getAttribute("name")}) that is not inside a <dd> element.`);return}if(dd.firstChild.nodeName!=="LABEL"){if(type==="checkbox"&&input.parentNode.nodeName==="DD"){newLabel.setAttribute("for",input.id);input.parentNode.classList.add("singleCheckbox");newLabel.className="";label.setAttribute("hidden","hidden");insertAfter(newLabel,input)}if(type==="radio"&&input.parentNode.nodeName==="DD"){newLabel.setAttribute("for",input.id);input.parentNode.classList.add("singleRadio");newLabel.className="";label.setAttribute("hidden","hidden");insertAfter(newLabel,input)}newLabel.innerHTML=label.innerHTML;if(label.hasAttribute("title")&&label.getAttribute("data-show-help-icon")!==null&&!label.querySelector("span.help")){const text=label.getAttribute("title");label.innerHTML+=` <span title="${text}" class="help">${icons.helpIcon}</span>`;newLabel.innerHTML+=` <span title="${text}" class="help">${icons.helpIcon}</span>`}if(dd.querySelector(":required")&&label.getAttribute("data-no-asterisk")===null&&!label.querySelector("span.required")){const text=label.getAttribute("data-asterisk-text")||"This field is required.";label.innerHTML+=` <span title="${text}" class="required">*</span>`;newLabel.innerHTML+=` <span title="${text}" class="required">*</span>`}if(!dd.querySelector("label"))dd.append(newLabel)}
28
32
  // removes old div that a radio or checkbox may have been added to
29
- if(dd.parentElement.nodeName==="DIV")dd.parentElement.remove();const div=document.createElement("div");div.append(label.closest("dt"),dd);dl.append(div)}else{newLabel.setAttribute("for",input.id);newLabel.innerHTML=label.innerHTML;if(input.hasAttribute("title")&&label.getAttribute("data-show-help-icon")!==null&&!label.querySelector("span.help")){const text=input.getAttribute("title");newLabel.innerHTML+=` <span title="${text}" class="help">${helpTextIcon}</span>`}if(input.hasAttribute("required")&&label.getAttribute("data-no-asterisk")===null&&!label.querySelector("span.required")){const text=label.getAttribute("data-asterisk-text")||"This field is required.";newLabel.innerHTML+=` <span title="${text}" class="required">*</span>`}label.setAttribute("hidden","hidden");insertAfter(newLabel,input)}
30
- // #endregion
31
- // #region keyboard shortcuts
32
- if(input.getAttribute("data-focus-key")!==null){function handleKeyboardShortcut(){const os=getOS();
33
- // this is the custom keyword for meta on linux/mac, ctrl on windows
34
- const defaultModifier="metactrl";
35
- // get focus key value
36
- let focusKey=input.getAttribute("data-focus-key");if(focusKey.length>1){console.error(`Provided focus key "${focusKey}" is more than one character. Using first character only.`);focusKey=focusKey.toString()[0]}
37
- // get focus modifier value
38
- let modifierSymbol;let modifierKey=defaultModifier;const modifierAttr={default:input.getAttribute("data-focus-modifier")||defaultModifier,linux:input.getAttribute("data-focus-modifier-linux"),mac:input.getAttribute("data-focus-modifier-mac"),windows:input.getAttribute("data-focus-modifier-win")};if(os&&modifierAttr[os])
39
- // a specific modifier key has been set by the user
40
- modifierKey=modifierAttr[os];else modifierKey=modifierAttr.default;
41
- // validate passed in modifier
42
- const recognizedModifiers=["ctrl","alt","opt","meta","cmd",defaultModifier];if(!recognizedModifiers.includes(modifierKey)){console.error(`Received an unrecognized modifier, "${modifierKey}," defaulting to "${defaultModifier}."`,input);modifierKey=defaultModifier}
43
- // retrieve modifier symbol
44
- if(["alt","opt"].includes(modifierKey))modifierSymbol=os==="mac"?"⌥":"⎇";else if(["meta","win","cmd"].includes(modifierKey)||modifierKey===defaultModifier&&os==="mac")if(os==="mac")modifierSymbol="⌘";else if(os==="linux")modifierSymbol="◆";else modifierSymbol="⊞";else if(modifierKey==="ctrl"||modifierKey===defaultModifier&&(os==="windows"||os==="linux"))if(os==="mac")modifierSymbol="⌃";else modifierSymbol="Ctrl";
45
- // add the shortcut to the cached array, if not a duplicate
46
- if(keyboardShortcuts.some(shortcut=>shortcut.key===focusKey&&shortcut.modifier===modifierKey))console.error(`Duplicate keyboard shortcut "${modifierKey} + ${focusKey}" detected. Only the first input will be focusable using this keyboard shortcut.`,input);else keyboardShortcuts.push({key:focusKey,modifier:modifierKey,input,os,defaultModifier});
47
- // set the shortcut indicator/title
48
- if(input.nodeName==="TEXTAREA"||input.type==="text"||input.type==="number"){
49
- // create focus indicator for valid inputs
50
- const indicator=document.createElement("span");indicator.classList.add("focus-key");indicator.innerHTML=`<kbd>${modifierSymbol} ${focusKey.toUpperCase()}</kbd>`;insertAfter(indicator,newLabel)}else
51
- // update the input title
52
- if(input.getAttribute("title"))input.setAttribute("title",input.getAttribute("title")+` (${modifierSymbol} + ${focusKey})`);else input.setAttribute("title",`Focus with ${modifierSymbol} + ${focusKey}`)}
53
- // placed in a function so that it may exit while still completing other semantic-form enhancements
54
- handleKeyboardShortcut()}
33
+ if(dd.parentElement.nodeName==="DIV")dd.parentElement.remove();const div=document.createElement("div");div.append(label.closest("dt"),dd);dl.append(div)}else{newLabel.setAttribute("for",input.id);newLabel.innerHTML=label.innerHTML;if(input.hasAttribute("title")&&label.getAttribute("data-show-help-icon")!==null&&!label.querySelector("span.help")){const text=input.getAttribute("title");newLabel.innerHTML+=` <span title="${text}" class="help">${icons.helpIcon}</span>`}if(input.hasAttribute("required")&&label.getAttribute("data-no-asterisk")===null&&!label.querySelector("span.required")){const text=label.getAttribute("data-asterisk-text")||"This field is required.";newLabel.innerHTML+=` <span title="${text}" class="required">*</span>`}label.setAttribute("hidden","hidden");insertAfter(newLabel,input)}
55
34
  // #endregion
56
35
  // #region standard inputs
36
+ const isWrapped=input.closest("dd").parentElement.nodeName==="DIV";
57
37
  // check for auto-grow attribute on textareas
58
38
  if(input.getAttribute("data-auto-grow")!==null){
59
39
  // progressively enhance inputs into textareas
60
40
  if(input.nodeName==="INPUT"&&input.type==="text"){const newInput=document.createElement("textarea");newInput.id=input.id;newInput.class=input.class;newInput.innerText=input.value;newInput.setAttribute("data-auto-grow","");input.replaceWith(newInput);input=newInput}if(input.nodeName==="TEXTAREA")
61
41
  // when pressing enter while this input is focused, we want to submit
62
- input.addEventListener("keypress",e=>{if(e.key!=="Enter"||e.key==="Enter"&&e.shiftKey)return;e.preventDefault();form.requestSubmit()})}if(type!=="checkbox"&&type!=="radio"){if(!input.getAttribute("placeholder"))input.setAttribute("placeholder"," ");const div=document.createElement("div");const dt=label.closest("dt");const dd=input.closest("dd");if(!dt){console.error(`semantic-forms: Found an input (${input.id||input.getAttribute("name")}) that does not have a corresponding <dt> element.`);continue}if(!dd){console.error(`semantic-forms: Found an input (${input.id||input.getAttribute("name")}) that does not have a corresponding <dd> element.`);continue}
63
- // #region input clear button
42
+ input.addEventListener("keypress",e=>{if(e.key!=="Enter"||e.key==="Enter"&&e.shiftKey)return;e.preventDefault();form.requestSubmit()})}if(type!=="checkbox"&&type!=="radio"){if(!input.getAttribute("placeholder"))input.setAttribute("placeholder"," ");const div=isWrapped?input.closest("dd").parentElement:document.createElement("div");const dt=label.closest("dt");const dd=input.closest("dd");if(!dt||!dd){console.error(`semantic-forms: Found an input (${input.id||input.getAttribute("name")}) that does not have a corresponding ${!dt?"<dt>":"<dd>"} element.`);return}
43
+ // input clear button
64
44
  if(input.nodeName!=="SELECT"&&type!=="range"){const clearBtn=document.createElement("button");clearBtn.type="button";clearBtn.title=input.getAttribute("data-clear-field-text")||"Clear field";clearBtn.ariaLabel=input.getAttribute("data-clear-field-text")||"Clear field";clearBtn.tabIndex=-1;clearBtn.innerHTML='<svg viewBox="0 0 16 16" width="18" height="18"><path d="M 1 1 L 15 15 M 1 15 L 15 1" fill="none" stroke-width="2" stroke="currentColor" />';clearBtn.classList.add("clear");clearBtn.id=`semanticFormsClearButton_${input.id}`;clearBtn.addEventListener("click",()=>{input.previousValue=input.value;input.value="";input.focus();lastClearFieldPressed=input.id;
65
45
  // used for any other updates required by various inputs
66
46
  input.dispatchEvent(new Event("input",{bubbles:true}))});insertAfter(clearBtn,dd.querySelector("label"))}input.addEventListener("focus",event=>{if(event.target.nodeName==="INPUT")lastFocusedInput=event.target});
67
- // #endregion
68
- // check for colspan- utility class
47
+ // check for colspan- utility class on dd, and move to div
69
48
  if(/colspan-/.test(dd.className)){const match=dd.className.match(/colspan-([0-9]|full)/)[0];dd.classList.remove(match);div.classList.add(match)}
70
49
  // check for max-content attribute
71
50
  // this may be removed once fully supported in Firefox and Safari: https://caniuse.com/wf-field-sizing
72
- if(input.getAttribute("data-max-content")!==null)if(!("fieldSizing"in document.createElement("input").style)){const adjustWidth=()=>{const value=input.value!==""?input.value:input.placeholder;const width=value.length*8+40;input.style.width=width+"px";input.style.maxWidth="100%";div.style.width=width+"px"};adjustWidth();input.addEventListener("input",adjustWidth)}div.append(dt,dd);dl.append(div);
51
+ if(input.getAttribute("data-max-content")!==null)if(!("fieldSizing"in document.createElement("input").style)){const adjustWidth=()=>{const value=input.value!==""?input.value:input.placeholder;const width=value.length*8+40;input.style.width=width+"px";input.style.maxWidth="100%"};adjustWidth();input.addEventListener("input",adjustWidth)}
52
+ // if the user did not wrap the input in a div, do it for them
53
+ if(!isWrapped){div.append(dt,dd);dl.append(div);
73
54
  // determine visibility of newly created <div>
74
- if(dt.style.display==="none"&&dd.style.display==="none")div.style.display="none"}
55
+ if(dt.style.display==="none"&&dd.style.display==="none")div.style.display="none"}}
75
56
  // #endregion
76
57
  // handle file input clear btn, cannot be handled with CSS
77
58
  if(type==="file"){const clearBtn=input.parentElement.querySelector(".clear");input.addEventListener("input",event=>{clearBtn.style.display=event.target.files.length?"flex":"none"});clearBtn.addEventListener("click",()=>{clearBtn.style.display="none"})}
78
59
  // handle range inputs with a class to display the value
60
+ // TODO: should this be a data attribute instead?
79
61
  if(type==="range"&&input.classList.contains("displayValue")){const label=input.parentNode.parentNode.querySelector("dd label");label.innerHTML+=`<span class="seperator">: </span><output>${input.value}</output>`;input.addEventListener("input",event=>{const output=event.target.parentNode.parentNode.querySelector("output");output.innerHTML=event.target.value})}
80
- // #region show password button
81
- if(type==="password"&&input.getAttribute("data-no-reveal")===null){const showBtn=document.createElement("button");showBtn.type="button";showBtn.title=input.getAttribute("data-show-password-text")||"Show password";showBtn.ariaLabel=input.getAttribute("data-show-password-text")||"Show password";showBtn.tabIndex=-1;showBtn.innerHTML=passwordShow;showBtn.classList.add("show");showBtn.id=`semanticFormsShowButton_${input.id}`;const dd=input.closest("dd");if(!dd){console.error(`semantic-forms: Found an input (${input.id||input.getAttribute("name")}) that is not inside a <dd> element.`);continue}showBtn.addEventListener("click",()=>{if(input.type==="password"){showBtn.innerHTML=passwordHide;showBtn.title=input.getAttribute("data-hide-password-text")||"Hide password";showBtn.ariaLabel=input.getAttribute("data-hide-password-text")||"Hide password";input.type="text"}else{showBtn.innerHTML=passwordShow;showBtn.title=input.getAttribute("data-show-password-text")||"Show password";showBtn.ariaLabel=input.getAttribute("data-show-password-text")||"Show password";input.type="password"}input.focus()});insertAfter(showBtn,dd.querySelector("label"))}
82
- // #endregion
62
+ // show password button
63
+ if(type==="password"&&input.getAttribute("data-no-reveal")===null){const showBtn=document.createElement("button");showBtn.type="button";showBtn.title=input.getAttribute("data-show-password-text")||"Show password";showBtn.ariaLabel=input.getAttribute("data-show-password-text")||"Show password";showBtn.tabIndex=-1;showBtn.innerHTML=icons.passwordShow;showBtn.classList.add("show");showBtn.id=`semanticFormsShowButton_${input.id}`;const dd=input.closest("dd");if(!dd){console.error(`semantic-forms: Found an input (${input.id||input.getAttribute("name")}) that is not inside a <dd> element.`);return}showBtn.addEventListener("click",()=>{if(input.type==="password"){showBtn.innerHTML=icons.passwordHide;showBtn.title=input.getAttribute("data-hide-password-text")||"Hide password";showBtn.ariaLabel=input.getAttribute("data-hide-password-text")||"Hide password";input.type="text"}else{showBtn.innerHTML=icons.passwordShow;showBtn.title=input.getAttribute("data-show-password-text")||"Show password";showBtn.ariaLabel=input.getAttribute("data-show-password-text")||"Show password";input.type="password"}input.focus()});insertAfter(showBtn,dd.querySelector("label"))}
83
64
  // add listener to shift clear button when scrollbar present
84
65
  if(input.nodeName==="TEXTAREA"){if(input.getAttribute("data-disable-autosize")===null){
85
66
  // add auto-sizing
@@ -104,26 +85,69 @@ if(maxRows)input.setAttribute("rows",""+Math.min(rows,Number(maxRows)));else inp
104
85
  input.dispatchEvent(new Event("input",{bubbles:true}))}
105
86
  // progressively enhance textarea for Firefox and Safari
106
87
  // this may be removed once fully supported in Firefox and Safari: https://caniuse.com/wf-field-sizing
107
- if(input.getAttribute("data-auto-grow")!==null){const adjustHeight=()=>{if(input.value.length){const borderWidth=parseInt(window.getComputedStyle(input).getPropertyValue("border-width"));input.style.height=input.scrollHeight+borderWidth*2+"px"}else input.style.height=window.getComputedStyle(form).getPropertyValue("--semanticFormsInputHeight")};
88
+ if(input.getAttribute("data-auto-grow")!==null)if(!("fieldSizing"in document.createElement("input").style)){const adjustHeight=()=>{if(input.value.length){const borderWidth=parseInt(window.getComputedStyle(input).getPropertyValue("border-width"));input.style.height=input.scrollHeight+borderWidth*2+"px"}else input.style.height=window.getComputedStyle(form).getPropertyValue("--semanticFormsInputHeight")};
108
89
  // set initial height to semantic-forms CSS variable
109
90
  input.style.height=window.getComputedStyle(form).getPropertyValue("--semanticFormsInputHeight");input.addEventListener("input",adjustHeight)}
110
91
  // shifts the clear button to the right if a scrollbar is present
111
- const shiftClearBtn=()=>{const clearBtn=input.parentElement?.querySelector("button.clear");if(clearBtn)clearBtn.style.marginRight=input.clientHeight<input.scrollHeight?"15px":""};input.addEventListener("input",shiftClearBtn);input.addEventListener("mouseup",shiftClearBtn);shiftClearBtn()}}}}
112
- /**
113
- * Places an element immediately after another element
114
- * @param {Object} newNode element being placed after the reference node
115
- * @param {*} referenceNode element to be used as reference for new node
116
- */function insertAfter(newNode,referenceNode){if(referenceNode.nextSibling)referenceNode.parentNode.insertBefore(newNode,referenceNode.nextSibling);else referenceNode.parentNode.appendChild(newNode)}
117
- /**
118
- * Uses the navigator to best determine the clients operating system.
119
- * @returns Operating system string (`mac`, `windows`, `linux`)
120
- */function getOS(){const userAgent=window.navigator.userAgent;const platform=window.navigator.platform;let os=null;if(platform.includes("Win"))os="windows";else if(platform.includes("Mac")||/iPhone|iPad|iPod/.test(userAgent))os="mac";else if(platform.includes("Linux")||/Android/.test(userAgent))os="linux";return os}
92
+ const shiftClearBtn=()=>{const clearBtn=input.parentElement?.querySelector("button.clear");if(clearBtn)clearBtn.style.marginRight=input.clientHeight<input.scrollHeight?"15px":""};input.addEventListener("input",shiftClearBtn);input.addEventListener("mouseup",shiftClearBtn);shiftClearBtn()}};const handleUndoRedo=event=>{
121
93
  // handle undo/redo
122
- let lastFocusedInput;let lastClearFieldPressed;document.addEventListener("keydown",event=>{if((event.ctrlKey||event.metaKey)&&event.key==="z"&&!event.shiftKey){
94
+ if((event.ctrlKey||event.metaKey)&&event.key==="z"&&!event.shiftKey){
123
95
  // undo clearing a field
124
- if(lastFocusedInput)if(lastFocusedInput?.parentNode?.querySelector("button.clear").id===`semanticFormsClearButton_${lastClearFieldPressed}`||lastFocusedInput?.parentNode?.querySelector("button.clear").name===`semanticFormsClearButton_${lastClearFieldPressed}`)if(lastFocusedInput.previousValue){lastFocusedInput.redoValue=lastFocusedInput.value;lastFocusedInput.value=lastFocusedInput.previousValue}}else if(event.ctrlKey&&event.key==="y"||event.metaKey&&event.shiftKey&&event.key==="z")
96
+ if(lastFocusedInput)if(lastFocusedInput?.parentNode?.querySelector("button.clear").id===`semanticFormsClearButton_${lastClearFieldPressed}`||lastFocusedInput?.parentNode?.querySelector("button.clear").name===`semanticFormsClearButton_${lastClearFieldPressed}`)if(lastFocusedInput.previousValue){console.log("update redo value",lastFocusedInput.value);lastFocusedInput.redoValue=lastFocusedInput.value;lastFocusedInput.value=lastFocusedInput.previousValue}}else if(event.ctrlKey&&event.key==="y"||event.metaKey&&event.shiftKey&&event.key==="z")
125
97
  // redo clearing a field
126
- if(lastFocusedInput)if(lastFocusedInput?.parentNode?.querySelector("button.clear").id===`semanticFormsClearButton_${lastClearFieldPressed}`||lastFocusedInput?.parentNode?.querySelector("button.clear").name===`semanticFormsClearButton_${lastClearFieldPressed}`)if(lastFocusedInput.redoValue){lastFocusedInput.previousValue=lastFocusedInput.value;lastFocusedInput.value=lastFocusedInput.redoValue}});
98
+ if(lastFocusedInput)if(lastFocusedInput?.parentNode?.querySelector("button.clear").id===`semanticFormsClearButton_${lastClearFieldPressed}`||lastFocusedInput?.parentNode?.querySelector("button.clear").name===`semanticFormsClearButton_${lastClearFieldPressed}`)if(lastFocusedInput.redoValue){lastFocusedInput.previousValue=lastFocusedInput.value;lastFocusedInput.value=lastFocusedInput.redoValue}};module.exports={enhanceInput,handleUndoRedo}
99
+ /***/},
100
+ /***/"./lib/keyboardShortcuts.js":
101
+ /*!**********************************!*\
102
+ !*** ./lib/keyboardShortcuts.js ***!
103
+ \**********************************/
104
+ /***/(module,__unused_webpack_exports,__webpack_require__)=>{const{getOS,insertAfter}=__webpack_require__(/*! ./helpers.js */"./lib/helpers.js");const specialCharMap={Minus:"-",Equal:"=",BracketLeft:"[",BracketRight:"]",Backslash:"\\",Semicolon:";",Quote:"'",Comma:",",Period:".",Slash:"/",Backquote:"`"};const shiftSpecialCharMap={1:"!",2:"@",3:"#",4:"$",5:"%",6:"^",7:"&",8:"*",9:"(",0:")",Minus:"_",Equal:"+",BracketLeft:"{",BracketRight:"}",Backslash:"|",Semicolon:":",Quote:'"',Comma:"<",Period:">",Slash:"?",Backquote:"~"};
105
+ // handles keyboard shortcut events
106
+ const shortcutListener=(e,shortcuts)=>{
107
+ // search for matching shortcut from cached shortcut configs
108
+ const shortcut=shortcuts.find(shortcut=>{let matchesKey=false;if(e.altKey&&!e.shiftKey)
109
+ // mac adjusts the key value if altKey is pressed
110
+ matchesKey="Key"+shortcut.key.toUpperCase()===e.code||"Digit"+shortcut.key.toUpperCase()===e.code||shortcut.key===e.key||specialCharMap[e.code]===shortcut.key;else if(e.shiftKey){
111
+ // check shift special character map
112
+ const code=e.code.replace(/Key|Digit/,"");matchesKey=(shiftSpecialCharMap[code]||shiftSpecialCharMap[e.key])&&(shiftSpecialCharMap[code]===shortcut.key||shiftSpecialCharMap[e.key]===shortcut.key)}else matchesKey=shortcut.key.toUpperCase()===e.key.toUpperCase();if(!matchesKey)return false;let matchesModifier;if(shortcut.modifier){if(shortcut.modifier===shortcut.defaultModifier)matchesModifier=shortcut.os==="windows"||shortcut.os==="linux"?e.ctrlKey:e.metaKey;if(shortcut.modifier==="meta")matchesModifier=e.metaKey;if(shortcut.modifier==="alt")matchesModifier=e.altKey;if(shortcut.modifier==="ctrl")matchesModifier=e.ctrlKey}return matchesModifier});if(shortcut){e.preventDefault();shortcut.input.focus()}};const createKeyboardShortcut=(input,shortcuts)=>{const os=getOS();
113
+ // this is the custom keyword for meta on linux/mac, ctrl on windows
114
+ const defaultModifier="metactrl";
115
+ // get focus key value
116
+ let focusKey=input.getAttribute("data-focus-key");if(focusKey.length>1){console.error(`Provided focus key "${focusKey}" is more than one character. Using first character only.`);focusKey=focusKey.toString()[0]}
117
+ // get focus modifier value
118
+ let modifierSymbol;let modifierKey=defaultModifier;const modifierAttr={default:input.getAttribute("data-focus-modifier")||defaultModifier,linux:input.getAttribute("data-focus-modifier-linux"),mac:input.getAttribute("data-focus-modifier-mac"),windows:input.getAttribute("data-focus-modifier-win")};if(os&&modifierAttr[os])
119
+ // a specific modifier key has been set by the user
120
+ modifierKey=modifierAttr[os];else modifierKey=modifierAttr.default;
121
+ // validate passed in modifier
122
+ const recognizedModifiers=["ctrl","alt","opt","meta","cmd",defaultModifier];if(!recognizedModifiers.includes(modifierKey)){console.error(`Received an unrecognized modifier, "${modifierKey}," defaulting to "${defaultModifier}."`,input);modifierKey=defaultModifier}
123
+ // retrieve modifier symbol
124
+ if(["alt","opt"].includes(modifierKey))modifierSymbol=os==="mac"?"⌥":"⎇";else if(["meta","win","cmd"].includes(modifierKey)||modifierKey===defaultModifier&&os==="mac")if(os==="mac")modifierSymbol="⌘";else if(os==="linux")modifierSymbol="◆";else modifierSymbol="⊞";else if(modifierKey==="ctrl"||modifierKey===defaultModifier&&(os==="windows"||os==="linux"))if(os==="mac")modifierSymbol="⌃";else modifierSymbol="Ctrl";
125
+ // add the shortcut to the cached array, if not a duplicate
126
+ if(shortcuts.some(shortcut=>shortcut.key===focusKey&&shortcut.modifier===modifierKey))console.error(`Duplicate keyboard shortcut "${modifierKey} + ${focusKey}" detected. Only the first input will be focusable using this keyboard shortcut.`,input);
127
+ // set the shortcut indicator/title
128
+ if(input.nodeName==="TEXTAREA"||input.type==="text"||input.type==="number"){
129
+ // create focus indicator for valid inputs
130
+ const indicator=document.createElement("span");indicator.classList.add("focus-key");indicator.innerHTML=`<kbd>${modifierSymbol} ${focusKey.toUpperCase()}</kbd>`;const label=input.nextSibling;insertAfter(indicator,label)}else
131
+ // update the input title
132
+ if(input.getAttribute("title"))input.setAttribute("title",input.getAttribute("title")+` (${modifierSymbol} + ${focusKey})`);else input.setAttribute("title",`Focus with ${modifierSymbol} + ${focusKey}`);return{key:focusKey,modifier:modifierKey,input,os,defaultModifier}};module.exports={shortcutListener,createKeyboardShortcut}
133
+ /***/},
134
+ /***/"./semanticForms.js":
135
+ /*!**************************!*\
136
+ !*** ./semanticForms.js ***!
137
+ \**************************/
138
+ /***/(module,__unused_webpack_exports,__webpack_require__)=>{const{createKeyboardShortcut,shortcutListener}=__webpack_require__(/*! ./lib/keyboardShortcuts.js */"./lib/keyboardShortcuts.js");const{enhanceInput,handleUndoRedo}=__webpack_require__(/*! ./lib/inputEnhancements.js */"./lib/inputEnhancements.js");const semanticForms=()=>{
139
+ // do some feature detection so none of the JS executes if the browser is too old
140
+ if(typeof document.getElementsByClassName!=="function"||typeof document.querySelector!=="function"||!document.body.classList||!window.MutationObserver){console.warn("semantic-forms was loaded into an unsupported browser and will not execute.");return}
141
+ // custom keyboard shortcut listener
142
+ const keyboardShortcuts=[];document.addEventListener("keydown",e=>shortcutListener(e,keyboardShortcuts));
143
+ // progressively enhance form elements that have the semanticForms class
144
+ const forms=document.querySelectorAll("form.semanticForms:not(.semanticFormsActive), table.semanticForms:not(.semanticFormsActive)");for(const form of forms){form.classList.add("semanticFormsActive");if(form.classList.contains("lowFlow"))continue;
145
+ // update each input in the semantic form
146
+ const inputs=Array.from(form.querySelectorAll("input, textarea, select"));for(const input of inputs){enhanceInput(input,form);
147
+ // handle keyboard shortcuts
148
+ if(input.getAttribute("data-focus-key")!==null){const shortcut=createKeyboardShortcut(input,keyboardShortcuts);keyboardShortcuts.push(shortcut)}}}
149
+ // prevents multiple listeners
150
+ document.removeEventListener("keydown",handleUndoRedo);document.addEventListener("keydown",handleUndoRedo);
127
151
  // monitor changes to the DOM and enhance new semanticForms forms that get added
128
152
  if(!window.semanticFormsObserver){window.semanticFormsObserver=new window.MutationObserver(mutations=>{let stop=false;for(const mutation of mutations){for(const node of mutation.addedNodes)if(node.nodeName==="FORM"||node?.querySelector?.("form")){semanticForms();stop=true}if(stop)break}});window.semanticFormsObserver.observe(document.body,{attributes:false,childList:true,characterData:false,subtree:true})}semanticForms.reinitialize=form=>{form.classList.remove("semanticFormsActive");semanticForms()}};module.exports=semanticForms
129
153
  /***/}
@@ -1 +1 @@
1
- {"version":3,"file":"semantic-forms.cjs","mappings":"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","sources":["webpack://semanticForms/webpack/universalModuleDefinition","webpack://semanticForms/./semanticForms.js","webpack://semanticForms/webpack/bootstrap","webpack://semanticForms/webpack/startup"],"sourcesContent":["(function webpackUniversalModuleDefinition(root, factory) {\n\tif(typeof exports === 'object' && typeof module === 'object')\n\t\tmodule.exports = factory();\n\telse if(typeof define === 'function' && define.amd)\n\t\tdefine(\"semanticForms\", [], factory);\n\telse if(typeof exports === 'object')\n\t\texports[\"semanticForms\"] = factory();\n\telse\n\t\troot[\"semanticForms\"] = factory();\n})(this, () => {\nreturn ","const semanticForms = () => {\n // do some feature detection so none of the JS executes if the browser is too old\n if (typeof document.getElementsByClassName !== 'function' || typeof document.querySelector !== 'function' || !document.body.classList || !window.MutationObserver) {\n console.warn('semantic-forms was loaded into an unsupported browser and will not execute.')\n return\n }\n\n const passwordShow = '<svg fill=\"none\" height=\"256\" viewBox=\"0 0 24 24\" width=\"256\" xmlns=\"http://www.w3.org/2000/svg\"><g stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\"><path d=\"m1 12s4-8 11-8 11 8 11 8\"/><path d=\"m1 12s4 8 11 8 11-8 11-8\"/><circle cx=\"12\" cy=\"12\" r=\"3\"/></g></svg>'\n const passwordHide = '<svg fill=\"none\" height=\"256\" viewBox=\"0 0 24 24\" width=\"256\" xmlns=\"http://www.w3.org/2000/svg\"><g stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\"><path d=\"m2 2 20 20\"/><path d=\"m6.71277 6.7226c-3.04798 2.07267-4.71277 5.2774-4.71277 5.2774s3.63636 7 10 7c2.0503 0 3.8174-.7266 5.2711-1.7116m-6.2711-12.23018c.3254-.03809.6588-.05822 1-.05822 6.3636 0 10 7 10 7s-.6918 1.3317-2 2.8335\"/><path d=\"m14 14.2362c-.5308.475-1.2316.7639-2 .7639-1.6569 0-3-1.3431-3-3 0-.8237.33193-1.5698.86932-2.11192\"/></g></svg>'\n const helpTextIcon = '<svg xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" version=\"1.1\" style=\"overflow:visible;\"><rect width=\"16\" height=\"16\" fill=\"none\"/><path fill=\"currentColor\" d=\"M8,10.5c-0.552,0-1,0.448-1,1c0,0.552,0.448,1,1,1c0.552,0,1-0.448,1-1C9,10.948,8.552,10.5,8,10.5z M8,0 C3.582,0,0,3.582,0,8c0,4.418,3.582,8,8,8s8-3.582,8-8C16,3.582,12.418,0,8,0z M12.243,12.243C11.109,13.376,9.603,14,8,14 s-3.109-0.624-4.243-1.757C2.624,11.109,2,9.603,2,8s0.624-3.109,1.757-4.243C4.891,2.624,6.397,2,8,2s3.109,0.624,4.243,1.757 C13.376,4.891,14,6.397,14,8C14,9.603,13.376,11.109,12.243,12.243z M7.927,3.755c-2.248,0-2.76,1.695-2.802,2.906h1.571 c0.028-0.256,0.101-1.418,1.221-1.418c0.672,0,1.206,0.406,1.206,1.175c0,0.695-0.724,1.155-1.303,1.711 C7.241,8.685,7.168,9.325,7.168,9.824V10c0.146,0,1.615,0,1.615,0V9.824c0-1.256,1.967-1.594,1.967-3.541 C10.75,5.059,9.874,3.755,7.927,3.755z\"/></svg>'\n\n const nodeNameLookup = ['TEXTAREA', 'SELECT']\n const inputTypeLookup = ['checkbox', 'color', 'date', 'datetime-local', 'email', 'file', 'image', 'month', 'number', 'password', 'radio', 'range', 'search', 'tel', 'text', 'time', 'url', 'week']\n const keyboardShortcuts = []\n\n // custom keyboard shortcut listener\n document.addEventListener('keydown', (e) => {\n const specialCharMap = {\n Minus: '-',\n Equal: '=',\n BracketLeft: '[',\n BracketRight: ']',\n Backslash: '\\\\',\n Semicolon: ';',\n Quote: '\\'',\n Comma: ',',\n Period: '.',\n Slash: '/',\n Backquote: '`'\n }\n\n const shiftSpecialCharMap = {\n 1: '!',\n 2: '@',\n 3: '#',\n 4: '$',\n 5: '%',\n 6: '^',\n 7: '&',\n 8: '*',\n 9: '(',\n 0: ')',\n Minus: '_',\n Equal: '+',\n BracketLeft: '{',\n BracketRight: '}',\n Backslash: '|',\n Semicolon: ':',\n Quote: '\"',\n Comma: '<',\n Period: '>',\n Slash: '?',\n Backquote: '~'\n }\n\n const shortcut = keyboardShortcuts.find(shortcut => {\n let matchesKey = false\n if (e.altKey && !e.shiftKey) {\n // mac adjusts the key value if altKey is pressed\n matchesKey = 'Key' + shortcut.key.toUpperCase() === e.code ||\n 'Digit' + shortcut.key.toUpperCase() === e.code ||\n shortcut.key === e.key ||\n specialCharMap[e.code] === shortcut.key\n } else if (e.shiftKey) {\n // check shift special character map\n const code = e.code.replace(/Key|Digit/, '')\n matchesKey = (shiftSpecialCharMap[code] || shiftSpecialCharMap[e.key]) &&\n (shiftSpecialCharMap[code] === shortcut.key || shiftSpecialCharMap[e.key] === shortcut.key)\n } else {\n matchesKey = shortcut.key.toUpperCase() === e.key.toUpperCase()\n }\n if (!matchesKey) return false\n\n let matchesModifier\n if (shortcut.modifier) {\n if (shortcut.modifier === shortcut.defaultModifier) matchesModifier = shortcut.os === 'windows' || shortcut.os === 'linux' ? e.ctrlKey : e.metaKey\n if (shortcut.modifier === 'meta') matchesModifier = e.metaKey\n if (shortcut.modifier === 'alt') matchesModifier = e.altKey\n if (shortcut.modifier === 'ctrl') matchesModifier = e.ctrlKey\n }\n return matchesModifier\n })\n\n if (shortcut) {\n e.preventDefault()\n shortcut.input.focus()\n }\n })\n\n // progressively enhance form elements that have the semanticForms class\n const forms = document.querySelectorAll('form.semanticForms:not(.semanticFormsActive), table.semanticForms:not(.semanticFormsActive)')\n\n for (const form of forms) {\n form.classList.add('semanticFormsActive')\n if (form.classList.contains('lowFlow')) continue\n\n // update each input in the semantic form\n const inputs = Array.from(form.querySelectorAll('input, textarea, select'))\n for (let input of inputs) {\n // ignore input if it has previously been formatted\n if (input.classList.contains('semanticform') || !input.id) continue\n\n const type = input.getAttribute('type')\n if (nodeNameLookup.includes(input.nodeName) || inputTypeLookup.includes(type)) {\n // recursively find <dl> element\n let dl = input.parentNode\n while (dl && dl.nodeName !== 'DL') dl = dl.parentNode\n\n if (!dl) continue\n if (!dl.classList.contains('floatLabelForm')) dl.classList.add('floatLabelForm')\n\n const label = input.parentNode.parentNode.id && (type === 'checkbox' || type === 'radio')\n ? document.querySelector('label[data-for=' + input.parentNode.parentNode.id.replace(/\\./g, '\\\\.') + ']')\n : document.querySelector('label[for=' + input.id.replace(/\\./g, '\\\\.') + ']')\n\n if (!label) {\n console.error(`semantic-forms: Found an input (${input.id || input.getAttribute('name')}) without a properly associated label. Make sure there is a label for it and the label has a matching \"for\" attribute.`)\n }\n\n input.classList.add('semanticform')\n\n // #region create labels\n\n const newLabel = document.createElement('label')\n newLabel.className = 'floatLabelFormAnimatedLabel'\n\n if (type === 'checkbox' || type === 'radio') {\n // recursively find <dd> element\n let dd = input.parentNode\n while (dd && dd.nodeName !== 'DD') dd = dd.parentNode\n\n if (!dd) {\n console.error(`semantic-forms: Found an input (${input.id || input.getAttribute('name')}) that is not inside a <dd> element.`)\n continue\n }\n\n if (dd.firstChild.nodeName !== 'LABEL') {\n if (type === 'checkbox' && input.parentNode.nodeName === 'DD') {\n newLabel.setAttribute('for', input.id)\n input.parentNode.classList.add('singleCheckbox')\n newLabel.className = ''\n label.setAttribute('hidden', 'hidden')\n insertAfter(newLabel, input)\n }\n\n if (type === 'radio' && input.parentNode.nodeName === 'DD') {\n newLabel.setAttribute('for', input.id)\n input.parentNode.classList.add('singleRadio')\n newLabel.className = ''\n label.setAttribute('hidden', 'hidden')\n insertAfter(newLabel, input)\n }\n\n newLabel.innerHTML = label.innerHTML\n\n if (label.hasAttribute('title') && label.getAttribute('data-show-help-icon') !== null && !label.querySelector('span.help')) {\n const text = label.getAttribute('title')\n label.innerHTML += ` <span title=\"${text}\" class=\"help\">${helpTextIcon}</span>`\n newLabel.innerHTML += ` <span title=\"${text}\" class=\"help\">${helpTextIcon}</span>`\n }\n\n if (dd.querySelector(':required') && label.getAttribute('data-no-asterisk') === null && !label.querySelector('span.required')) {\n const text = label.getAttribute('data-asterisk-text') || 'This field is required.'\n label.innerHTML += ` <span title=\"${text}\" class=\"required\">*</span>`\n newLabel.innerHTML += ` <span title=\"${text}\" class=\"required\">*</span>`\n }\n\n if (!dd.querySelector('label')) dd.append(newLabel)\n }\n\n // removes old div that a radio or checkbox may have been added to\n if (dd.parentElement.nodeName === 'DIV') dd.parentElement.remove()\n\n const div = document.createElement('div')\n div.append(label.closest('dt'), dd)\n dl.append(div)\n } else {\n newLabel.setAttribute('for', input.id)\n newLabel.innerHTML = label.innerHTML\n\n if (input.hasAttribute('title') && label.getAttribute('data-show-help-icon') !== null && !label.querySelector('span.help')) {\n const text = input.getAttribute('title')\n newLabel.innerHTML += ` <span title=\"${text}\" class=\"help\">${helpTextIcon}</span>`\n }\n\n if (input.hasAttribute('required') && label.getAttribute('data-no-asterisk') === null && !label.querySelector('span.required')) {\n const text = label.getAttribute('data-asterisk-text') || 'This field is required.'\n newLabel.innerHTML += ` <span title=\"${text}\" class=\"required\">*</span>`\n }\n\n label.setAttribute('hidden', 'hidden')\n\n insertAfter(newLabel, input)\n }\n // #endregion\n\n // #region keyboard shortcuts\n if (input.getAttribute('data-focus-key') !== null) {\n function handleKeyboardShortcut () {\n const os = getOS()\n // this is the custom keyword for meta on linux/mac, ctrl on windows\n const defaultModifier = 'metactrl'\n\n // get focus key value\n let focusKey = input.getAttribute('data-focus-key')\n if (focusKey.length > 1) {\n console.error(`Provided focus key \"${focusKey}\" is more than one character. Using first character only.`)\n focusKey = focusKey.toString()[0]\n }\n\n // get focus modifier value\n let modifierSymbol\n let modifierKey = defaultModifier\n const modifierAttr = {\n default: input.getAttribute('data-focus-modifier') || defaultModifier,\n linux: input.getAttribute('data-focus-modifier-linux'),\n mac: input.getAttribute('data-focus-modifier-mac'),\n windows: input.getAttribute('data-focus-modifier-win')\n }\n if (os && modifierAttr[os]) {\n // a specific modifier key has been set by the user\n modifierKey = modifierAttr[os]\n } else {\n modifierKey = modifierAttr.default\n }\n\n // validate passed in modifier\n const recognizedModifiers = ['ctrl', 'alt', 'opt', 'meta', 'cmd', defaultModifier]\n if (!recognizedModifiers.includes(modifierKey)) {\n console.error(`Received an unrecognized modifier, \"${modifierKey},\" defaulting to \"${defaultModifier}.\"`, input)\n modifierKey = defaultModifier\n }\n\n // retrieve modifier symbol\n if (['alt', 'opt'].includes(modifierKey)) {\n modifierSymbol = os === 'mac' ? '⌥' : '⎇'\n } else if (['meta', 'win', 'cmd'].includes(modifierKey) || (modifierKey === defaultModifier && os === 'mac')) {\n if (os === 'mac') {\n modifierSymbol = '⌘'\n } else if (os === 'linux') {\n modifierSymbol = '◆'\n } else {\n modifierSymbol = '⊞'\n }\n } else if (modifierKey === 'ctrl' || (modifierKey === defaultModifier && (os === 'windows' || os === 'linux'))) {\n if (os === 'mac') {\n modifierSymbol = '⌃'\n } else {\n modifierSymbol = 'Ctrl'\n }\n }\n\n // add the shortcut to the cached array, if not a duplicate\n if (keyboardShortcuts.some(shortcut => shortcut.key === focusKey && shortcut.modifier === modifierKey)) {\n console.error(`Duplicate keyboard shortcut \"${modifierKey} + ${focusKey}\" detected. Only the first input will be focusable using this keyboard shortcut.`, input)\n } else {\n keyboardShortcuts.push({\n key: focusKey,\n modifier: modifierKey,\n input,\n os,\n defaultModifier\n })\n }\n\n // set the shortcut indicator/title\n if (input.nodeName === 'TEXTAREA' || input.type === 'text' || input.type === 'number') {\n // create focus indicator for valid inputs\n const indicator = document.createElement('span')\n indicator.classList.add('focus-key')\n indicator.innerHTML = `<kbd>${modifierSymbol} ${focusKey.toUpperCase()}</kbd>`\n insertAfter(indicator, newLabel)\n } else {\n // update the input title\n if (input.getAttribute('title')) {\n input.setAttribute('title', input.getAttribute('title') + ` (${modifierSymbol} + ${focusKey})`)\n } else {\n input.setAttribute('title', `Focus with ${modifierSymbol} + ${focusKey}`)\n }\n }\n }\n\n // placed in a function so that it may exit while still completing other semantic-form enhancements\n handleKeyboardShortcut()\n }\n // #endregion\n\n // #region standard inputs\n // check for auto-grow attribute on textareas\n if (input.getAttribute('data-auto-grow') !== null) {\n // progressively enhance inputs into textareas\n if (input.nodeName === 'INPUT' && input.type === 'text') {\n const newInput = document.createElement('textarea')\n newInput.id = input.id\n newInput.class = input.class\n newInput.innerText = input.value\n newInput.setAttribute('data-auto-grow', '')\n input.replaceWith(newInput)\n input = newInput\n }\n\n if (input.nodeName === 'TEXTAREA') {\n // when pressing enter while this input is focused, we want to submit\n input.addEventListener('keypress', (e) => {\n if (e.key !== 'Enter' || (e.key === 'Enter' && e.shiftKey)) return\n e.preventDefault()\n form.requestSubmit()\n })\n }\n }\n\n if (type !== 'checkbox' && type !== 'radio') {\n if (!input.getAttribute('placeholder')) input.setAttribute('placeholder', ' ')\n\n const div = document.createElement('div')\n const dt = label.closest('dt')\n const dd = input.closest('dd')\n\n if (!dt) {\n console.error(`semantic-forms: Found an input (${input.id || input.getAttribute('name')}) that does not have a corresponding <dt> element.`)\n continue\n }\n if (!dd) {\n console.error(`semantic-forms: Found an input (${input.id || input.getAttribute('name')}) that does not have a corresponding <dd> element.`)\n continue\n }\n\n // #region input clear button\n if (input.nodeName !== 'SELECT' && type !== 'range') {\n const clearBtn = document.createElement('button')\n clearBtn.type = 'button'\n clearBtn.title = input.getAttribute('data-clear-field-text') || 'Clear field'\n clearBtn.ariaLabel = input.getAttribute('data-clear-field-text') || 'Clear field'\n clearBtn.tabIndex = -1\n clearBtn.innerHTML = '<svg viewBox=\"0 0 16 16\" width=\"18\" height=\"18\"><path d=\"M 1 1 L 15 15 M 1 15 L 15 1\" fill=\"none\" stroke-width=\"2\" stroke=\"currentColor\" />'\n clearBtn.classList.add('clear')\n clearBtn.id = `semanticFormsClearButton_${input.id}`\n clearBtn.addEventListener('click', () => {\n input.previousValue = input.value\n input.value = ''\n input.focus()\n lastClearFieldPressed = input.id\n\n // used for any other updates required by various inputs\n input.dispatchEvent(new Event('input', { bubbles: true }))\n })\n insertAfter(clearBtn, dd.querySelector('label'))\n }\n input.addEventListener('focus', event => {\n if (event.target.nodeName === 'INPUT') lastFocusedInput = event.target\n })\n // #endregion\n\n // check for colspan- utility class\n if (/colspan-/.test(dd.className)) {\n const match = dd.className.match(/colspan-([0-9]|full)/)[0]\n dd.classList.remove(match)\n div.classList.add(match)\n }\n\n // check for max-content attribute\n // this may be removed once fully supported in Firefox and Safari: https://caniuse.com/wf-field-sizing\n if (input.getAttribute('data-max-content') !== null) {\n if (!('fieldSizing' in document.createElement('input').style)) {\n const adjustWidth = () => {\n const value = input.value !== '' ? input.value : input.placeholder\n const width = value.length * 8 + 40\n input.style.width = width + 'px'\n input.style.maxWidth = '100%'\n div.style.width = width + 'px'\n }\n adjustWidth()\n input.addEventListener('input', adjustWidth)\n }\n }\n\n div.append(dt, dd)\n dl.append(div)\n\n // determine visibility of newly created <div>\n if (dt.style.display === 'none' && dd.style.display === 'none') div.style.display = 'none'\n }\n // #endregion\n\n // handle file input clear btn, cannot be handled with CSS\n if (type === 'file') {\n const clearBtn = input.parentElement.querySelector('.clear')\n input.addEventListener('input', event => {\n clearBtn.style.display = event.target.files.length ? 'flex' : 'none'\n })\n clearBtn.addEventListener('click', () => {\n clearBtn.style.display = 'none'\n })\n }\n\n // handle range inputs with a class to display the value\n if (type === 'range' && input.classList.contains('displayValue')) {\n const label = input.parentNode.parentNode.querySelector('dd label')\n label.innerHTML += `<span class=\"seperator\">: </span><output>${input.value}</output>`\n input.addEventListener('input', event => {\n const output = event.target.parentNode.parentNode.querySelector('output')\n output.innerHTML = event.target.value\n })\n }\n\n // #region show password button\n if (type === 'password' && input.getAttribute('data-no-reveal') === null) {\n const showBtn = document.createElement('button')\n showBtn.type = 'button'\n showBtn.title = input.getAttribute('data-show-password-text') || 'Show password'\n showBtn.ariaLabel = input.getAttribute('data-show-password-text') || 'Show password'\n showBtn.tabIndex = -1\n showBtn.innerHTML = passwordShow\n showBtn.classList.add('show')\n showBtn.id = `semanticFormsShowButton_${input.id}`\n const dd = input.closest('dd')\n if (!dd) {\n console.error(`semantic-forms: Found an input (${input.id || input.getAttribute('name')}) that is not inside a <dd> element.`)\n continue\n }\n showBtn.addEventListener('click', () => {\n if (input.type === 'password') {\n showBtn.innerHTML = passwordHide\n showBtn.title = input.getAttribute('data-hide-password-text') || 'Hide password'\n showBtn.ariaLabel = input.getAttribute('data-hide-password-text') || 'Hide password'\n input.type = 'text'\n } else {\n showBtn.innerHTML = passwordShow\n showBtn.title = input.getAttribute('data-show-password-text') || 'Show password'\n showBtn.ariaLabel = input.getAttribute('data-show-password-text') || 'Show password'\n input.type = 'password'\n }\n input.focus()\n })\n insertAfter(showBtn, dd.querySelector('label'))\n }\n // #endregion\n\n // add listener to shift clear button when scrollbar present\n if (input.nodeName === 'TEXTAREA') {\n if (input.getAttribute('data-disable-autosize') === null) {\n // add auto-sizing\n input.style.setProperty('resize', 'none')\n input.style.setProperty('min-height', '0')\n input.style.setProperty('max-height', 'none')\n input.style.setProperty('height', 'auto')\n\n const handleInput = () => {\n // reset rows attribute to get accurate scrollHeight\n let maxRows = input.getAttribute('data-max-rows')\n\n if (maxRows) {\n if (isNaN(maxRows) || Number(maxRows) <= 0) {\n console.warn(`An invalid value was passed to the \"data-max-rows\" attribute. This value will be ignored.\\n\\nProvided value: ${input.getAttribute('data-max-rows')}`)\n maxRows = null\n }\n }\n\n const minRows = input.getAttribute('data-max-rows') && Number(input.getAttribute('data-max-rows')) < 5 ? input.getAttribute('data-max-rows') : '5'\n input.setAttribute('rows', minRows)\n\n // get the computed values object reference\n const style = window.getComputedStyle(input)\n\n // force content-box for size accurate line-height calculation, remove scrollbars, lock width (subtract inline padding and inline border widths), and remove inline padding and borders to keep width consistent (for text wrapping accuracy)\n const inlinePadding = parseFloat(style['padding-left']) + parseFloat(style['padding-right'])\n const inlineBorderWidth = parseFloat(style['border-left-width']) + parseFloat(style['border-right-width'])\n input.style.setProperty('overflow', 'hidden', 'important')\n input.style.setProperty('width', (parseFloat(style.width) - inlinePadding - inlineBorderWidth) + 'px')\n input.style.setProperty('box-sizing', 'content-box')\n input.style.setProperty('padding-inline', '0')\n input.style.setProperty('border-width', '0')\n\n // get the base line height, and top / bottom padding\n const blockPadding = parseFloat(style['padding-top']) + parseFloat(style['padding-bottom'])\n const lineHeight = style['line-height'] === 'normal'\n ? parseFloat(style.height) // if line-height is not explicitly set, use the computed height value (ignore padding due to content-box)\n : parseFloat(style['line-height']) // otherwise (line-height is explicitly set), use the computed line-height value\n\n // get the scroll height (rounding to be safe to ensure cross browser consistency)\n const scrollHeight = Math.round(input.scrollHeight)\n\n // undo overflow, width, border-width, box-sizing & inline padding overrides\n input.style.removeProperty('width')\n input.style.removeProperty('box-sizing')\n input.style.removeProperty('padding-inline')\n input.style.removeProperty('border-width')\n input.style.removeProperty('overflow')\n\n // subtract blockPadding from scrollHeight and divide that by our lineHeight to get the row count, round to nearest integer as it will always be within ~.1 of the correct whole number\n const rows = Math.round((scrollHeight - blockPadding) / lineHeight)\n\n // set the calculated rows attribute (limited by rowLimit)\n if (maxRows) {\n input.setAttribute('rows', '' + Math.min(rows, Number(maxRows)))\n } else {\n input.setAttribute('rows', '' + rows)\n }\n }\n\n input.addEventListener('input', handleInput)\n\n // trigger the event to set the initial rows value\n input.dispatchEvent(new Event('input', { bubbles: true }))\n }\n\n // progressively enhance textarea for Firefox and Safari\n // this may be removed once fully supported in Firefox and Safari: https://caniuse.com/wf-field-sizing\n if (input.getAttribute('data-auto-grow') !== null) {\n const adjustHeight = () => {\n if (input.value.length) {\n const borderWidth = parseInt(window.getComputedStyle(input).getPropertyValue('border-width'))\n input.style.height = (input.scrollHeight + (borderWidth * 2)) + 'px'\n } else {\n input.style.height = window.getComputedStyle(form).getPropertyValue('--semanticFormsInputHeight')\n }\n }\n\n // set initial height to semantic-forms CSS variable\n input.style.height = window.getComputedStyle(form).getPropertyValue('--semanticFormsInputHeight')\n input.addEventListener('input', adjustHeight)\n }\n\n // shifts the clear button to the right if a scrollbar is present\n const shiftClearBtn = () => {\n const clearBtn = input.parentElement?.querySelector('button.clear')\n if (clearBtn) clearBtn.style.marginRight = input.clientHeight < input.scrollHeight ? '15px' : ''\n }\n input.addEventListener('input', shiftClearBtn)\n input.addEventListener('mouseup', shiftClearBtn)\n shiftClearBtn()\n }\n }\n }\n }\n\n /**\n * Places an element immediately after another element\n * @param {Object} newNode element being placed after the reference node\n * @param {*} referenceNode element to be used as reference for new node\n */\n function insertAfter (newNode, referenceNode) {\n if (referenceNode.nextSibling) referenceNode.parentNode.insertBefore(newNode, referenceNode.nextSibling)\n else referenceNode.parentNode.appendChild(newNode)\n }\n\n /**\n * Uses the navigator to best determine the clients operating system.\n * @returns Operating system string (`mac`, `windows`, `linux`)\n */\n function getOS () {\n const userAgent = window.navigator.userAgent\n const platform = window.navigator.platform\n let os = null\n\n if (platform.includes('Win')) {\n os = 'windows'\n } else if (platform.includes('Mac') || /iPhone|iPad|iPod/.test(userAgent)) {\n os = 'mac'\n } else if (platform.includes('Linux') || /Android/.test(userAgent)) {\n os = 'linux'\n }\n return os\n }\n\n // handle undo/redo\n let lastFocusedInput\n let lastClearFieldPressed\n document.addEventListener('keydown', event => {\n if ((event.ctrlKey || event.metaKey) && event.key === 'z' && !event.shiftKey) {\n // undo clearing a field\n if (lastFocusedInput) {\n if (lastFocusedInput?.parentNode?.querySelector('button.clear').id === `semanticFormsClearButton_${lastClearFieldPressed}` || lastFocusedInput?.parentNode?.querySelector('button.clear').name === `semanticFormsClearButton_${lastClearFieldPressed}`) {\n if (lastFocusedInput.previousValue) {\n lastFocusedInput.redoValue = lastFocusedInput.value\n lastFocusedInput.value = lastFocusedInput.previousValue\n }\n }\n }\n } else if ((event.ctrlKey && event.key === 'y') || (event.metaKey && event.shiftKey && event.key === 'z')) {\n // redo clearing a field\n if (lastFocusedInput) {\n if (lastFocusedInput?.parentNode?.querySelector('button.clear').id === `semanticFormsClearButton_${lastClearFieldPressed}` || lastFocusedInput?.parentNode?.querySelector('button.clear').name === `semanticFormsClearButton_${lastClearFieldPressed}`) {\n if (lastFocusedInput.redoValue) {\n lastFocusedInput.previousValue = lastFocusedInput.value\n lastFocusedInput.value = lastFocusedInput.redoValue\n }\n }\n }\n }\n })\n\n // monitor changes to the DOM and enhance new semanticForms forms that get added\n if (!window.semanticFormsObserver) {\n window.semanticFormsObserver = new window.MutationObserver(mutations => {\n let stop = false\n for (const mutation of mutations) {\n for (const node of mutation.addedNodes) {\n if (node.nodeName === 'FORM' || node?.querySelector?.('form')) {\n semanticForms()\n stop = true\n }\n }\n if (stop) break\n }\n })\n window.semanticFormsObserver.observe(document.body, { attributes: false, childList: true, characterData: false, subtree: true })\n }\n\n semanticForms.reinitialize = form => {\n form.classList.remove('semanticFormsActive')\n semanticForms()\n }\n}\n\nmodule.exports = semanticForms\n","// The module cache\nvar __webpack_module_cache__ = {};\n\n// The require function\nfunction __webpack_require__(moduleId) {\n\t// Check if module is in cache\n\tvar cachedModule = __webpack_module_cache__[moduleId];\n\tif (cachedModule !== undefined) {\n\t\treturn cachedModule.exports;\n\t}\n\t// Create a new module (and put it into the cache)\n\tvar module = __webpack_module_cache__[moduleId] = {\n\t\t// no module.id needed\n\t\t// no module.loaded needed\n\t\texports: {}\n\t};\n\n\t// Execute the module function\n\t__webpack_modules__[moduleId](module, module.exports, __webpack_require__);\n\n\t// Return the exports of the module\n\treturn module.exports;\n}\n\n","// startup\n// Load entry module and return exports\n// This entry module is referenced by other modules so it can't be inlined\nvar __webpack_exports__ = __webpack_require__(\"./semanticForms.js\");\n"],"names":["root","factory","exports","module","define","amd","this","semanticForms","document","getElementsByClassName","querySelector","body","classList","window","MutationObserver","console","warn","passwordShow","passwordHide","helpTextIcon","nodeNameLookup","inputTypeLookup","keyboardShortcuts","addEventListener","e","specialCharMap","Minus","Equal","BracketLeft","BracketRight","Backslash","Semicolon","Quote","Comma","Period","Slash","Backquote","shiftSpecialCharMap","shortcut","find","matchesKey","altKey","shiftKey","key","toUpperCase","code","replace","matchesModifier","modifier","defaultModifier","os","ctrlKey","metaKey","preventDefault","input","focus","forms","querySelectorAll","form","add","contains","inputs","Array","from","id","type","getAttribute","includes","nodeName","dl","parentNode","label","error","newLabel","createElement","className","dd","firstChild","setAttribute","insertAfter","innerHTML","hasAttribute","text","append","parentElement","remove","div","closest","handleKeyboardShortcut","getOS","focusKey","length","toString","modifierSymbol","modifierKey","modifierAttr","default","linux","mac","windows","recognizedModifiers","some","push","indicator","newInput","class","innerText","value","replaceWith","requestSubmit","dt","clearBtn","title","ariaLabel","tabIndex","previousValue","lastClearFieldPressed","dispatchEvent","Event","bubbles","event","target","lastFocusedInput","test","match","style","adjustWidth","placeholder","width","maxWidth","display","files","output","showBtn","setProperty","handleInput","maxRows","isNaN","Number","minRows","getComputedStyle","inlinePadding","parseFloat","inlineBorderWidth","blockPadding","lineHeight","height","scrollHeight","Math","round","removeProperty","rows","min","adjustHeight","borderWidth","parseInt","getPropertyValue","shiftClearBtn","marginRight","clientHeight","newNode","referenceNode","nextSibling","insertBefore","appendChild","userAgent","navigator","platform","name","redoValue","semanticFormsObserver","mutations","stop","mutation","node","addedNodes","observe","attributes","childList","characterData","subtree","reinitialize","__webpack_module_cache__","__webpack_require__","moduleId","cachedModule","undefined","__webpack_modules__","__webpack_exports__"],"sourceRoot":""}
1
+ {"version":3,"file":"semantic-forms.cjs","mappings":"CAAA,SAA2CA,KAAMC,SAChD,UAAUC,UAAY,iBAAmBC,SAAW,SACnDA,OAAOD,QAAUD,eACb,UAAUG,SAAW,YAAcA,OAAOC,IAC9CD,OAAO,gBAAiB,GAAIH,cACxB,UAAUC,UAAY,SAC1BA,QAAQ,iBAAmBD,eAE3BD,KAAK,iBAAmBC,SACzB,EATD,CASGK,KAAM,Y;;;;;;;;;;;ACLT,MAAMC,MAAQ,KACZ,MAAMC,UAAYC,OAAOC,UAAUF,UACnC,MAAMG,SAAWF,OAAOC,UAAUC,SAClC,IAAIC,GAAK,KAET,GAAID,SAASE,SAAS,OACpBD,GAAK,eACA,GAAID,SAASE,SAAS,QAAU,mBAAmBC,KAAKN,WAC7DI,GAAK,WACA,GAAID,SAASE,SAAS,UAAY,UAAUC,KAAKN,WACtDI,GAAK,QAEP,OAAOA;;;;;IAQT,MAAMG,YAAc,CAACC,QAASC,iBAC5B,GAAIA,cAAcC,YAAaD,cAAcE,WAAWC,aAAaJ,QAASC,cAAcC,kBACvFD,cAAcE,WAAWE,YAAYL,UAG5Cb,OAAOD,QAAU,CAAEK,MAAOQ;;;;;;6DC7B1B,MAAM,aAAkB,uCAAQ,oBAEhC,MAAMO,MAAQ,CACZC,aAAc,8SACdC,aAAc,siBACdC,SAAU,u7BAGZ,MAAMC,QAAU,CACdC,SAAU,CAAC,WAAY,UACvBC,UAAW,CAAC,WAAY,QAAS,OAAQ,iBAAkB,QAAS,OAAQ,QAAS,QAAS,SAAU,WAAY,QAAS,QAAS,SAAU,MAAO,OAAQ,OAAQ,MAAO,SAGhL,IAAIC,iBACJ,IAAIC,sBAEJ,MAAMC,aAAe,CAACC,MAAOC;;AAE3B,GAAID,MAAME,UAAUC,SAAS,kBAAoBH,MAAMI,GAAI,OAE3D,MAAMC,KAAOL,MAAMM,aAAa,QAChC,IAAKZ,QAAQC,SAASd,SAASmB,MAAML,YAAcD,QAAQE,UAAUf,SAASwB,MAAO;gCAGrF;IAAIE,GAAKP,MAAMb,WACf,MAAOoB,IAAMA,GAAGZ,WAAa,KAAMY,GAAKA,GAAGpB,WAC3C,IAAKoB,GAAI,OACT,IAAKA,GAAGL,UAAUC,SAAS,kBAAmBI,GAAGL,UAAUM,IAAI,kBAE/D,MAAMC,MAAQT,MAAMb,WAAWA,WAAWiB,KAAOC,OAAS,YAAcA,OAAS,SAC7EK,SAASC,cAAc,kBAAoBX,MAAMb,WAAWA,WAAWiB,GAAGQ,QAAQ,MAAO,OAAS,KAClGF,SAASC,cAAc,aAAeX,MAAMI,GAAGQ,QAAQ,MAAO,OAAS,KAE3E,IAAKH,MACHI,QAAQC,MAAM,mCAAmCd,MAAMI,IAAMJ,MAAMM,aAAa,iIAGlFN,MAAME,UAAUM,IAAI;wBAIpB;MAAMO,SAAWL,SAASM,cAAc,SACxCD,SAASE,UAAY,8BAErB,GAAIZ,OAAS,YAAcA,OAAS,QAAS;;AAE3C,IAAIa,GAAKlB,MAAMb,WACf,MAAO+B,IAAMA,GAAGvB,WAAa,KAAMuB,GAAKA,GAAG/B,WAE3C,IAAK+B,GAAI,CACPL,QAAQC,MAAM,mCAAmCd,MAAMI,IAAMJ,MAAMM,aAAa,+CAChF,MACF,CAEA,GAAIY,GAAGC,WAAWxB,WAAa,QAAS,CACtC,GAAIU,OAAS,YAAcL,MAAMb,WAAWQ,WAAa,KAAM,CAC7DoB,SAASK,aAAa,MAAOpB,MAAMI,IACnCJ,MAAMb,WAAWe,UAAUM,IAAI,kBAC/BO,SAASE,UAAY,GACrBR,MAAMW,aAAa,SAAU,UAC7BrC,YAAYgC,SAAUf,MACxB,CAEA,GAAIK,OAAS,SAAWL,MAAMb,WAAWQ,WAAa,KAAM,CAC1DoB,SAASK,aAAa,MAAOpB,MAAMI,IACnCJ,MAAMb,WAAWe,UAAUM,IAAI,eAC/BO,SAASE,UAAY,GACrBR,MAAMW,aAAa,SAAU,UAC7BrC,YAAYgC,SAAUf,MACxB,CAEAe,SAASM,UAAYZ,MAAMY,UAE3B,GAAIZ,MAAMa,aAAa,UAAYb,MAAMH,aAAa,yBAA2B,OAASG,MAAME,cAAc,aAAc,CAC1H,MAAMY,KAAOd,MAAMH,aAAa,SAChCG,MAAMY,WAAa,iBAAiBE,sBAAsBjC,MAAMG,kBAChEsB,SAASM,WAAa,iBAAiBE,sBAAsBjC,MAAMG,iBACrE,CAEA,GAAIyB,GAAGP,cAAc,cAAgBF,MAAMH,aAAa,sBAAwB,OAASG,MAAME,cAAc,iBAAkB,CAC7H,MAAMY,KAAOd,MAAMH,aAAa,uBAAyB,0BACzDG,MAAMY,WAAa,iBAAiBE,kCACpCR,SAASM,WAAa,iBAAiBE,iCACzC,CAEA,IAAKL,GAAGP,cAAc,SAAUO,GAAGM,OAAOT,SAC5C;kEAGA;GAAIG,GAAGO,cAAc9B,WAAa,MAAOuB,GAAGO,cAAcC,SAE1D,MAAMC,IAAMjB,SAASM,cAAc,OACnCW,IAAIH,OAAOf,MAAMmB,QAAQ,MAAOV,IAChCX,GAAGiB,OAAOG,IACZ,KAAO,CACLZ,SAASK,aAAa,MAAOpB,MAAMI,IACnCW,SAASM,UAAYZ,MAAMY,UAE3B,GAAIrB,MAAMsB,aAAa,UAAYb,MAAMH,aAAa,yBAA2B,OAASG,MAAME,cAAc,aAAc,CAC1H,MAAMY,KAAOvB,MAAMM,aAAa,SAChCS,SAASM,WAAa,iBAAiBE,sBAAsBjC,MAAMG,iBACrE,CAEA,GAAIO,MAAMsB,aAAa,aAAeb,MAAMH,aAAa,sBAAwB,OAASG,MAAME,cAAc,iBAAkB,CAC9H,MAAMY,KAAOd,MAAMH,aAAa,uBAAyB,0BACzDS,SAASM,WAAa,iBAAiBE,iCACzC,CAEAd,MAAMW,aAAa,SAAU,UAE7BrC,YAAYgC,SAAUf,MACxB;;0BAKA;MAAM6B,UAAY7B,MAAM4B,QAAQ,MAAMH,cAAc9B,WAAa;6CAGjE;GAAIK,MAAMM,aAAa,oBAAsB,KAAM;;AAEjD,GAAIN,MAAML,WAAa,SAAWK,MAAMK,OAAS,OAAQ,CACvD,MAAMyB,SAAWpB,SAASM,cAAc,YACxCc,SAAS1B,GAAKJ,MAAMI,GACpB0B,SAASC,MAAQ/B,MAAM+B,MACvBD,SAASE,UAAYhC,MAAMiC,MAC3BH,SAASV,aAAa,iBAAkB,IACxCpB,MAAMkC,YAAYJ,UAClB9B,MAAQ8B,QACV,CAEA,GAAI9B,MAAML,WAAa;;AAErBK,MAAMmC,iBAAiB,WAAaC,IAClC,GAAIA,EAAEC,MAAQ,SAAYD,EAAEC,MAAQ,SAAWD,EAAEE,SAAW,OAC5DF,EAAEG,iBACFtC,KAAKuC,iBAGX,CAEA,GAAInC,OAAS,YAAcA,OAAS,QAAS,CAC3C,IAAKL,MAAMM,aAAa,eAAgBN,MAAMoB,aAAa,cAAe,KAE1E,MAAMO,IAAME,UAAY7B,MAAM4B,QAAQ,MAAMH,cAAgBf,SAASM,cAAc,OACnF,MAAMyB,GAAKhC,MAAMmB,QAAQ,MACzB,MAAMV,GAAKlB,MAAM4B,QAAQ,MAEzB,IAAKa,KAAOvB,GAAI,CACdL,QAAQC,MAAM,mCAAmCd,MAAMI,IAAMJ,MAAMM,aAAa,gDAAgDmC,GAAK,OAAS,mBAC9I,MACF;qBAGA;GAAIzC,MAAML,WAAa,UAAYU,OAAS,QAAS,CACnD,MAAMqC,SAAWhC,SAASM,cAAc,UACxC0B,SAASrC,KAAO,SAChBqC,SAASC,MAAQ3C,MAAMM,aAAa,0BAA4B,cAChEoC,SAASE,UAAY5C,MAAMM,aAAa,0BAA4B,cACpEoC,SAASG,UAAY,EACrBH,SAASrB,UAAY,8IACrBqB,SAASxC,UAAUM,IAAI,SACvBkC,SAAStC,GAAK,4BAA4BJ,MAAMI,KAChDsC,SAASP,iBAAiB,QAAS,KACjCnC,MAAM8C,cAAgB9C,MAAMiC,MAC5BjC,MAAMiC,MAAQ,GACdjC,MAAM+C,QACNjD,sBAAwBE,MAAMI;wDAG9BJ;MAAMgD,cAAc,IAAIC,MAAM,QAAS,CAAEC,QAAS,UAEpDnE,YAAY2D,SAAUxB,GAAGP,cAAc,SACzC,CAEAX,MAAMmC,iBAAiB,QAASgB,QAC9B,GAAIA,MAAMC,OAAOzD,WAAa,QAASE,iBAAmBsD,MAAMC;0DAIlE;GAAI,WAAWtE,KAAKoC,GAAGD,WAAY,CACjC,MAAMoC,MAAQnC,GAAGD,UAAUoC,MAAM,wBAAwB,GACzDnC,GAAGhB,UAAUwB,OAAO2B,OACpB1B,IAAIzB,UAAUM,IAAI6C,MACpB;;sGAIA;GAAIrD,MAAMM,aAAa,sBAAwB,KAC7C,KAAM,gBAAiBI,SAASM,cAAc,SAASsC,OAAQ,CAC7D,MAAMC,YAAc,KAClB,MAAMtB,MAAQjC,MAAMiC,QAAU,GAAKjC,MAAMiC,MAAQjC,MAAMwD,YACvD,MAAMC,MAAQxB,MAAMyB,OAAS,EAAI,GACjC1D,MAAMsD,MAAMG,MAAQA,MAAQ,KAC5BzD,MAAMsD,MAAMK,SAAW,QAEzBJ,cACAvD,MAAMmC,iBAAiB,QAASoB,YAClC;8DAIF;IAAK1B,UAAW,CACdF,IAAIH,OAAOiB,GAAIvB,IACfX,GAAGiB,OAAOG;8CAGV;GAAIc,GAAGa,MAAMM,UAAY,QAAU1C,GAAGoC,MAAMM,UAAY,OAAQjC,IAAI2B,MAAMM,QAAU,MACtF,CACF;;0DAIA;GAAIvD,OAAS,OAAQ,CACnB,MAAMqC,SAAW1C,MAAMyB,cAAcd,cAAc,UACnDX,MAAMmC,iBAAiB,QAASgB,QAC9BT,SAASY,MAAMM,QAAUT,MAAMC,OAAOS,MAAMH,OAAS,OAAS,SAEhEhB,SAASP,iBAAiB,QAAS,KACjCO,SAASY,MAAMM,QAAU,QAE7B;;iDAIA;GAAIvD,OAAS,SAAWL,MAAME,UAAUC,SAAS,gBAAiB,CAChE,MAAMM,MAAQT,MAAMb,WAAWA,WAAWwB,cAAc,YACxDF,MAAMY,WAAa,4CAA4CrB,MAAMiC,iBACrEjC,MAAMmC,iBAAiB,QAASgB,QAC9B,MAAMW,OAASX,MAAMC,OAAOjE,WAAWA,WAAWwB,cAAc,UAChEmD,OAAOzC,UAAY8B,MAAMC,OAAOnB,OAEpC;uBAGA;GAAI5B,OAAS,YAAcL,MAAMM,aAAa,oBAAsB,KAAM,CACxE,MAAMyD,QAAUrD,SAASM,cAAc,UACvC+C,QAAQ1D,KAAO,SACf0D,QAAQpB,MAAQ3C,MAAMM,aAAa,4BAA8B,gBACjEyD,QAAQnB,UAAY5C,MAAMM,aAAa,4BAA8B,gBACrEyD,QAAQlB,UAAY,EACpBkB,QAAQ1C,UAAY/B,MAAMC,aAC1BwE,QAAQ7D,UAAUM,IAAI,QACtBuD,QAAQ3D,GAAK,2BAA2BJ,MAAMI,KAC9C,MAAMc,GAAKlB,MAAM4B,QAAQ,MACzB,IAAKV,GAAI,CACPL,QAAQC,MAAM,mCAAmCd,MAAMI,IAAMJ,MAAMM,aAAa,+CAChF,MACF,CACAyD,QAAQ5B,iBAAiB,QAAS,KAChC,GAAInC,MAAMK,OAAS,WAAY,CAC7B0D,QAAQ1C,UAAY/B,MAAME,aAC1BuE,QAAQpB,MAAQ3C,MAAMM,aAAa,4BAA8B,gBACjEyD,QAAQnB,UAAY5C,MAAMM,aAAa,4BAA8B,gBACrEN,MAAMK,KAAO,MACf,KAAO,CACL0D,QAAQ1C,UAAY/B,MAAMC,aAC1BwE,QAAQpB,MAAQ3C,MAAMM,aAAa,4BAA8B,gBACjEyD,QAAQnB,UAAY5C,MAAMM,aAAa,4BAA8B,gBACrEN,MAAMK,KAAO,UACf,CACAL,MAAM+C,UAERhE,YAAYgF,QAAS7C,GAAGP,cAAc,SACxC;4DAGA;GAAIX,MAAML,WAAa,WAAY,CACjC,GAAIK,MAAMM,aAAa,2BAA6B,KAAM;;AAExDN,MAAMsD,MAAMU,YAAY,SAAU,QAClChE,MAAMsD,MAAMU,YAAY,aAAc,KACtChE,MAAMsD,MAAMU,YAAY,aAAc,QACtChE,MAAMsD,MAAMU,YAAY,SAAU,QAElC,MAAMC,YAAc;;AAElB,IAAIC,QAAUlE,MAAMM,aAAa,iBAEjC,GAAI4D,QACF,GAAIC,MAAMD,UAAYE,OAAOF,UAAY,EAAG,CAC1CrD,QAAQwD,KAAK,gHAAgHrE,MAAMM,aAAa,oBAChJ4D,QAAU,IACZ,CAGF,MAAMI,QAAUtE,MAAMM,aAAa,kBAAoB8D,OAAOpE,MAAMM,aAAa,kBAAoB,EAAIN,MAAMM,aAAa,iBAAmB,IAC/IN,MAAMoB,aAAa,OAAQkD;2CAG3B;MAAMhB,MAAQ7E,OAAO8F,iBAAiBvE;6OAGtC;MAAMwE,cAAgBC,WAAWnB,MAAM,iBAAmBmB,WAAWnB,MAAM,kBAC3E,MAAMoB,kBAAoBD,WAAWnB,MAAM,sBAAwBmB,WAAWnB,MAAM,uBACpFtD,MAAMsD,MAAMU,YAAY,WAAY,SAAU,aAC9ChE,MAAMsD,MAAMU,YAAY,QAAUS,WAAWnB,MAAMG,OAASe,cAAgBE,kBAAqB,MACjG1E,MAAMsD,MAAMU,YAAY,aAAc,eACtChE,MAAMsD,MAAMU,YAAY,iBAAkB,KAC1ChE,MAAMsD,MAAMU,YAAY,eAAgB;qDAGxC;MAAMW,aAAeF,WAAWnB,MAAM,gBAAkBmB,WAAWnB,MAAM,mBACzE,MAAMsB,WAAatB,MAAM,iBAAmB,SACxCmB,WAAWnB,MAAMuB,QACjBJ,WAAWnB,MAAM;kFAGrB;MAAMwB,aAAeC,KAAKC,MAAMhF,MAAM8E;4EAGtC9E;MAAMsD,MAAM2B,eAAe,SAC3BjF,MAAMsD,MAAM2B,eAAe,cAC3BjF,MAAMsD,MAAM2B,eAAe,kBAC3BjF,MAAMsD,MAAM2B,eAAe,gBAC3BjF,MAAMsD,MAAM2B,eAAe;uLAG3B;MAAMC,KAAOH,KAAKC,OAAOF,aAAeH,cAAgBC;0DAGxD;GAAIV,QACFlE,MAAMoB,aAAa,OAAQ,GAAK2D,KAAKI,IAAID,KAAMd,OAAOF,gBAEtDlE,MAAMoB,aAAa,OAAQ,GAAK8D,OAIpClF,MAAMmC,iBAAiB,QAAS8B;kDAGhCjE;MAAMgD,cAAc,IAAIC,MAAM,QAAS,CAAEC,QAAS,OACpD;;sGAIA;GAAIlD,MAAMM,aAAa,oBAAsB,KAC3C,KAAM,gBAAiBI,SAASM,cAAc,SAASsC,OAAQ,CAC7D,MAAM8B,aAAe,KACnB,GAAIpF,MAAMiC,MAAMyB,OAAQ,CACtB,MAAM2B,YAAcC,SAAS7G,OAAO8F,iBAAiBvE,OAAOuF,iBAAiB,iBAC7EvF,MAAMsD,MAAMuB,OAAU7E,MAAM8E,aAAgBO,YAAc,EAAM,IAClE,MACErF,MAAMsD,MAAMuB,OAASpG,OAAO8F,iBAAiBtE,MAAMsF,iBAAiB;oDAKxEvF;MAAMsD,MAAMuB,OAASpG,OAAO8F,iBAAiBtE,MAAMsF,iBAAiB,8BACpEvF,MAAMmC,iBAAiB,QAASiD,aAClC;iEAIF;MAAMI,cAAgB,KACpB,MAAM9C,SAAW1C,MAAMyB,eAAed,cAAc,gBACpD,GAAI+B,SAAUA,SAASY,MAAMmC,YAAczF,MAAM0F,aAAe1F,MAAM8E,aAAe,OAAS,IAEhG9E,MAAMmC,iBAAiB,QAASqD,eAChCxF,MAAMmC,iBAAiB,UAAWqD,eAClCA,eACF,GAGF,MAAMG,eAAkBxC;;AAEtB,IAAKA,MAAMyC,SAAWzC,MAAM0C,UAAY1C,MAAMd,MAAQ,MAAQc,MAAMb;;AAElE,GAAIzC,iBACF,GAAIA,kBAAkBV,YAAYwB,cAAc,gBAAgBP,KAAO,4BAA4BN,yBAA2BD,kBAAkBV,YAAYwB,cAAc,gBAAgBmF,OAAS,4BAA4BhG,wBAC7N,GAAID,iBAAiBiD,cAAe,CAClCjC,QAAQkF,IAAI,oBAAqBlG,iBAAiBoC,OAClDpC,iBAAiBmG,UAAYnG,iBAAiBoC,MAC9CpC,iBAAiBoC,MAAQpC,iBAAiBiD,aAC5C,OAIJ,GAAKK,MAAMyC,SAAWzC,MAAMd,MAAQ,KAASc,MAAM0C,SAAW1C,MAAMb,UAAYa,MAAMd,MAAQ;;AAE5F,GAAIxC,iBACF,GAAIA,kBAAkBV,YAAYwB,cAAc,gBAAgBP,KAAO,4BAA4BN,yBAA2BD,kBAAkBV,YAAYwB,cAAc,gBAAgBmF,OAAS,4BAA4BhG,wBAC7N,GAAID,iBAAiBmG,UAAW,CAC9BnG,iBAAiBiD,cAAgBjD,iBAAiBoC,MAClDpC,iBAAiBoC,MAAQpC,iBAAiBmG,SAC5C,GAOV7H,OAAOD,QAAU,CAAE6B,aAAc4F;;;;;;6DCxYjC,MAAM,MAAO,aAAkB,uCAAQ,oBAEvC,MAAMM,eAAiB,CACrBC,MAAO,IACPC,MAAO,IACPC,YAAa,IACbC,aAAc,IACdC,UAAW,KACXC,UAAW,IACXC,MAAO,IACPC,MAAO,IACPC,OAAQ,IACRC,MAAO,IACPC,UAAW,KAEb,MAAMC,oBAAsB,CAC1B,EAAG,IACH,EAAG,IACH,EAAG,IACH,EAAG,IACH,EAAG,IACH,EAAG,IACH,EAAG,IACH,EAAG,IACH,EAAG,IACH,EAAG,IACHX,MAAO,IACPC,MAAO,IACPC,YAAa,IACbC,aAAc,IACdC,UAAW,IACXC,UAAW,IACXC,MAAO,IACPC,MAAO,IACPC,OAAQ,IACRC,MAAO,IACPC,UAAW;mCAIb;MAAME,iBAAmB,CAAC1E,EAAG2E;;AAE3B,MAAMC,SAAWD,UAAUE,KAAKD,WAC9B,IAAIE,WAAa,MACjB,GAAI9E,EAAE+E,SAAW/E,EAAEE;;AAEjB4E,WAAa,MAAQF,SAAS3E,IAAI+E,gBAAkBhF,EAAEiF,MACpD,QAAUL,SAAS3E,IAAI+E,gBAAkBhF,EAAEiF,MAC3CL,SAAS3E,MAAQD,EAAEC,KACnB4D,eAAe7D,EAAEiF,QAAUL,SAAS3E,SACjC,GAAID,EAAEE,SAAU;;AAErB,MAAM+E,KAAOjF,EAAEiF,KAAKzG,QAAQ,YAAa,IACzCsG,YAAcL,oBAAoBQ,OAASR,oBAAoBzE,EAAEC,QAC9DwE,oBAAoBQ,QAAUL,SAAS3E,KAAOwE,oBAAoBzE,EAAEC,OAAS2E,SAAS3E,IAC3F,MACE6E,WAAaF,SAAS3E,IAAI+E,gBAAkBhF,EAAEC,IAAI+E,cAEpD,IAAKF,WAAY,OAAO,MAExB,IAAII,gBACJ,GAAIN,SAASO,SAAU,CACrB,GAAIP,SAASO,WAAaP,SAASQ,gBAAiBF,gBAAkBN,SAASpI,KAAO,WAAaoI,SAASpI,KAAO,QAAUwD,EAAEwD,QAAUxD,EAAEyD,QAC3I,GAAImB,SAASO,WAAa,OAAQD,gBAAkBlF,EAAEyD,QACtD,GAAImB,SAASO,WAAa,MAAOD,gBAAkBlF,EAAE+E,OACrD,GAAIH,SAASO,WAAa,OAAQD,gBAAkBlF,EAAEwD,OACxD,CACA,OAAO0B,kBAGT,GAAIN,SAAU,CACZ5E,EAAEG,iBACFyE,SAAShH,MAAM+C,OACjB,GAGF,MAAM0E,uBAAyB,CAACzH,MAAO+G,aACrC,MAAMnI,GAAKL;oEAEX;MAAMiJ,gBAAkB;sBAGxB;IAAIE,SAAW1H,MAAMM,aAAa,kBAClC,GAAIoH,SAAShE,OAAS,EAAG,CACvB7C,QAAQC,MAAM,uBAAuB4G,qEACrCA,SAAWA,SAASC,WAAW,EACjC;2BAGA;IAAIC,eACJ,IAAIC,YAAcL,gBAClB,MAAMM,aAAe,CACnBC,QAAS/H,MAAMM,aAAa,wBAA0BkH,gBACtDQ,MAAOhI,MAAMM,aAAa,6BAC1B2H,IAAKjI,MAAMM,aAAa,2BACxB4H,QAASlI,MAAMM,aAAa,4BAE9B,GAAI1B,IAAMkJ,aAAalJ;;AAErBiJ,YAAcC,aAAalJ,SAE3BiJ,YAAcC,aAAaC;8BAI7B;MAAMI,oBAAsB,CAAC,OAAQ,MAAO,MAAO,OAAQ,MAAOX,iBAClE,IAAKW,oBAAoBtJ,SAASgJ,aAAc,CAC9ChH,QAAQC,MAAM,uCAAuC+G,gCAAgCL,oBAAqBxH,OAC1G6H,YAAcL,eAChB;2BAGA;GAAI,CAAC,MAAO,OAAO3I,SAASgJ,aAC1BD,eAAiBhJ,KAAO,MAAQ,IAAM,SACjC,GAAI,CAAC,OAAQ,MAAO,OAAOC,SAASgJ,cAAiBA,cAAgBL,iBAAmB5I,KAAO,MACpG,GAAIA,KAAO,MACTgJ,eAAiB,SACZ,GAAIhJ,KAAO,QAChBgJ,eAAiB,SAEjBA,eAAiB,SAEd,GAAIC,cAAgB,QAAWA,cAAgBL,kBAAoB5I,KAAO,WAAaA,KAAO,SACnG,GAAIA,KAAO,MACTgJ,eAAiB,SAEjBA,eAAiB;2DAKrB;GAAIb,UAAUqB,KAAKpB,UAAYA,SAAS3E,MAAQqF,UAAYV,SAASO,WAAaM,aAChFhH,QAAQC,MAAM,gCAAgC+G,iBAAiBH,2FAA4F1H;mCAI7J;GAAIA,MAAML,WAAa,YAAcK,MAAMK,OAAS,QAAUL,MAAMK,OAAS,SAAU;;AAErF,MAAMgI,UAAY3H,SAASM,cAAc,QACzCqH,UAAUnI,UAAUM,IAAI,aACxB6H,UAAUhH,UAAY,QAAQuG,kBAAkBF,SAASN,sBAEzD,MAAM3G,MAAQT,MAAMd,YACpBH,YAAYsJ,UAAW5H,MACzB;;AAEE,GAAIT,MAAMM,aAAa,SACrBN,MAAMoB,aAAa,QAASpB,MAAMM,aAAa,SAAW,KAAKsH,oBAAoBF,kBAEnF1H,MAAMoB,aAAa,QAAS,cAAcwG,oBAAoBF,YAIlE,MAAO,CACLrF,IAAKqF,SACLH,SAAUM,YACV7H,MACApB,GACA4I,kBAIJrJ,OAAOD,QAAU,CACf4I,iBACAW;;;;;;6DCpKF,MAAM,uBAAwB,kBAAuB,qDAAQ,8BAC7D,MAAM,aAAc,gBAAqB,qDAAQ,8BAEjD,MAAMa,cAAgB;;AAEpB,UAAW5H,SAAS6H,yBAA2B,mBAAqB7H,SAASC,gBAAkB,aAAeD,SAAS8H,KAAKtI,YAAczB,OAAOgK,iBAAkB,CACjK5H,QAAQwD,KAAK,+EACb,MACF;oCAGA;MAAMqE,kBAAoB,GAC1BhI,SAASyB,iBAAiB,UAAYC,GAAM0E,iBAAiB1E,EAAGsG;wEAGhE;MAAMC,MAAQjI,SAASkI,iBAAiB,+FAExC,IAAK,MAAM3I,QAAQ0I,MAAO,CACxB1I,KAAKC,UAAUM,IAAI,uBACnB,GAAIP,KAAKC,UAAUC,SAAS,WAAY;yCAGxC;MAAM0I,OAASC,MAAMC,KAAK9I,KAAK2I,iBAAiB,4BAChD,IAAK,MAAM5I,SAAS6I,OAAQ,CAC1B9I,aAAaC,MAAOC;4BAGpB;GAAID,MAAMM,aAAa,oBAAsB,KAAM,CACjD,MAAM0G,SAAWS,uBAAuBzH,MAAO0I,mBAC/CA,kBAAkBM,KAAKhC,SACzB,CACF,CACF;8BAGAtG;SAASuI,oBAAoB,UAAWtD,gBACxCjF,SAASyB,iBAAiB,UAAWwD;gFAGrC;IAAKlH,OAAOyK,sBAAuB,CACjCzK,OAAOyK,sBAAwB,IAAIzK,OAAOgK,iBAAiBU,YACzD,IAAIC,KAAO,MACX,IAAK,MAAMC,YAAYF,UAAW,CAChC,IAAK,MAAMG,QAAQD,SAASE,WAC1B,GAAID,KAAK3J,WAAa,QAAU2J,MAAM3I,gBAAgB,QAAS,CAC7D2H,gBACAc,KAAO,IACT,CAEF,GAAIA,KAAM,KACZ,IAEF3K,OAAOyK,sBAAsBM,QAAQ9I,SAAS8H,KAAM,CAAEiB,WAAY,MAAOC,UAAW,KAAMC,cAAe,MAAOC,QAAS,MAC3H,CAEAtB,cAAcuB,aAAe5J,OAC3BA,KAAKC,UAAUwB,OAAO,uBACtB4G,kBAIJnK,OAAOD,QAAUoK;;;;;QC5DjB,IAAIwB,yBAA2B,CAAC;;;QAGhC,SAASC,oBAAoBC;;QAE5B,IAAIC,aAAeH,yBAAyBE;QAC5C,GAAIC,oBAAiBC;QACpB,OAAOD,aAAa/L;;;QAGrB,IAAIC,OAAS2L,yBAAyBE,UAAY;;;QAGjD9L,QAAS,CAAC;;;;QAIXiM,oBAAoBH,UAAU7L,OAAQA,OAAOD,QAAS6L;;;QAGtD,OAAO5L,OAAOD;QACf;;;;;;;QCnBA,IAAIkM,oBAAsBL,oBAAoB","sources":["webpack://semanticForms/webpack/universalModuleDefinition","webpack://semanticForms/./lib/helpers.js","webpack://semanticForms/./lib/inputEnhancements.js","webpack://semanticForms/./lib/keyboardShortcuts.js","webpack://semanticForms/./semanticForms.js","webpack://semanticForms/webpack/bootstrap","webpack://semanticForms/webpack/startup"],"sourcesContent":["(function webpackUniversalModuleDefinition(root, factory) {\n\tif(typeof exports === 'object' && typeof module === 'object')\n\t\tmodule.exports = factory();\n\telse if(typeof define === 'function' && define.amd)\n\t\tdefine(\"semanticForms\", [], factory);\n\telse if(typeof exports === 'object')\n\t\texports[\"semanticForms\"] = factory();\n\telse\n\t\troot[\"semanticForms\"] = factory();\n})(this, () => {\nreturn ","/**\n * Uses the navigator to best determine the clients operating system.\n * @returns Operating system string (`mac`, `windows`, `linux`)\n */\nconst getOS = () => {\n const userAgent = window.navigator.userAgent\n const platform = window.navigator.platform\n let os = null\n\n if (platform.includes('Win')) {\n os = 'windows'\n } else if (platform.includes('Mac') || /iPhone|iPad|iPod/.test(userAgent)) {\n os = 'mac'\n } else if (platform.includes('Linux') || /Android/.test(userAgent)) {\n os = 'linux'\n }\n return os\n}\n\n/**\n * Places an element immediately after another element\n * @param {Object} newNode element being placed after the reference node\n * @param {*} referenceNode element to be used as reference for new node\n */\nconst insertAfter = (newNode, referenceNode) => {\n if (referenceNode.nextSibling) referenceNode.parentNode.insertBefore(newNode, referenceNode.nextSibling)\n else referenceNode.parentNode.appendChild(newNode)\n}\n\nmodule.exports = { getOS, insertAfter }\n","const { insertAfter } = require('./helpers.js')\n\nconst icons = {\n passwordShow: '<svg fill=\"none\" height=\"256\" viewBox=\"0 0 24 24\" width=\"256\" xmlns=\"http://www.w3.org/2000/svg\"><g stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\"><path d=\"m1 12s4-8 11-8 11 8 11 8\"/><path d=\"m1 12s4 8 11 8 11-8 11-8\"/><circle cx=\"12\" cy=\"12\" r=\"3\"/></g></svg>',\n passwordHide: '<svg fill=\"none\" height=\"256\" viewBox=\"0 0 24 24\" width=\"256\" xmlns=\"http://www.w3.org/2000/svg\"><g stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\"><path d=\"m2 2 20 20\"/><path d=\"m6.71277 6.7226c-3.04798 2.07267-4.71277 5.2774-4.71277 5.2774s3.63636 7 10 7c2.0503 0 3.8174-.7266 5.2711-1.7116m-6.2711-12.23018c.3254-.03809.6588-.05822 1-.05822 6.3636 0 10 7 10 7s-.6918 1.3317-2 2.8335\"/><path d=\"m14 14.2362c-.5308.475-1.2316.7639-2 .7639-1.6569 0-3-1.3431-3-3 0-.8237.33193-1.5698.86932-2.11192\"/></g></svg>',\n helpIcon: '<svg xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" version=\"1.1\" style=\"overflow:visible;\"><rect width=\"16\" height=\"16\" fill=\"none\"/><path fill=\"currentColor\" d=\"M8,10.5c-0.552,0-1,0.448-1,1c0,0.552,0.448,1,1,1c0.552,0,1-0.448,1-1C9,10.948,8.552,10.5,8,10.5z M8,0 C3.582,0,0,3.582,0,8c0,4.418,3.582,8,8,8s8-3.582,8-8C16,3.582,12.418,0,8,0z M12.243,12.243C11.109,13.376,9.603,14,8,14 s-3.109-0.624-4.243-1.757C2.624,11.109,2,9.603,2,8s0.624-3.109,1.757-4.243C4.891,2.624,6.397,2,8,2s3.109,0.624,4.243,1.757 C13.376,4.891,14,6.397,14,8C14,9.603,13.376,11.109,12.243,12.243z M7.927,3.755c-2.248,0-2.76,1.695-2.802,2.906h1.571 c0.028-0.256,0.101-1.418,1.221-1.418c0.672,0,1.206,0.406,1.206,1.175c0,0.695-0.724,1.155-1.303,1.711 C7.241,8.685,7.168,9.325,7.168,9.824V10c0.146,0,1.615,0,1.615,0V9.824c0-1.256,1.967-1.594,1.967-3.541 C10.75,5.059,9.874,3.755,7.927,3.755z\"/></svg>'\n}\n\nconst lookups = {\n nodeName: ['TEXTAREA', 'SELECT'],\n inputType: ['checkbox', 'color', 'date', 'datetime-local', 'email', 'file', 'image', 'month', 'number', 'password', 'radio', 'range', 'search', 'tel', 'text', 'time', 'url', 'week']\n}\n\nlet lastFocusedInput\nlet lastClearFieldPressed\n\nconst enhanceInput = (input, form) => {\n // ignore input if it has previously been formatted\n if (input.classList.contains('semanticform') || !input.id) return\n\n const type = input.getAttribute('type')\n if (!lookups.nodeName.includes(input.nodeName) && !lookups.inputType.includes(type)) return\n\n // recursively find <dl> element\n let dl = input.parentNode\n while (dl && dl.nodeName !== 'DL') dl = dl.parentNode\n if (!dl) return\n if (!dl.classList.contains('floatLabelForm')) dl.classList.add('floatLabelForm')\n\n const label = input.parentNode.parentNode.id && (type === 'checkbox' || type === 'radio')\n ? document.querySelector('label[data-for=' + input.parentNode.parentNode.id.replace(/\\./g, '\\\\.') + ']')\n : document.querySelector('label[for=' + input.id.replace(/\\./g, '\\\\.') + ']')\n\n if (!label) {\n console.error(`semantic-forms: Found an input (${input.id || input.getAttribute('name')}) without a properly associated label. Make sure there is a label for it and the label has a matching \"for\" attribute.`)\n }\n\n input.classList.add('semanticform')\n\n // #region create labels\n\n const newLabel = document.createElement('label')\n newLabel.className = 'floatLabelFormAnimatedLabel'\n\n if (type === 'checkbox' || type === 'radio') {\n // recursively find <dd> element\n let dd = input.parentNode\n while (dd && dd.nodeName !== 'DD') dd = dd.parentNode\n\n if (!dd) {\n console.error(`semantic-forms: Found an input (${input.id || input.getAttribute('name')}) that is not inside a <dd> element.`)\n return\n }\n\n if (dd.firstChild.nodeName !== 'LABEL') {\n if (type === 'checkbox' && input.parentNode.nodeName === 'DD') {\n newLabel.setAttribute('for', input.id)\n input.parentNode.classList.add('singleCheckbox')\n newLabel.className = ''\n label.setAttribute('hidden', 'hidden')\n insertAfter(newLabel, input)\n }\n\n if (type === 'radio' && input.parentNode.nodeName === 'DD') {\n newLabel.setAttribute('for', input.id)\n input.parentNode.classList.add('singleRadio')\n newLabel.className = ''\n label.setAttribute('hidden', 'hidden')\n insertAfter(newLabel, input)\n }\n\n newLabel.innerHTML = label.innerHTML\n\n if (label.hasAttribute('title') && label.getAttribute('data-show-help-icon') !== null && !label.querySelector('span.help')) {\n const text = label.getAttribute('title')\n label.innerHTML += ` <span title=\"${text}\" class=\"help\">${icons.helpIcon}</span>`\n newLabel.innerHTML += ` <span title=\"${text}\" class=\"help\">${icons.helpIcon}</span>`\n }\n\n if (dd.querySelector(':required') && label.getAttribute('data-no-asterisk') === null && !label.querySelector('span.required')) {\n const text = label.getAttribute('data-asterisk-text') || 'This field is required.'\n label.innerHTML += ` <span title=\"${text}\" class=\"required\">*</span>`\n newLabel.innerHTML += ` <span title=\"${text}\" class=\"required\">*</span>`\n }\n\n if (!dd.querySelector('label')) dd.append(newLabel)\n }\n\n // removes old div that a radio or checkbox may have been added to\n if (dd.parentElement.nodeName === 'DIV') dd.parentElement.remove()\n\n const div = document.createElement('div')\n div.append(label.closest('dt'), dd)\n dl.append(div)\n } else {\n newLabel.setAttribute('for', input.id)\n newLabel.innerHTML = label.innerHTML\n\n if (input.hasAttribute('title') && label.getAttribute('data-show-help-icon') !== null && !label.querySelector('span.help')) {\n const text = input.getAttribute('title')\n newLabel.innerHTML += ` <span title=\"${text}\" class=\"help\">${icons.helpIcon}</span>`\n }\n\n if (input.hasAttribute('required') && label.getAttribute('data-no-asterisk') === null && !label.querySelector('span.required')) {\n const text = label.getAttribute('data-asterisk-text') || 'This field is required.'\n newLabel.innerHTML += ` <span title=\"${text}\" class=\"required\">*</span>`\n }\n\n label.setAttribute('hidden', 'hidden')\n\n insertAfter(newLabel, input)\n }\n // #endregion\n\n // #region standard inputs\n\n const isWrapped = input.closest('dd').parentElement.nodeName === 'DIV'\n\n // check for auto-grow attribute on textareas\n if (input.getAttribute('data-auto-grow') !== null) {\n // progressively enhance inputs into textareas\n if (input.nodeName === 'INPUT' && input.type === 'text') {\n const newInput = document.createElement('textarea')\n newInput.id = input.id\n newInput.class = input.class\n newInput.innerText = input.value\n newInput.setAttribute('data-auto-grow', '')\n input.replaceWith(newInput)\n input = newInput\n }\n\n if (input.nodeName === 'TEXTAREA') {\n // when pressing enter while this input is focused, we want to submit\n input.addEventListener('keypress', (e) => {\n if (e.key !== 'Enter' || (e.key === 'Enter' && e.shiftKey)) return\n e.preventDefault()\n form.requestSubmit()\n })\n }\n }\n\n if (type !== 'checkbox' && type !== 'radio') {\n if (!input.getAttribute('placeholder')) input.setAttribute('placeholder', ' ')\n\n const div = isWrapped ? input.closest('dd').parentElement : document.createElement('div')\n const dt = label.closest('dt')\n const dd = input.closest('dd')\n\n if (!dt || !dd) {\n console.error(`semantic-forms: Found an input (${input.id || input.getAttribute('name')}) that does not have a corresponding ${!dt ? '<dt>' : '<dd>'} element.`)\n return\n }\n\n // input clear button\n if (input.nodeName !== 'SELECT' && type !== 'range') {\n const clearBtn = document.createElement('button')\n clearBtn.type = 'button'\n clearBtn.title = input.getAttribute('data-clear-field-text') || 'Clear field'\n clearBtn.ariaLabel = input.getAttribute('data-clear-field-text') || 'Clear field'\n clearBtn.tabIndex = -1\n clearBtn.innerHTML = '<svg viewBox=\"0 0 16 16\" width=\"18\" height=\"18\"><path d=\"M 1 1 L 15 15 M 1 15 L 15 1\" fill=\"none\" stroke-width=\"2\" stroke=\"currentColor\" />'\n clearBtn.classList.add('clear')\n clearBtn.id = `semanticFormsClearButton_${input.id}`\n clearBtn.addEventListener('click', () => {\n input.previousValue = input.value\n input.value = ''\n input.focus()\n lastClearFieldPressed = input.id\n\n // used for any other updates required by various inputs\n input.dispatchEvent(new Event('input', { bubbles: true }))\n })\n insertAfter(clearBtn, dd.querySelector('label'))\n }\n\n input.addEventListener('focus', event => {\n if (event.target.nodeName === 'INPUT') lastFocusedInput = event.target\n })\n\n // check for colspan- utility class on dd, and move to div\n if (/colspan-/.test(dd.className)) {\n const match = dd.className.match(/colspan-([0-9]|full)/)[0]\n dd.classList.remove(match)\n div.classList.add(match)\n }\n\n // check for max-content attribute\n // this may be removed once fully supported in Firefox and Safari: https://caniuse.com/wf-field-sizing\n if (input.getAttribute('data-max-content') !== null) {\n if (!('fieldSizing' in document.createElement('input').style)) {\n const adjustWidth = () => {\n const value = input.value !== '' ? input.value : input.placeholder\n const width = value.length * 8 + 40\n input.style.width = width + 'px'\n input.style.maxWidth = '100%'\n }\n adjustWidth()\n input.addEventListener('input', adjustWidth)\n }\n }\n\n // if the user did not wrap the input in a div, do it for them\n if (!isWrapped) {\n div.append(dt, dd)\n dl.append(div)\n\n // determine visibility of newly created <div>\n if (dt.style.display === 'none' && dd.style.display === 'none') div.style.display = 'none'\n }\n }\n // #endregion\n\n // handle file input clear btn, cannot be handled with CSS\n if (type === 'file') {\n const clearBtn = input.parentElement.querySelector('.clear')\n input.addEventListener('input', event => {\n clearBtn.style.display = event.target.files.length ? 'flex' : 'none'\n })\n clearBtn.addEventListener('click', () => {\n clearBtn.style.display = 'none'\n })\n }\n\n // handle range inputs with a class to display the value\n // TODO: should this be a data attribute instead?\n if (type === 'range' && input.classList.contains('displayValue')) {\n const label = input.parentNode.parentNode.querySelector('dd label')\n label.innerHTML += `<span class=\"seperator\">: </span><output>${input.value}</output>`\n input.addEventListener('input', event => {\n const output = event.target.parentNode.parentNode.querySelector('output')\n output.innerHTML = event.target.value\n })\n }\n\n // show password button\n if (type === 'password' && input.getAttribute('data-no-reveal') === null) {\n const showBtn = document.createElement('button')\n showBtn.type = 'button'\n showBtn.title = input.getAttribute('data-show-password-text') || 'Show password'\n showBtn.ariaLabel = input.getAttribute('data-show-password-text') || 'Show password'\n showBtn.tabIndex = -1\n showBtn.innerHTML = icons.passwordShow\n showBtn.classList.add('show')\n showBtn.id = `semanticFormsShowButton_${input.id}`\n const dd = input.closest('dd')\n if (!dd) {\n console.error(`semantic-forms: Found an input (${input.id || input.getAttribute('name')}) that is not inside a <dd> element.`)\n return\n }\n showBtn.addEventListener('click', () => {\n if (input.type === 'password') {\n showBtn.innerHTML = icons.passwordHide\n showBtn.title = input.getAttribute('data-hide-password-text') || 'Hide password'\n showBtn.ariaLabel = input.getAttribute('data-hide-password-text') || 'Hide password'\n input.type = 'text'\n } else {\n showBtn.innerHTML = icons.passwordShow\n showBtn.title = input.getAttribute('data-show-password-text') || 'Show password'\n showBtn.ariaLabel = input.getAttribute('data-show-password-text') || 'Show password'\n input.type = 'password'\n }\n input.focus()\n })\n insertAfter(showBtn, dd.querySelector('label'))\n }\n\n // add listener to shift clear button when scrollbar present\n if (input.nodeName === 'TEXTAREA') {\n if (input.getAttribute('data-disable-autosize') === null) {\n // add auto-sizing\n input.style.setProperty('resize', 'none')\n input.style.setProperty('min-height', '0')\n input.style.setProperty('max-height', 'none')\n input.style.setProperty('height', 'auto')\n\n const handleInput = () => {\n // reset rows attribute to get accurate scrollHeight\n let maxRows = input.getAttribute('data-max-rows')\n\n if (maxRows) {\n if (isNaN(maxRows) || Number(maxRows) <= 0) {\n console.warn(`An invalid value was passed to the \"data-max-rows\" attribute. This value will be ignored.\\n\\nProvided value: ${input.getAttribute('data-max-rows')}`)\n maxRows = null\n }\n }\n\n const minRows = input.getAttribute('data-max-rows') && Number(input.getAttribute('data-max-rows')) < 5 ? input.getAttribute('data-max-rows') : '5'\n input.setAttribute('rows', minRows)\n\n // get the computed values object reference\n const style = window.getComputedStyle(input)\n\n // force content-box for size accurate line-height calculation, remove scrollbars, lock width (subtract inline padding and inline border widths), and remove inline padding and borders to keep width consistent (for text wrapping accuracy)\n const inlinePadding = parseFloat(style['padding-left']) + parseFloat(style['padding-right'])\n const inlineBorderWidth = parseFloat(style['border-left-width']) + parseFloat(style['border-right-width'])\n input.style.setProperty('overflow', 'hidden', 'important')\n input.style.setProperty('width', (parseFloat(style.width) - inlinePadding - inlineBorderWidth) + 'px')\n input.style.setProperty('box-sizing', 'content-box')\n input.style.setProperty('padding-inline', '0')\n input.style.setProperty('border-width', '0')\n\n // get the base line height, and top / bottom padding\n const blockPadding = parseFloat(style['padding-top']) + parseFloat(style['padding-bottom'])\n const lineHeight = style['line-height'] === 'normal'\n ? parseFloat(style.height) // if line-height is not explicitly set, use the computed height value (ignore padding due to content-box)\n : parseFloat(style['line-height']) // otherwise (line-height is explicitly set), use the computed line-height value\n\n // get the scroll height (rounding to be safe to ensure cross browser consistency)\n const scrollHeight = Math.round(input.scrollHeight)\n\n // undo overflow, width, border-width, box-sizing & inline padding overrides\n input.style.removeProperty('width')\n input.style.removeProperty('box-sizing')\n input.style.removeProperty('padding-inline')\n input.style.removeProperty('border-width')\n input.style.removeProperty('overflow')\n\n // subtract blockPadding from scrollHeight and divide that by our lineHeight to get the row count, round to nearest integer as it will always be within ~.1 of the correct whole number\n const rows = Math.round((scrollHeight - blockPadding) / lineHeight)\n\n // set the calculated rows attribute (limited by rowLimit)\n if (maxRows) {\n input.setAttribute('rows', '' + Math.min(rows, Number(maxRows)))\n } else {\n input.setAttribute('rows', '' + rows)\n }\n }\n\n input.addEventListener('input', handleInput)\n\n // trigger the event to set the initial rows value\n input.dispatchEvent(new Event('input', { bubbles: true }))\n }\n\n // progressively enhance textarea for Firefox and Safari\n // this may be removed once fully supported in Firefox and Safari: https://caniuse.com/wf-field-sizing\n if (input.getAttribute('data-auto-grow') !== null) {\n if (!('fieldSizing' in document.createElement('input').style)) {\n const adjustHeight = () => {\n if (input.value.length) {\n const borderWidth = parseInt(window.getComputedStyle(input).getPropertyValue('border-width'))\n input.style.height = (input.scrollHeight + (borderWidth * 2)) + 'px'\n } else {\n input.style.height = window.getComputedStyle(form).getPropertyValue('--semanticFormsInputHeight')\n }\n }\n\n // set initial height to semantic-forms CSS variable\n input.style.height = window.getComputedStyle(form).getPropertyValue('--semanticFormsInputHeight')\n input.addEventListener('input', adjustHeight)\n }\n }\n\n // shifts the clear button to the right if a scrollbar is present\n const shiftClearBtn = () => {\n const clearBtn = input.parentElement?.querySelector('button.clear')\n if (clearBtn) clearBtn.style.marginRight = input.clientHeight < input.scrollHeight ? '15px' : ''\n }\n input.addEventListener('input', shiftClearBtn)\n input.addEventListener('mouseup', shiftClearBtn)\n shiftClearBtn()\n }\n}\n\nconst handleUndoRedo = (event) => {\n // handle undo/redo\n if ((event.ctrlKey || event.metaKey) && event.key === 'z' && !event.shiftKey) {\n // undo clearing a field\n if (lastFocusedInput) {\n if (lastFocusedInput?.parentNode?.querySelector('button.clear').id === `semanticFormsClearButton_${lastClearFieldPressed}` || lastFocusedInput?.parentNode?.querySelector('button.clear').name === `semanticFormsClearButton_${lastClearFieldPressed}`) {\n if (lastFocusedInput.previousValue) {\n console.log('update redo value', lastFocusedInput.value)\n lastFocusedInput.redoValue = lastFocusedInput.value\n lastFocusedInput.value = lastFocusedInput.previousValue\n }\n }\n }\n } else {\n if ((event.ctrlKey && event.key === 'y') || (event.metaKey && event.shiftKey && event.key === 'z')) {\n // redo clearing a field\n if (lastFocusedInput) {\n if (lastFocusedInput?.parentNode?.querySelector('button.clear').id === `semanticFormsClearButton_${lastClearFieldPressed}` || lastFocusedInput?.parentNode?.querySelector('button.clear').name === `semanticFormsClearButton_${lastClearFieldPressed}`) {\n if (lastFocusedInput.redoValue) {\n lastFocusedInput.previousValue = lastFocusedInput.value\n lastFocusedInput.value = lastFocusedInput.redoValue\n }\n }\n }\n }\n }\n}\n\nmodule.exports = { enhanceInput, handleUndoRedo }\n","const { getOS, insertAfter } = require('./helpers.js')\n\nconst specialCharMap = {\n Minus: '-',\n Equal: '=',\n BracketLeft: '[',\n BracketRight: ']',\n Backslash: '\\\\',\n Semicolon: ';',\n Quote: '\\'',\n Comma: ',',\n Period: '.',\n Slash: '/',\n Backquote: '`'\n}\nconst shiftSpecialCharMap = {\n 1: '!',\n 2: '@',\n 3: '#',\n 4: '$',\n 5: '%',\n 6: '^',\n 7: '&',\n 8: '*',\n 9: '(',\n 0: ')',\n Minus: '_',\n Equal: '+',\n BracketLeft: '{',\n BracketRight: '}',\n Backslash: '|',\n Semicolon: ':',\n Quote: '\"',\n Comma: '<',\n Period: '>',\n Slash: '?',\n Backquote: '~'\n}\n\n// handles keyboard shortcut events\nconst shortcutListener = (e, shortcuts) => {\n // search for matching shortcut from cached shortcut configs\n const shortcut = shortcuts.find(shortcut => {\n let matchesKey = false\n if (e.altKey && !e.shiftKey) {\n // mac adjusts the key value if altKey is pressed\n matchesKey = 'Key' + shortcut.key.toUpperCase() === e.code ||\n 'Digit' + shortcut.key.toUpperCase() === e.code ||\n shortcut.key === e.key ||\n specialCharMap[e.code] === shortcut.key\n } else if (e.shiftKey) {\n // check shift special character map\n const code = e.code.replace(/Key|Digit/, '')\n matchesKey = (shiftSpecialCharMap[code] || shiftSpecialCharMap[e.key]) &&\n (shiftSpecialCharMap[code] === shortcut.key || shiftSpecialCharMap[e.key] === shortcut.key)\n } else {\n matchesKey = shortcut.key.toUpperCase() === e.key.toUpperCase()\n }\n if (!matchesKey) return false\n\n let matchesModifier\n if (shortcut.modifier) {\n if (shortcut.modifier === shortcut.defaultModifier) matchesModifier = shortcut.os === 'windows' || shortcut.os === 'linux' ? e.ctrlKey : e.metaKey\n if (shortcut.modifier === 'meta') matchesModifier = e.metaKey\n if (shortcut.modifier === 'alt') matchesModifier = e.altKey\n if (shortcut.modifier === 'ctrl') matchesModifier = e.ctrlKey\n }\n return matchesModifier\n })\n\n if (shortcut) {\n e.preventDefault()\n shortcut.input.focus()\n }\n}\n\nconst createKeyboardShortcut = (input, shortcuts) => {\n const os = getOS()\n // this is the custom keyword for meta on linux/mac, ctrl on windows\n const defaultModifier = 'metactrl'\n\n // get focus key value\n let focusKey = input.getAttribute('data-focus-key')\n if (focusKey.length > 1) {\n console.error(`Provided focus key \"${focusKey}\" is more than one character. Using first character only.`)\n focusKey = focusKey.toString()[0]\n }\n\n // get focus modifier value\n let modifierSymbol\n let modifierKey = defaultModifier\n const modifierAttr = {\n default: input.getAttribute('data-focus-modifier') || defaultModifier,\n linux: input.getAttribute('data-focus-modifier-linux'),\n mac: input.getAttribute('data-focus-modifier-mac'),\n windows: input.getAttribute('data-focus-modifier-win')\n }\n if (os && modifierAttr[os]) {\n // a specific modifier key has been set by the user\n modifierKey = modifierAttr[os]\n } else {\n modifierKey = modifierAttr.default\n }\n\n // validate passed in modifier\n const recognizedModifiers = ['ctrl', 'alt', 'opt', 'meta', 'cmd', defaultModifier]\n if (!recognizedModifiers.includes(modifierKey)) {\n console.error(`Received an unrecognized modifier, \"${modifierKey},\" defaulting to \"${defaultModifier}.\"`, input)\n modifierKey = defaultModifier\n }\n\n // retrieve modifier symbol\n if (['alt', 'opt'].includes(modifierKey)) {\n modifierSymbol = os === 'mac' ? '⌥' : '⎇'\n } else if (['meta', 'win', 'cmd'].includes(modifierKey) || (modifierKey === defaultModifier && os === 'mac')) {\n if (os === 'mac') {\n modifierSymbol = '⌘'\n } else if (os === 'linux') {\n modifierSymbol = '◆'\n } else {\n modifierSymbol = '⊞'\n }\n } else if (modifierKey === 'ctrl' || (modifierKey === defaultModifier && (os === 'windows' || os === 'linux'))) {\n if (os === 'mac') {\n modifierSymbol = '⌃'\n } else {\n modifierSymbol = 'Ctrl'\n }\n }\n\n // add the shortcut to the cached array, if not a duplicate\n if (shortcuts.some(shortcut => shortcut.key === focusKey && shortcut.modifier === modifierKey)) {\n console.error(`Duplicate keyboard shortcut \"${modifierKey} + ${focusKey}\" detected. Only the first input will be focusable using this keyboard shortcut.`, input)\n }\n\n // set the shortcut indicator/title\n if (input.nodeName === 'TEXTAREA' || input.type === 'text' || input.type === 'number') {\n // create focus indicator for valid inputs\n const indicator = document.createElement('span')\n indicator.classList.add('focus-key')\n indicator.innerHTML = `<kbd>${modifierSymbol} ${focusKey.toUpperCase()}</kbd>`\n\n const label = input.nextSibling\n insertAfter(indicator, label)\n } else {\n // update the input title\n if (input.getAttribute('title')) {\n input.setAttribute('title', input.getAttribute('title') + ` (${modifierSymbol} + ${focusKey})`)\n } else {\n input.setAttribute('title', `Focus with ${modifierSymbol} + ${focusKey}`)\n }\n }\n\n return {\n key: focusKey,\n modifier: modifierKey,\n input,\n os,\n defaultModifier\n }\n}\n\nmodule.exports = {\n shortcutListener,\n createKeyboardShortcut\n}\n","const { createKeyboardShortcut, shortcutListener } = require('./lib/keyboardShortcuts.js')\nconst { enhanceInput, handleUndoRedo } = require('./lib/inputEnhancements.js')\n\nconst semanticForms = () => {\n // do some feature detection so none of the JS executes if the browser is too old\n if (typeof document.getElementsByClassName !== 'function' || typeof document.querySelector !== 'function' || !document.body.classList || !window.MutationObserver) {\n console.warn('semantic-forms was loaded into an unsupported browser and will not execute.')\n return\n }\n\n // custom keyboard shortcut listener\n const keyboardShortcuts = []\n document.addEventListener('keydown', (e) => shortcutListener(e, keyboardShortcuts))\n\n // progressively enhance form elements that have the semanticForms class\n const forms = document.querySelectorAll('form.semanticForms:not(.semanticFormsActive), table.semanticForms:not(.semanticFormsActive)')\n\n for (const form of forms) {\n form.classList.add('semanticFormsActive')\n if (form.classList.contains('lowFlow')) continue\n\n // update each input in the semantic form\n const inputs = Array.from(form.querySelectorAll('input, textarea, select'))\n for (const input of inputs) {\n enhanceInput(input, form)\n\n // handle keyboard shortcuts\n if (input.getAttribute('data-focus-key') !== null) {\n const shortcut = createKeyboardShortcut(input, keyboardShortcuts)\n keyboardShortcuts.push(shortcut)\n }\n }\n }\n\n // prevents multiple listeners\n document.removeEventListener('keydown', handleUndoRedo)\n document.addEventListener('keydown', handleUndoRedo)\n\n // monitor changes to the DOM and enhance new semanticForms forms that get added\n if (!window.semanticFormsObserver) {\n window.semanticFormsObserver = new window.MutationObserver(mutations => {\n let stop = false\n for (const mutation of mutations) {\n for (const node of mutation.addedNodes) {\n if (node.nodeName === 'FORM' || node?.querySelector?.('form')) {\n semanticForms()\n stop = true\n }\n }\n if (stop) break\n }\n })\n window.semanticFormsObserver.observe(document.body, { attributes: false, childList: true, characterData: false, subtree: true })\n }\n\n semanticForms.reinitialize = form => {\n form.classList.remove('semanticFormsActive')\n semanticForms()\n }\n}\n\nmodule.exports = semanticForms\n","// The module cache\nvar __webpack_module_cache__ = {};\n\n// The require function\nfunction __webpack_require__(moduleId) {\n\t// Check if module is in cache\n\tvar cachedModule = __webpack_module_cache__[moduleId];\n\tif (cachedModule !== undefined) {\n\t\treturn cachedModule.exports;\n\t}\n\t// Create a new module (and put it into the cache)\n\tvar module = __webpack_module_cache__[moduleId] = {\n\t\t// no module.id needed\n\t\t// no module.loaded needed\n\t\texports: {}\n\t};\n\n\t// Execute the module function\n\t__webpack_modules__[moduleId](module, module.exports, __webpack_require__);\n\n\t// Return the exports of the module\n\treturn module.exports;\n}\n\n","// startup\n// Load entry module and return exports\n// This entry module is referenced by other modules so it can't be inlined\nvar __webpack_exports__ = __webpack_require__(\"./semanticForms.js\");\n"],"names":["root","factory","exports","module","define","amd","this","getOS","userAgent","window","navigator","platform","os","includes","test","insertAfter","newNode","referenceNode","nextSibling","parentNode","insertBefore","appendChild","icons","passwordShow","passwordHide","helpIcon","lookups","nodeName","inputType","lastFocusedInput","lastClearFieldPressed","enhanceInput","input","form","classList","contains","id","type","getAttribute","dl","add","label","document","querySelector","replace","console","error","newLabel","createElement","className","dd","firstChild","setAttribute","innerHTML","hasAttribute","text","append","parentElement","remove","div","closest","isWrapped","newInput","class","innerText","value","replaceWith","addEventListener","e","key","shiftKey","preventDefault","requestSubmit","dt","clearBtn","title","ariaLabel","tabIndex","previousValue","focus","dispatchEvent","Event","bubbles","event","target","match","style","adjustWidth","placeholder","width","length","maxWidth","display","files","output","showBtn","setProperty","handleInput","maxRows","isNaN","Number","warn","minRows","getComputedStyle","inlinePadding","parseFloat","inlineBorderWidth","blockPadding","lineHeight","height","scrollHeight","Math","round","removeProperty","rows","min","adjustHeight","borderWidth","parseInt","getPropertyValue","shiftClearBtn","marginRight","clientHeight","handleUndoRedo","ctrlKey","metaKey","name","log","redoValue","specialCharMap","Minus","Equal","BracketLeft","BracketRight","Backslash","Semicolon","Quote","Comma","Period","Slash","Backquote","shiftSpecialCharMap","shortcutListener","shortcuts","shortcut","find","matchesKey","altKey","toUpperCase","code","matchesModifier","modifier","defaultModifier","createKeyboardShortcut","focusKey","toString","modifierSymbol","modifierKey","modifierAttr","default","linux","mac","windows","recognizedModifiers","some","indicator","semanticForms","getElementsByClassName","body","MutationObserver","keyboardShortcuts","forms","querySelectorAll","inputs","Array","from","push","removeEventListener","semanticFormsObserver","mutations","stop","mutation","node","addedNodes","observe","attributes","childList","characterData","subtree","reinitialize","__webpack_module_cache__","__webpack_require__","moduleId","cachedModule","undefined","__webpack_modules__","__webpack_exports__"],"sourceRoot":""}