code refactoring
This commit is contained in:
parent
7068afd2b7
commit
a051e5a067
8
components/dist/chips.js
vendored
8
components/dist/chips.js
vendored
@ -181,7 +181,7 @@ customElements.define('sm-chips', class extends HTMLElement {
|
||||
this._value = value;
|
||||
this.assignedElements.forEach(elem => {
|
||||
if (elem.value == value) {
|
||||
elem.setAttribute('selected', 'true');
|
||||
elem.setAttribute('selected', '');
|
||||
elem.scrollIntoView({ behavior: "smooth", block: "nearest", inline: "center" });
|
||||
}
|
||||
else
|
||||
@ -213,7 +213,7 @@ customElements.define('sm-chips', class extends HTMLElement {
|
||||
this.slotChangeTimeout = setTimeout(() => {
|
||||
this.assignedElements = slot.assignedElements();
|
||||
this.assignedElements.forEach(elem => {
|
||||
if (elem.hasAttribute('selected') && elem.getAttribute('selected') === 'true') {
|
||||
if (elem.hasAttribute('selected')) {
|
||||
this._value = elem.value;
|
||||
}
|
||||
});
|
||||
@ -304,7 +304,7 @@ smChip.innerHTML = `
|
||||
:host(:focus-within) .sm-chip{
|
||||
box-shadow: 0 0 0 0.1rem var(--accent-color,teal) inset;
|
||||
}
|
||||
:host(:hover:not([selected="true"])) .sm-chip{
|
||||
:host(:hover:not([selected])) .sm-chip{
|
||||
background-color: rgba(var(--text-color,(17,17,17)), 0.06);
|
||||
}
|
||||
.sm-chip{
|
||||
@ -318,7 +318,7 @@ smChip.innerHTML = `
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
background: var(--background,inherit);
|
||||
}
|
||||
:host([selected="true"]) .sm-chip{
|
||||
:host([selected]) .sm-chip{
|
||||
background-color: var(--accent-color, teal);
|
||||
color: rgba(var(--background-color, (255,255,255)), 1);
|
||||
}
|
||||
|
||||
2
components/dist/chips.min.js
vendored
2
components/dist/chips.min.js
vendored
File diff suppressed because one or more lines are too long
23
components/dist/form.js
vendored
23
components/dist/form.js
vendored
@ -35,11 +35,6 @@ customElements.define('sm-form', class extends HTMLElement {
|
||||
this.supportedElements = 'input, sm-input, sm-textarea, sm-checkbox, tags-input, file-input, sm-switch, sm-radio';
|
||||
this.formElements = [];
|
||||
this._requiredElements = []
|
||||
this.debounce = this.debounce.bind(this);
|
||||
this._checkValidity = this._checkValidity.bind(this);
|
||||
this.handleKeydown = this.handleKeydown.bind(this);
|
||||
this.reset = this.reset.bind(this);
|
||||
this.elementsChanged = this.elementsChanged.bind(this);
|
||||
}
|
||||
static get observedAttributes() {
|
||||
return ['skip-submit'];
|
||||
@ -47,7 +42,7 @@ customElements.define('sm-form', class extends HTMLElement {
|
||||
get validity() {
|
||||
return this.isFormValid;
|
||||
}
|
||||
debounce(callback, wait) {
|
||||
debounce = (callback, wait) => {
|
||||
let timeoutId = null;
|
||||
return (...args) => {
|
||||
window.clearTimeout(timeoutId);
|
||||
@ -56,7 +51,7 @@ customElements.define('sm-form', class extends HTMLElement {
|
||||
}, wait);
|
||||
};
|
||||
}
|
||||
_checkValidity() {
|
||||
_checkValidity = () => {
|
||||
if (!this.submitButton || this._requiredElements.length === 0) return;
|
||||
this.invalidFieldsCount = 0
|
||||
this._requiredElements.forEach(([elem, isWC]) => {
|
||||
@ -72,7 +67,7 @@ customElements.define('sm-form', class extends HTMLElement {
|
||||
if (!this.skipSubmit)
|
||||
this.submitButton.disabled = !this.isFormValid;
|
||||
}
|
||||
handleKeydown(e) {
|
||||
handleKeydown = (e) => {
|
||||
if (e.key === 'Enter' && e.target.tagName.includes('INPUT')) {
|
||||
if (this.invalidFieldsCount === 0) {
|
||||
if (this.submitButton) {
|
||||
@ -96,15 +91,19 @@ customElements.define('sm-form', class extends HTMLElement {
|
||||
duration: 300,
|
||||
easing: 'ease'
|
||||
});
|
||||
if (isWC) elem.focusIn();
|
||||
else elem.focus();
|
||||
if (isWC) {
|
||||
elem.focusIn();
|
||||
if (elem.tagName === 'SM-INPUT' && elem.value.trim() === '') {
|
||||
elem.showError()
|
||||
}
|
||||
} else elem.focus();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
reset() {
|
||||
reset = () => {
|
||||
this.formElements.forEach(([elem, isWC]) => {
|
||||
if (isWC) elem.reset();
|
||||
else {
|
||||
@ -121,7 +120,7 @@ customElements.define('sm-form', class extends HTMLElement {
|
||||
});
|
||||
this._checkValidity();
|
||||
}
|
||||
elementsChanged() {
|
||||
elementsChanged = () => {
|
||||
this.formElements = [...this.querySelectorAll(this.supportedElements)].map(elem => {
|
||||
return [elem, elem.tagName.includes('-')];
|
||||
});
|
||||
|
||||
2
components/dist/form.min.js
vendored
2
components/dist/form.min.js
vendored
@ -1 +1 @@
|
||||
const smForm = document.createElement("template"); smForm.innerHTML = '\n <style>\n *{\n padding: 0;\n margin: 0;\n box-sizing: border-box;\n }\n :host{\n display: grid;\n width: 100%;\n }\n form{\n display: inherit;\n gap: var(--gap, 1.5rem);\n width: 100%;\n }\n </style>\n <form part="form" onsubmit="return false">\n <slot></slot>\n </form>\n ', customElements.define("sm-form", class extends HTMLElement { constructor() { super(), this.attachShadow({ mode: "open" }).append(smForm.content.cloneNode(!0)), this.form = this.shadowRoot.querySelector("form"), this.invalidFieldsCount, this.skipSubmit = !1, this.isFormValid = void 0, this.supportedElements = "input, sm-input, sm-textarea, sm-checkbox, tags-input, file-input, sm-switch, sm-radio", this.formElements = [], this._requiredElements = [], this.debounce = this.debounce.bind(this), this._checkValidity = this._checkValidity.bind(this), this.handleKeydown = this.handleKeydown.bind(this), this.reset = this.reset.bind(this), this.elementsChanged = this.elementsChanged.bind(this) } static get observedAttributes() { return ["skip-submit"] } get validity() { return this.isFormValid } debounce(e, t) { let i = null; return (...s) => { window.clearTimeout(i), i = window.setTimeout((() => { e.apply(null, s) }), t) } } _checkValidity() { this.submitButton && 0 !== this._requiredElements.length && (this.invalidFieldsCount = 0, this._requiredElements.forEach((([e, t]) => { (!e.disabled && t && !e.isValid || !t && !e.checkValidity()) && this.invalidFieldsCount++ })), this.isFormValid !== (0 === this.invalidFieldsCount) && (this.isFormValid = 0 === this.invalidFieldsCount, this.dispatchEvent(new CustomEvent(this.isFormValid ? "valid" : "invalid", { bubbles: !0, composed: !0 })), this.skipSubmit || (this.submitButton.disabled = !this.isFormValid))) } handleKeydown(e) { if ("Enter" === e.key && e.target.tagName.includes("INPUT")) if (0 === this.invalidFieldsCount) this.submitButton && this.submitButton.click(), this.dispatchEvent(new CustomEvent("submit", { bubbles: !0, composed: !0 })); else for (const [e, t] of this._requiredElements) { if (t ? !e.isValid : !e.checkValidity()) { (e?.shadowRoot?.lastElementChild || e).animate([{ transform: "translateX(-1rem)" }, { transform: "translateX(1rem)" }, { transform: "translateX(-0.5rem)" }, { transform: "translateX(0.5rem)" }, { transform: "translateX(0)" }], { duration: 300, easing: "ease" }), t ? e.focusIn() : e.focus(); break } } } reset() { this.formElements.forEach((([e, t]) => { if (t) e.reset(); else switch (e.type) { case "checkbox": case "radio": e.checked = !1; break; default: e.value = "" } })), this._checkValidity() } elementsChanged() { this.formElements = [...this.querySelectorAll(this.supportedElements)].map((e => [e, e.tagName.includes("-")])), this._requiredElements = this.formElements.filter((([e]) => e.hasAttribute("required"))), this.submitButton = this.querySelector('[variant="primary"], [type="submit"]'), this.resetButton = this.querySelector('[type="reset"]'), this.resetButton && this.resetButton.addEventListener("click", this.reset), this._checkValidity() } connectedCallback() { const e = this.debounce(this.elementsChanged, 100); this.addEventListener("input", this.debounce(this._checkValidity, 100)), this.addEventListener("keydown", this.debounce(this.handleKeydown, 100)), this.shadowRoot.querySelector("slot").addEventListener("slotchange", e), this.mutationObserver = new MutationObserver((t => { t.forEach((t => { ("childList" === t.type && [...t.addedNodes].some((e => 1 === e.nodeType && e.querySelector(this.supportedElements))) || [...t.removedNodes].some((e => 1 === e.nodeType && e.querySelector(this.supportedElements)))) && e() })) })), this.mutationObserver.observe(this, { childList: !0, subtree: !0 }) } attributeChangedCallback(e, t, i) { "skip-submit" === e && (this.skipSubmit = null !== i) } disconnectedCallback() { this.removeEventListener("input", this.debounce(this._checkValidity, 100)), this.removeEventListener("keydown", this.debounce(this.handleKeydown, 100)), this.mutationObserver.disconnect() } });
|
||||
const smForm=document.createElement("template");smForm.innerHTML='\n <style>\n *{\n padding: 0;\n margin: 0;\n box-sizing: border-box;\n }\n :host{\n display: grid;\n width: 100%;\n }\n form{\n display: inherit;\n gap: var(--gap, 1.5rem);\n width: 100%;\n }\n </style>\n <form part="form" onsubmit="return false">\n <slot></slot>\n </form>\n ',customElements.define("sm-form",class extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"}).append(smForm.content.cloneNode(!0)),this.form=this.shadowRoot.querySelector("form"),this.invalidFieldsCount,this.skipSubmit=!1,this.isFormValid=void 0,this.supportedElements="input, sm-input, sm-textarea, sm-checkbox, tags-input, file-input, sm-switch, sm-radio",this.formElements=[],this._requiredElements=[]}static get observedAttributes(){return["skip-submit"]}get validity(){return this.isFormValid}debounce=(callback,wait)=>{let timeoutId=null;return(...args)=>{window.clearTimeout(timeoutId),timeoutId=window.setTimeout((()=>{callback.apply(null,args)}),wait)}};_checkValidity=()=>{this.submitButton&&0!==this._requiredElements.length&&(this.invalidFieldsCount=0,this._requiredElements.forEach((([elem,isWC])=>{(!elem.disabled&&isWC&&!elem.isValid||!isWC&&!elem.checkValidity())&&this.invalidFieldsCount++})),this.isFormValid!==(0===this.invalidFieldsCount)&&(this.isFormValid=0===this.invalidFieldsCount,this.dispatchEvent(new CustomEvent(this.isFormValid?"valid":"invalid",{bubbles:!0,composed:!0})),this.skipSubmit||(this.submitButton.disabled=!this.isFormValid)))};handleKeydown=e=>{if("Enter"===e.key&&e.target.tagName.includes("INPUT"))if(0===this.invalidFieldsCount)this.submitButton&&this.submitButton.click(),this.dispatchEvent(new CustomEvent("submit",{bubbles:!0,composed:!0}));else for(const[elem,isWC]of this._requiredElements){if(isWC?!elem.isValid:!elem.checkValidity()){(elem?.shadowRoot?.lastElementChild||elem).animate([{transform:"translateX(-1rem)"},{transform:"translateX(1rem)"},{transform:"translateX(-0.5rem)"},{transform:"translateX(0.5rem)"},{transform:"translateX(0)"}],{duration:300,easing:"ease"}),isWC?(elem.focusIn(),"SM-INPUT"===elem.tagName&&""===elem.value.trim()&&elem.showError()):elem.focus();break}}};reset=()=>{this.formElements.forEach((([elem,isWC])=>{if(isWC)elem.reset();else switch(elem.type){case"checkbox":case"radio":elem.checked=!1;break;default:elem.value=""}})),this._checkValidity()};elementsChanged=()=>{this.formElements=[...this.querySelectorAll(this.supportedElements)].map((elem=>[elem,elem.tagName.includes("-")])),this._requiredElements=this.formElements.filter((([elem])=>elem.hasAttribute("required"))),this.submitButton=this.querySelector('[variant="primary"], [type="submit"]'),this.resetButton=this.querySelector('[type="reset"]'),this.resetButton&&this.resetButton.addEventListener("click",this.reset),this._checkValidity()};connectedCallback(){const updateFormDecedents=this.debounce(this.elementsChanged,100);this.addEventListener("input",this.debounce(this._checkValidity,100)),this.addEventListener("keydown",this.debounce(this.handleKeydown,100)),this.shadowRoot.querySelector("slot").addEventListener("slotchange",updateFormDecedents),this.mutationObserver=new MutationObserver((mutations=>{mutations.forEach((mutation=>{("childList"===mutation.type&&[...mutation.addedNodes].some((node=>1===node.nodeType&&node.querySelector(this.supportedElements)))||[...mutation.removedNodes].some((node=>1===node.nodeType&&node.querySelector(this.supportedElements))))&&updateFormDecedents()}))})),this.mutationObserver.observe(this,{childList:!0,subtree:!0})}attributeChangedCallback(name,oldValue,newValue){"skip-submit"===name&&(this.skipSubmit=null!==newValue)}disconnectedCallback(){this.removeEventListener("input",this.debounce(this._checkValidity,100)),this.removeEventListener("keydown",this.debounce(this.handleKeydown,100)),this.mutationObserver.disconnect()}});
|
||||
16
components/dist/select.js
vendored
16
components/dist/select.js
vendored
@ -188,7 +188,7 @@ customElements.define('sm-select', class extends HTMLElement {
|
||||
|
||||
reset(fire = true) {
|
||||
if (this.availableOptions[0] && this.previousOption !== this.availableOptions[0]) {
|
||||
const selectedOption = this.availableOptions.find(option => option.hasAttribute('selected') && option.getAttribute('selected') === 'true') || this.availableOptions[0];
|
||||
const selectedOption = this.availableOptions.find(option => option.hasAttribute('selected')) || this.availableOptions[0];
|
||||
this.value = selectedOption.getAttribute('value')
|
||||
if (fire) {
|
||||
this.fireEvent()
|
||||
@ -197,9 +197,9 @@ customElements.define('sm-select', class extends HTMLElement {
|
||||
}
|
||||
selectOption(selectedOption) {
|
||||
if (this.previousOption !== selectedOption) {
|
||||
this.querySelectorAll('[selected="true"]').forEach(option => option.removeAttribute('selected'))
|
||||
this.querySelectorAll('[selected').forEach(option => option.removeAttribute('selected'))
|
||||
this.selectedOptionText.textContent = `${this.label}${selectedOption.textContent}`;
|
||||
selectedOption.setAttribute('selected', 'true')
|
||||
selectedOption.setAttribute('selected', '')
|
||||
this.previousOption = selectedOption
|
||||
}
|
||||
}
|
||||
@ -229,7 +229,7 @@ customElements.define('sm-select', class extends HTMLElement {
|
||||
], this.animationOptions)
|
||||
this.setAttribute('open', '');
|
||||
this.style.zIndex = 1000;
|
||||
(this.availableOptions.find(option => option.hasAttribute('selected') && option.getAttribute('selected') === 'true') || this.availableOptions[0]).focus()
|
||||
(this.availableOptions.find(option => option.hasAttribute('selected')) || this.availableOptions[0]).focus()
|
||||
document.addEventListener('mousedown', this.handleClickOutside)
|
||||
this.isOpen = true
|
||||
}
|
||||
@ -307,7 +307,7 @@ customElements.define('sm-select', class extends HTMLElement {
|
||||
if (e.target === this) {
|
||||
if (this.isOpen && e.key === 'ArrowDown') {
|
||||
e.preventDefault();
|
||||
(this.availableOptions.find(option => option.hasAttribute('selected') && option.getAttribute('selected') === 'true') || this.availableOptions[0]).focus()
|
||||
(this.availableOptions.find(option => option.hasAttribute('selected')) || this.availableOptions[0]).focus()
|
||||
this.handleOptionSelection(e)
|
||||
} else if (e.key === ' ') {
|
||||
e.preventDefault()
|
||||
@ -355,7 +355,7 @@ customElements.define('sm-select', class extends HTMLElement {
|
||||
}
|
||||
});
|
||||
if (attributesChanged) {
|
||||
const selectedOption = this.availableOptions.find(option => option.hasAttribute('selected') && option.getAttribute('selected') === 'true') || this.availableOptions[0];
|
||||
const selectedOption = this.availableOptions.find(option => option.hasAttribute('selected')) || this.availableOptions[0];
|
||||
this.selectedOptionText.textContent = `${this.label}${selectedOption.textContent}`;
|
||||
this.setAttribute('value', selectedOption.getAttribute('value'));
|
||||
}
|
||||
@ -444,7 +444,7 @@ smOption.innerHTML = `
|
||||
:host(:focus) .option::before{
|
||||
opacity: 1
|
||||
}
|
||||
:host([selected="true"]) .option::before{
|
||||
:host([selected]) .option::before{
|
||||
opacity: 1;
|
||||
background: var(--accent-color, teal);
|
||||
}
|
||||
@ -452,7 +452,7 @@ smOption.innerHTML = `
|
||||
.option:hover{
|
||||
background: rgba(var(--text-color,(17,17,17)), 0.1);
|
||||
}
|
||||
:host(:not([selected="true"]):hover) .option::before{
|
||||
:host(:not([selected]):hover) .option::before{
|
||||
opacity: 1
|
||||
}
|
||||
}
|
||||
|
||||
2
components/dist/select.min.js
vendored
2
components/dist/select.min.js
vendored
File diff suppressed because one or more lines are too long
@ -36,22 +36,69 @@
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<sm-notifications id="notification_drawer"></sm-notifications>
|
||||
<button onclick="pushNotification()">
|
||||
Send Notification
|
||||
</button>
|
||||
<sm-form>
|
||||
<sm-input placeholder="fafh" value="" animate required>
|
||||
<sm-button slot="right" type="submit">Submit</sm-button>
|
||||
</sm-input>
|
||||
<button type="submit">Submit</button>
|
||||
</sm-form>
|
||||
</body>
|
||||
<script>
|
||||
function pushNotification() {
|
||||
document.getElementById('notification_drawer').push(`<h4>This is a notification.</h4><p>d snfkjsdn sdf sdfsd</p>`, {
|
||||
timeout: 10000,
|
||||
action: {
|
||||
label: 'click me',
|
||||
callback: () => {
|
||||
console.log('clicked')
|
||||
document.querySelector('sm-input').isValid
|
||||
let currentSubscriber = null;
|
||||
/**
|
||||
* @param {any} initialValue - initial value for the signal
|
||||
* @returns {array} - array containing getter and setter for the signal
|
||||
* @example
|
||||
* const [getCount, setCount] = $signal(0);
|
||||
*/
|
||||
function $signal(initialValue) {
|
||||
let value = initialValue;
|
||||
const subscribers = new Set();
|
||||
|
||||
function getter() {
|
||||
if (currentSubscriber) {
|
||||
const weakRef = new WeakRef({ func: currentSubscriber });
|
||||
subscribers.add(weakRef);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
function setter(newValue) {
|
||||
if (newValue !== value) {
|
||||
value = newValue;
|
||||
for (const subscriber of subscribers) {
|
||||
const ref = subscriber.deref();
|
||||
if (ref) {
|
||||
ref.func();
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
return [getter, setter];
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param {function} fn - function that will run if any of its dependent signals change
|
||||
* @example
|
||||
* $effect(() => {
|
||||
* console.log(count());
|
||||
* }
|
||||
* @returns {void}
|
||||
*/
|
||||
async function $effect(fn) {
|
||||
currentSubscriber = fn;
|
||||
const result = fn();
|
||||
try {
|
||||
if (result instanceof Promise) {
|
||||
await result;
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
} finally {
|
||||
currentSubscriber = null;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
1
components/test.min.html
Normal file
1
components/test.min.html
Normal file
@ -0,0 +1 @@
|
||||
<!DOCTYPE html><html lang=en><head><meta charset=UTF-8><meta http-equiv=X-UA-Compatible content="IE=edge"><meta name=viewport content="width=device-width,initial-scale=1"><title>Document</title><script src=dist/select.js></script><script src=dist/form.js></script><script src=dist/popup.js></script><script src=dist/switch.js></script><script src=dist/checkbox.js></script><script src=dist/radio.js></script><script src=dist/input.js></script><script src=dist/textarea.js></script><script src=dist/text-field.js></script><script src=dist/button.js></script><script src=dist/menu.js></script><script src=dist/cube-loader.js></script><script src=dist/tags-input.js></script><script src=dist/strip-select.js></script><script src=dist/collapsed-text.js></script><script src=dist/notifications.js></script><link rel=stylesheet href=css/main.min.css><style>div{display:flex;padding:4vmax}body{overflow:auto}</style></head><body><sm-form><sm-input placeholder=fafh value="" animate required><sm-button slot=right type=submit>Submit</sm-button></sm-input><button type=submit>Submit</button></sm-form></body><script>document.querySelector("sm-input").isValid;let currentSubscriber=null;function $signal(r){let c=r;const t=new Set;return[function(){var r;return currentSubscriber&&(r=new WeakRef({func:currentSubscriber}),t.add(r)),c},function(r){if(r!==c){c=r;for(const n of t){var e=n.deref();e&&e.func()}}}]}async function $effect(r){r=(currentSubscriber=r)();try{r instanceof Promise&&await r}catch(r){console.error(r)}finally{currentSubscriber=null}}</script></html>
|
||||
Loading…
Reference in New Issue
Block a user