aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/eval.ts58
-rw-r--r--src/index.ts32
2 files changed, 69 insertions, 21 deletions
diff --git a/src/eval.ts b/src/eval.ts
index 76eaa21..03391c2 100644
--- a/src/eval.ts
+++ b/src/eval.ts
@@ -1,46 +1,67 @@
import { Expr } from "./parser";
import { match, matchString } from "./utils/adt";
-export type Dependencies = {
+export type EvalActions = {
addClass(id: string, classes: string): Promise<void>
removeClass(id: string, classes: string): Promise<void>
delay(num: number): Promise<void>
jsEval(js: string): Promise<any>
- // loadCssx(id: string, url: string): Promise<string>
- // getVarable(name: string, def?: string): Promise<string>
- // updateVariable(id: string, varName: string, value: string): Promise<void>
+ loadCssx(id: string, url: string): Promise<string>
+ getVariable(name: string): Promise<string | undefined>
+ updateVariable(id: string, varName: string, value: string): Promise<void>
// calculate ??
}
-export const evalExpr = async (expr: Expr, deps: Dependencies): Promise<string | undefined> =>
- match<Promise<string | undefined>, Expr>(expr, {
+type EvalValue = string | undefined | void
+
+export const evalExpr = async (expr: Expr, actions: EvalActions): Promise<EvalValue> =>
+ match<Promise<EvalValue>, Expr>(expr, {
Call: async ({ name, args }) => {
- await matchString(name, {
+ return matchString<Promise<EvalValue>, string>(name, {
'add-class': async () => {
- const id = await evalExpr(args[0], deps)
- const classes = await evalExpr(args[1], deps)
+ const id = await evalExpr(args[0], actions)
+ const classes = await evalExpr(args[1], actions)
if (id && classes) {
- await deps.addClass(id, classes)
+ await actions.addClass(id, classes)
}
},
'remove-class': async () => {
- const id = await evalExpr(args[0], deps)
- const classes = await evalExpr(args[1], deps)
+ const id = await evalExpr(args[0], actions)
+ const classes = await evalExpr(args[1], actions)
if (id && classes) {
- await deps.removeClass(id, classes)
+ await actions.removeClass(id, classes)
}
},
'delay': async () => {
- const num = await evalExpr(args[0], deps)
- num && await deps.delay(parseInt(num, 10))
+ const num = await evalExpr(args[0], actions)
+ num && await actions.delay(parseInt(num, 10))
},
'js-eval': async () => {
- const js = await evalExpr(args[0], deps)
- js && await deps.jsEval(js)
+ const js = await evalExpr(args[0], actions)
+ js && await actions.jsEval(js)
+ },
+ 'load-cssx': async () => {
+ const id = await evalExpr(args[0], actions)
+ const url = await evalExpr(args[1], actions)
+ if (id && url) {
+ await actions.loadCssx(id, url)
+ }
+ },
+ 'var': async () => {
+ const varName = await evalExpr(args[0], actions)
+ const defaultValue = await evalExpr(args[1], actions)
+ return varName && (actions.getVariable(varName) ?? defaultValue)
+ },
+ 'update': async () => {
+ const id = await evalExpr(args[0], actions)
+ const varName = await evalExpr(args[1], actions)
+ const value = await evalExpr(args[2], actions)
+ if (id && varName && value) {
+ actions.updateVariable(id, varName, value)
+ }
},
_: () => Promise.reject(new Error('not supposed to be here')),
})
- return undefined
},
LiteralString: async s => s,
Identifier: async s => s,
@@ -48,3 +69,4 @@ export const evalExpr = async (expr: Expr, deps: Dependencies): Promise<string |
_: async _ => undefined,
})
+
diff --git a/src/index.ts b/src/index.ts
index 4987e65..9e9443c 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -1,4 +1,4 @@
-import { Dependencies, evalExpr } from './eval'
+import { EvalActions, evalExpr } from './eval'
import { parse } from './parser'
const UNSET_PROPERTY_VALUE = '<unset>'
@@ -33,12 +33,37 @@ const getChildrenIds = ($element: Element) => {
return value.split(/(\s*,\s*)|\s+/g).filter(Boolean)
}
-const evalDeps = (_el: Element): Dependencies => ({
+const getEvalActions = ($element: Element): 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))
+ }
+ },
})
const handleEvents = async ($element: Element) => {
@@ -50,7 +75,7 @@ const handleEvents = async ($element: Element) => {
console.log(`Triggered event: ${event}`)
const exprs = parse(handlerExpr)
for (const expr of exprs) {
- await evalExpr(expr, evalDeps($element))
+ await evalExpr(expr, getEvalActions($element))
}
}
}
@@ -73,6 +98,7 @@ const manageElement = async ($element: Element) => {
$element.appendChild($childrenRoot)
for (const id of childrenIds) {
+ // TODO: Allow adding node types other than div
const $child =
$childrenRoot.querySelector(`:scope > #${id}`) ??
Object.assign(document.createElement('div'), { id })