aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--TODO.norg20
-rw-r--r--examples/todo-list/style.css27
-rw-r--r--src/index.ts53
3 files changed, 66 insertions, 34 deletions
diff --git a/TODO.norg b/TODO.norg
index bac7d16..59a664f 100644
--- a/TODO.norg
+++ b/TODO.norg
@@ -1,4 +1,4 @@
-* Tasks
+* Now
- (x) Hydrate existing elements instead of re-creating
- (x) `load-cssx` functions
- (x) `get-variable`
@@ -18,15 +18,27 @@
- (x) More complex selector support for cssx-children
- (x) `add-element` & `remove-element`
- (x) conditionals
+ - (x) on update
- ( ) children of instance must also be instantiated
- - ( ) figure out how to manage element on change of css variables
- - ( ) access an instance of component
+ - ( ) access child from an instance (update checkbox)
+ - ( ) access instance from child (delete task)
+ - ( ) filter for on update on specific properties
+ - ( ) eval
+ - ( ) update property on child on update of parent
+ - ( ) functions/lazy properties?
- ( ) string concatenation
- ( ) `request` error handling
- ( ) keyboard events
- ( ) Code cleanup
+
+* Later
+ - ( ) `add-class` & `remove-class` should use self if id is not specified?
- ( ) Evaluate `calc`
+ - ( ) access an instance of component
- ( ) Additional events
- ( ) Improve error messages
- - ( ) `add-class` & `remove-class` should use self if id is not specified?
+
+* Maybe
- ( ) `list` & `tuple` data structures?
+ - ( ) server-side css? Why the fuck not!?
+
diff --git a/examples/todo-list/style.css b/examples/todo-list/style.css
index b746829..b3b9d07 100644
--- a/examples/todo-list/style.css
+++ b/examples/todo-list/style.css
@@ -8,6 +8,8 @@
--cssx-children: main#container;
}
+body * { box-sizing: border-box; }
+
#container {
max-width: 600px;
margin: 2rem auto;
@@ -75,32 +77,36 @@
--cssx-text: '+';
}
-
[data-instance=task-item] {
--text: "default text";
--done: "false";
padding: 1rem;
cursor: pointer;
+ display: flex;
+ width: 100%;
+ align-items: center;
--cssx-on-click: update(--done, if(get-var(--done), "false", "true"));
- --cssx-on-update:
- update(checkbox, --checked, if(get-var(--done), true, false))
- ;
+ --cssx-on-update: update(checkbox, --checked, if(get-var(--done), true, false));
- --cssx-children: div#checkbox;
+ --cssx-children: div#checkbox div#task-text button#delete-task;
}
-[data-instance=task-item]::after {
+
+[data-instance=task-item] [data-element=task-text] {
+ flex: 2;
+}
+[data-instance=task-item] [data-element=task-text]::after {
content: "[" var(--done) "] " var(--text);
+ padding-left: 0.8rem;
}
[data-instance=task-item]:not(:first-child) {
content: "";
- display: block;
border-top: 1px solid var(--color-gray);
}
-#checkbox {
+[data-instance=task-item] [data-element=checkbox] {
--checked: false;
width: 18px;
@@ -112,3 +118,8 @@
update(background-color, if(get-var(--checked), get-var(--color-accent), transparent))
;
}
+
+[data-instance=task-item] [data-element=delete-task] {
+ --cssx-text: 'Delete';
+ --cssx-on-click: remove-element(task-item);
+}
diff --git a/src/index.ts b/src/index.ts
index aba1491..c1b997d 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -19,11 +19,13 @@ const EVENT_HANDLERS = {
[CSSX_ON_UPDATE_EVENT]: '--cssx-on-update',
}
-const PROPERTIES = [
- '--cssx-children',
- '--cssx-text',
- '--cssx-disgustingly-set-innerhtml',
-]
+const LAYER_CLASS_NAME = 'cssx-layer'
+
+const PROPERTIES = {
+ CHILDREN: '--cssx-children',
+ TEXT: '--cssx-text',
+ HTML: '--cssx-disgustingly-set-innerhtml',
+}
export const injectStyles = () => {
const STYLE_TAG_CLASS = 'cssx-style-root'
@@ -32,33 +34,38 @@ export const injectStyles = () => {
const $style = document.createElement('style')
$style.className = STYLE_TAG_CLASS
- const properties = [...PROPERTIES, ...Object.values(EVENT_HANDLERS)]
+ const properties = [
+ ...Object.values(PROPERTIES),
+ ...Object.values(EVENT_HANDLERS),
+ ]
$style.textContent = `.cssx-layer {
${properties.map(p => `${p}: ${UNSET_PROPERTY_VALUE};`).join(' ')}
display: inherit;
width: inherit;
height: inherit;
+ align-items: inherit;
+ justify-content: inherit;
}`
document.body.appendChild($style)
}
-export const getPropertyValue = ($element: Element, prop: string) => {
+export const getPropertyValue = ($element: HTMLElement, prop: string) => {
const value = `${getComputedStyle($element).getPropertyValue(prop)}`.trim()
return !value || value === UNSET_PROPERTY_VALUE ? '' : value
}
export const getDeclarations = (
- $element: Element,
+ $element: HTMLElement,
actions: EvalActions,
): Promise<Array<DeclarationEval>> => {
- const value = getPropertyValue($element, '--cssx-children')
+ const value = getPropertyValue($element, PROPERTIES.CHILDREN)
return extractDeclaration(value, actions)
}
const getEvalActions = (
- $element: Element,
+ $element: HTMLElement,
{ event = null, pure = false }: { event?: any; pure?: boolean },
): EvalActions => {
const actions: EvalActions = {
@@ -145,7 +152,7 @@ const getEvalActions = (
}
export const handleEvents = async (
- $element: Element,
+ $element: HTMLElement,
isNewElement: boolean = false,
) => {
for (const [eventType, property] of Object.entries(EVENT_HANDLERS)) {
@@ -179,15 +186,16 @@ export const handleEvents = async (
const declarationToElement = (
declaration: DeclarationEval,
- $parent?: Element,
-) => {
+ $parent?: HTMLElement,
+): { node: HTMLElement; isNewElement: boolean } => {
const { tag, id, selectors } = declaration.selector
const tagName = tag || 'div'
- let $child = $parent?.querySelector(`:scope > #${id}`)
+ let $child = $parent?.querySelector<HTMLElement>(`:scope > #${id}`)
const isNewElement = !$child
if (!$child) {
$child = Object.assign(document.createElement(tagName), { id })
+ $child.dataset.element = id
}
// Add selectors
@@ -200,7 +208,7 @@ const declarationToElement = (
}
for (const [key, value] of declaration.properties) {
- ;($child as HTMLElement)?.style.setProperty(key, JSON.stringify(value))
+ $child?.style.setProperty(key, JSON.stringify(value))
}
return { node: $child, isNewElement }
@@ -208,12 +216,13 @@ const declarationToElement = (
const createLayer = async (
declarations: Array<DeclarationEval>,
- $parent: Element,
+ $parent: HTMLElement,
) => {
- const LAYER_CLASS = 'cssx-layer'
const $childrenRoot =
- $parent?.querySelector(`:scope > .${LAYER_CLASS}`) ??
- Object.assign(document.createElement('div'), { className: LAYER_CLASS })
+ $parent?.querySelector<HTMLElement>(`:scope > .${LAYER_CLASS_NAME}`) ??
+ Object.assign(document.createElement('div'), {
+ className: LAYER_CLASS_NAME,
+ })
if (!$childrenRoot.parentNode) $parent.appendChild($childrenRoot)
@@ -228,14 +237,14 @@ const createLayer = async (
}
export const manageElement = async (
- $element: Element,
+ $element: HTMLElement,
isNewElement: boolean = false,
) => {
await handleEvents($element, isNewElement)
const actions = getEvalActions($element, { pure: true })
- const text = getPropertyValue($element, '--cssx-text')
+ const text = getPropertyValue($element, PROPERTIES.TEXT)
if (text) {
try {
const exprs = parse(text)
@@ -246,7 +255,7 @@ export const manageElement = async (
}
}
- const html = getPropertyValue($element, '--cssx-disgustingly-set-innerhtml')
+ const html = getPropertyValue($element, PROPERTIES.HTML)
if (html) $element.innerHTML = html.replace(/(^'|")|('|"$)/g, '')
const declarations = await getDeclarations($element, actions)