diff --git a/ui/_/code/quill.js b/ui/_/code/quill.js index 1c3c315..39ac364 100644 --- a/ui/_/code/quill.js +++ b/ui/_/code/quill.js @@ -1,6 +1,7 @@ /* Sam Russell Captured Sun + 12.26.25 - State for arrays, nested objects. State for stacks (Shadow-only) 12.17.25 - [Hyperia] - adding width, height functions. adding "e" to onClick. adding the non-window $$ funcs. 12.16.25 - [comalyr] - State 11.25.25.1 - Added minHeight and minWidth to be counted as numerical styles @@ -228,25 +229,58 @@ window.register = (el, tagname) => { window[el.prototype.constructor.name] = function (...params) { let instance = new el(...params) if(instance.state) { - let proxy = new Proxy(instance.state, { - get(target, prop, receiver) { - if (typeof prop === "symbol") { // Ignore internal / symbol accesses - return Reflect.get(target, prop, receiver); - } + const proxyCache = new WeakMap(); - quill.lastLastState = quill.lastState - quill.lastState = prop; - return Reflect.get(target, prop, receiver); - }, - set(target, prop, value, receiver) { - const oldValue = target[prop]; - if (oldValue === value) return true; + function reactive(value, path=[]) { + if (value && typeof value === "object") { + if (proxyCache.has(value)) return proxyCache.get(value); - const result = Reflect.set(target, prop, value, receiver); - instance.stateWatchers[prop].forEach((cb) => cb()) - return result; + const p = new Proxy(value, createHandlers(path)); + proxyCache.set(value, p); + return p; } - }); + return value; + } + + function isNumericKey(prop) { + return typeof prop === "string" && prop !== "" && String(+prop) === prop; + } + + function createHandlers(path) { + return { + get(target, prop, receiver) { + if (typeof prop === "symbol") { + return Reflect.get(target, prop, receiver); + } + + let nextPath = (Array.isArray(target) && !isNumericKey(prop)) ? path : path.concat(prop) // To filter out arr.length, arr.map, arr.forEach, etc. + quill.lastState = nextPath.join("."); + + const v = Reflect.get(target, prop, receiver); + return reactive(v, nextPath); + }, + + set(target, prop, value, receiver) { + const oldLength = Array.isArray(target) ? target.length : undefined; + const oldValue = target[prop]; + if (oldValue === value) return true; + + const result = Reflect.set(target, prop, value, receiver); + + let changedPath = (Array.isArray(target) && (!isNumericKey(prop) || target.length !== oldLength)) ? path : path.concat(prop).join("."); // To filter out arr.length, arr.map, arr.forEach, and also a push/pop/unshift. + const watchers = instance.stateWatchers[changedPath]; + + if (watchers) { + watchers.forEach(cb => cb()); + } + + return result; + } + }; + } + + let proxy = reactive(instance.state) + Object.defineProperty(instance, "state", { value: proxy, writable: false, @@ -520,12 +554,6 @@ HTMLElement.prototype.fontSize = StyleFunction(function(value, unit = "px") { return this }) -function checkPositionType(el) { - let computed = window.getComputedStyle(el).position - if(!(computed === "absolute" || computed === "fixed")) { - el.style.position = "absolute" - } -} HTMLElement.prototype.width = function(value, unit = "px") { if ((typeof value !== 'number' && value !== "auto") || Number.isNaN(value)) @@ -547,6 +575,13 @@ HTMLElement.prototype.height = function(value, unit = "px") { return this } +function checkPositionType(el) { + let computed = window.getComputedStyle(el).position + if(!(computed === "absolute" || computed === "fixed")) { + el.style.position = "absolute" + } +} + HTMLElement.prototype.x = function(value, unit = "px") { if (typeof value !== 'number' || isNaN(value)) throw new Error(`Invalid value: ${value}. Expected a number.`); @@ -788,61 +823,47 @@ window.textarea = function(placeholder = "") { /* STACKS */ -window.VStack = function (cb = () => {}) { - let styles = ` - display: flex; - flex-direction: column; - ` +handleStack = function(cb, name, styles="") { let nowRendering = quill.rendering[quill.rendering.length-1] if (nowRendering.innerHTML.trim() === "" && !quill.isStack(nowRendering)) { nowRendering.style.cssText += styles - nowRendering.classList.add("VStack") + nowRendering.classList.add(name) cb() + if(quill.lastState) { + nowRendering.addStateWatcher(quill.lastState, () => { + nowRendering.innerHTML = "" + cb() + }) + } return nowRendering + } else { + let div = document.createElement("div") + div.classList.add(name) + div.style.cssText += styles + div.render = cb + quill.render(div) + return div } +} - let div = document.createElement("div") - div.classList.add("VStack") - div.style.cssText += styles - div.render = cb - quill.render(div) - return div +window.VStack = function (cb = () => {}) { + let styles = ` + display: flex; + flex-direction: column; + ` + return handleStack(cb, "VStack", styles) } window.HStack = function (cb = () => {}) { let styles = ` - display: flex; - flex-direction: row; + display: flex; + flex-direction: row; `; - let nowRendering = quill.rendering[quill.rendering.length - 1]; - if (nowRendering.innerHTML.trim() === "" && !quill.isStack(nowRendering)) { - nowRendering.style.cssText += styles; - nowRendering.classList.add("HStack") - cb(); - return nowRendering; - } - - let div = document.createElement("div"); - div.classList.add("HStack"); - div.style.cssText += styles; - div.render = cb; - quill.render(div); - return div; + return handleStack(cb, "HStack", styles) }; window.ZStack = function (cb = () => {}) { - let nowRendering = quill.rendering[quill.rendering.length - 1]; - if (nowRendering.innerHTML.trim() === "" && !quill.isStack(nowRendering)) { - nowRendering.classList.add("ZStack") - cb(); - return nowRendering; - } - - let div = document.createElement("div"); - div.classList.add("ZStack"); - div.render = cb; - quill.render(div); - return div; + return handleStack(cb, "ZStack") }; /* SHAPES */