diff options
| author | Akshay Nair <phenax5@gmail.com> | 2023-08-12 20:13:29 +0530 |
|---|---|---|
| committer | Akshay Nair <phenax5@gmail.com> | 2023-08-12 20:13:29 +0530 |
| commit | a61f5ec92a9382b0c25fae9a344da0d7eb21b702 (patch) | |
| tree | 42d0b265b9f4b9c3c4b2ab3ac5e2a6ffa54bcccd /src | |
| parent | 53420ee477e9cad629bd8e6804d477d6ded8c110 (diff) | |
| download | css-everything-a61f5ec92a9382b0c25fae9a344da0d7eb21b702.tar.gz css-everything-a61f5ec92a9382b0c25fae9a344da0d7eb21b702.zip | |
refactor: moves stuff around
Diffstat (limited to '')
| -rw-r--r-- | src/index.ts | 164 | ||||
| -rw-r--r-- | src/renderer.ts | 164 |
2 files changed, 164 insertions, 164 deletions
diff --git a/src/index.ts b/src/index.ts index 9ca6c4e..1c8184a 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,3 +1,163 @@ -import { render } from './renderer' +import { EvalActions, evalExpr } from './eval' +import { parse } from './parser' -render({ root: document.body }) +const UNSET_PROPERTY_VALUE = '<unset>' +const EVENT_HANDLERS = { + click: '--cssx-on-click', + load: '--cssx-on-load', + mount: '--cssx-on-mount', + submit: '--cssx-on-submit', +} + +const PROPERTIES = [ + '--cssx-children', + '--cssx-text', + '--cssx-disgustingly-set-innerhtml', +] + +export const injectStyles = () => { + const STYLE_TAG_CLASS = 'cssx-style-root' + if (document.querySelector(`.${STYLE_TAG_CLASS}`)) return + + const $style = document.createElement('style') + $style.className = STYLE_TAG_CLASS + + const properties = [...PROPERTIES, ...Object.values(EVENT_HANDLERS)] + + $style.textContent = `.cssx-layer { + ${properties.map(p => `${p}: ${UNSET_PROPERTY_VALUE};`).join(' ')} + }` + + document.body.appendChild($style) +} + +export const getPropertyValue = ($element: Element, prop: string) => { + const value = `${getComputedStyle($element).getPropertyValue(prop)}`.trim() + return !value || value === UNSET_PROPERTY_VALUE ? '' : value +} + +export const getChildrenIds = ($element: Element) => { + const value = getPropertyValue($element, '--cssx-children') + return value.split(/(\s*,\s*)|\s+/g).filter(Boolean) +} + +const getEvalActions = ($element: Element, event: any): EvalActions => ({ + addClass: async (id, cls) => document.getElementById(id)?.classList.add(cls), + removeClass: async (id, cls) => + document.getElementById(id)?.classList.remove(cls), + delay: delay => new Promise(res => setTimeout(res, delay)), + jsEval: async js => (0, eval)(js), + loadCssx: async (id, url) => + new Promise((resolve, reject) => { + const $link = Object.assign(document.createElement('link'), { + href: url, + rel: 'stylesheet', + }) + $link.onload = () => { + const $el = document.getElementById(id) + // NOTE: Maybe create and append to body if no root? + if ($el) { + manageElement($el) + resolve(id) + } else { + console.error(`[CSSX] Unable to find root for ${id}`) + reject(`[CSSX] Unable to find root for ${id}`) + } + } + document.body.appendChild($link) + }), + getVariable: async varName => getPropertyValue($element, varName), + updateVariable: async (targetId, varName, value) => { + const $el = document.getElementById(targetId) + if ($el) { + $el.style.setProperty(varName, JSON.stringify(value)) + } + }, + setAttribute: async (id, name, value) => { + const $el = id ? document.getElementById(id) : $element + if (value) { + $el?.setAttribute(name, value) + } else { + $el?.removeAttribute(name) + } + }, + getAttribute: async (id, name) => { + const $el = id ? document.getElementById(id) : $element + return $el?.getAttribute(name) ?? undefined + }, + withEvent: async fn => fn(event), + getFormData: async () => + $element.nodeName === 'FORM' + ? new FormData($element as HTMLFormElement) + : undefined, + sendRequest: async ({ url, method, data }) => { + await fetch(url, { method, body: data }) + // TODO: Handle response? + }, +}) + +export const handleEvents = async ( + $element: Element, + isNewElement: boolean = false, +) => { + for (const [eventType, property] of Object.entries(EVENT_HANDLERS)) { + const handlerExpr = getPropertyValue($element, property) + + if (handlerExpr) { + const eventHandler = async (event: any) => { + const exprs = parse(handlerExpr) + for (const expr of exprs) { + await evalExpr(expr, getEvalActions($element, event)) + } + } + + if (eventType === 'mount') { + if (isNewElement) setTimeout(eventHandler) + } else { + ;($element as any)[`on${eventType}`] = eventHandler + } + } + } +} + +export const manageElement = async ( + $element: Element, + isNewElement: boolean = false, +) => { + await handleEvents($element, isNewElement) + + const text = getPropertyValue($element, '--cssx-text') + if (text) $element.textContent = text + + const html = getPropertyValue($element, '--cssx-disgustingly-set-innerhtml') + if (html) $element.innerHTML = html.replace(/(^'|")|('|"$)/g, '') + + const childrenIds = getChildrenIds($element) + if (childrenIds.length > 0) { + const LAYER_CLASS = 'cssx-layer' + const $childrenRoot = + $element.querySelector(`:scope > .${LAYER_CLASS}`) ?? + Object.assign(document.createElement('div'), { className: LAYER_CLASS }) + $element.appendChild($childrenRoot) + + for (const childId of childrenIds) { + const selector = childId.split('#') + const [tag, id] = selector.length >= 2 ? selector : ['div', ...selector] + let $child = $childrenRoot.querySelector(`:scope > #${id}`) + const isNewElement = !$child + if (!$child) { + $child = Object.assign(document.createElement(tag || 'div'), { id }) + } + $childrenRoot.appendChild($child) + await manageElement($child, isNewElement) + } + } +} + +export interface Options { + root?: HTMLElement +} +export const render = async ({ root = document.body }: Options = {}) => { + injectStyles() + await manageElement(root) +} diff --git a/src/renderer.ts b/src/renderer.ts index 1c8184a..44add3e 100644 --- a/src/renderer.ts +++ b/src/renderer.ts @@ -1,163 +1,3 @@ -import { EvalActions, evalExpr } from './eval' -import { parse } from './parser' +import { render } from '.' -const UNSET_PROPERTY_VALUE = '<unset>' -const EVENT_HANDLERS = { - click: '--cssx-on-click', - load: '--cssx-on-load', - mount: '--cssx-on-mount', - submit: '--cssx-on-submit', -} - -const PROPERTIES = [ - '--cssx-children', - '--cssx-text', - '--cssx-disgustingly-set-innerhtml', -] - -export const injectStyles = () => { - const STYLE_TAG_CLASS = 'cssx-style-root' - if (document.querySelector(`.${STYLE_TAG_CLASS}`)) return - - const $style = document.createElement('style') - $style.className = STYLE_TAG_CLASS - - const properties = [...PROPERTIES, ...Object.values(EVENT_HANDLERS)] - - $style.textContent = `.cssx-layer { - ${properties.map(p => `${p}: ${UNSET_PROPERTY_VALUE};`).join(' ')} - }` - - document.body.appendChild($style) -} - -export const getPropertyValue = ($element: Element, prop: string) => { - const value = `${getComputedStyle($element).getPropertyValue(prop)}`.trim() - return !value || value === UNSET_PROPERTY_VALUE ? '' : value -} - -export const getChildrenIds = ($element: Element) => { - const value = getPropertyValue($element, '--cssx-children') - return value.split(/(\s*,\s*)|\s+/g).filter(Boolean) -} - -const getEvalActions = ($element: Element, event: any): EvalActions => ({ - addClass: async (id, cls) => document.getElementById(id)?.classList.add(cls), - removeClass: async (id, cls) => - document.getElementById(id)?.classList.remove(cls), - delay: delay => new Promise(res => setTimeout(res, delay)), - jsEval: async js => (0, eval)(js), - loadCssx: async (id, url) => - new Promise((resolve, reject) => { - const $link = Object.assign(document.createElement('link'), { - href: url, - rel: 'stylesheet', - }) - $link.onload = () => { - const $el = document.getElementById(id) - // NOTE: Maybe create and append to body if no root? - if ($el) { - manageElement($el) - resolve(id) - } else { - console.error(`[CSSX] Unable to find root for ${id}`) - reject(`[CSSX] Unable to find root for ${id}`) - } - } - document.body.appendChild($link) - }), - getVariable: async varName => getPropertyValue($element, varName), - updateVariable: async (targetId, varName, value) => { - const $el = document.getElementById(targetId) - if ($el) { - $el.style.setProperty(varName, JSON.stringify(value)) - } - }, - setAttribute: async (id, name, value) => { - const $el = id ? document.getElementById(id) : $element - if (value) { - $el?.setAttribute(name, value) - } else { - $el?.removeAttribute(name) - } - }, - getAttribute: async (id, name) => { - const $el = id ? document.getElementById(id) : $element - return $el?.getAttribute(name) ?? undefined - }, - withEvent: async fn => fn(event), - getFormData: async () => - $element.nodeName === 'FORM' - ? new FormData($element as HTMLFormElement) - : undefined, - sendRequest: async ({ url, method, data }) => { - await fetch(url, { method, body: data }) - // TODO: Handle response? - }, -}) - -export const handleEvents = async ( - $element: Element, - isNewElement: boolean = false, -) => { - for (const [eventType, property] of Object.entries(EVENT_HANDLERS)) { - const handlerExpr = getPropertyValue($element, property) - - if (handlerExpr) { - const eventHandler = async (event: any) => { - const exprs = parse(handlerExpr) - for (const expr of exprs) { - await evalExpr(expr, getEvalActions($element, event)) - } - } - - if (eventType === 'mount') { - if (isNewElement) setTimeout(eventHandler) - } else { - ;($element as any)[`on${eventType}`] = eventHandler - } - } - } -} - -export const manageElement = async ( - $element: Element, - isNewElement: boolean = false, -) => { - await handleEvents($element, isNewElement) - - const text = getPropertyValue($element, '--cssx-text') - if (text) $element.textContent = text - - const html = getPropertyValue($element, '--cssx-disgustingly-set-innerhtml') - if (html) $element.innerHTML = html.replace(/(^'|")|('|"$)/g, '') - - const childrenIds = getChildrenIds($element) - if (childrenIds.length > 0) { - const LAYER_CLASS = 'cssx-layer' - const $childrenRoot = - $element.querySelector(`:scope > .${LAYER_CLASS}`) ?? - Object.assign(document.createElement('div'), { className: LAYER_CLASS }) - $element.appendChild($childrenRoot) - - for (const childId of childrenIds) { - const selector = childId.split('#') - const [tag, id] = selector.length >= 2 ? selector : ['div', ...selector] - let $child = $childrenRoot.querySelector(`:scope > #${id}`) - const isNewElement = !$child - if (!$child) { - $child = Object.assign(document.createElement(tag || 'div'), { id }) - } - $childrenRoot.appendChild($child) - await manageElement($child, isNewElement) - } - } -} - -export interface Options { - root?: HTMLElement -} -export const render = async ({ root = document.body }: Options = {}) => { - injectStyles() - await manageElement(root) -} +render({ root: document.body }) |
