diff options
| author | Akshay Nair <phenax5@gmail.com> | 2023-08-25 18:58:47 +0530 |
|---|---|---|
| committer | Akshay Nair <phenax5@gmail.com> | 2023-08-25 19:00:57 +0530 |
| commit | 8058d047a5a50406ff4175c83b8488eea7c4e706 (patch) | |
| tree | 7256dcde0c396fafad9ff2ca45b9eaa33691db3b | |
| parent | ca0737e393bbf5c45f688593bbfaf41079a66784 (diff) | |
| download | css-everything-8058d047a5a50406ff4175c83b8488eea7c4e706.tar.gz css-everything-8058d047a5a50406ff4175c83b8488eea7c4e706.zip | |
docs: crazy amounts of docs
Diffstat (limited to '')
| -rw-r--r-- | README.md | 6 | ||||
| -rw-r--r-- | TODO.norg | 2 | ||||
| -rw-r--r-- | docs/README.md | 9 | ||||
| -rw-r--r-- | docs/api/functions.md | 266 | ||||
| -rw-r--r-- | docs/how-it-works.md | 130 | ||||
| -rw-r--r-- | docs/how_it_works.md | 4 | ||||
| -rw-r--r-- | docs/recipies.md | 6 | ||||
| -rw-r--r-- | examples/clock/style.css | 2 | ||||
| -rw-r--r-- | package.json | 1 | ||||
| -rw-r--r-- | src/eval.ts | 14 | ||||
| -rw-r--r-- | src/index.ts | 1 |
11 files changed, 400 insertions, 41 deletions
@@ -3,11 +3,11 @@ A ui library where you only write CSS. No HTML, no JS, no build system, only CSS > Disclaimer: Don't use this - ## Usage -### Docs -WIP. Coming soon maybe? +- [Read the documentation](https://github.com/phenax/css-everything/tree/main/docs/README.md) to become enlightened. +- [Here's how this works](https://github.com/phenax/css-everything/tree/main/docs/how-it-works.md). + ### Simple example You can start by adding the script tag for the renderer inside the body @@ -8,7 +8,7 @@ - (x) Scoped catch on try - (x) `do` expression - (x) `let` expression - - ( ) `h` declarations + - (x) `h` declarations - ( ) `has-class` - ( ) `add-class` & `remove-class` should use self if id is not specified? - ( ) Update `--cssx-text` on update diff --git a/docs/README.md b/docs/README.md index e69de29..0e2fb78 100644 --- a/docs/README.md +++ b/docs/README.md @@ -0,0 +1,9 @@ +# Documentation + +- [API/functions](./api/functions.md) +- [API/hooks](./api/hooks.md) +- [API/properties](./api/properties.md) +- [How it works?](./how-it-works.md) +- [Security](./security.md) +- [Common recipies](./recipies.md) + diff --git a/docs/api/functions.md b/docs/api/functions.md index 39f85cb..55fd701 100644 --- a/docs/api/functions.md +++ b/docs/api/functions.md @@ -5,19 +5,33 @@ type custom-property-name = `--${string}` type selector = string // Any css selector or identifier (used as id) type condition = string // empty string, 0, 'false', "'false'" and "\"false\"" are all false, the rest are fine. Don't ask. type duration = number | `${number}ms` | `${number}s` +type pair = string: any ``` -## get-var -Get css custom property from an element +=== + + +## Core + +### get-var +Get css custom property from an element. Basically var but evaluated lazily. NOTE: Avoid using `var` inside cssx expressions. ```typescript function get-var(custom-property-name): string -function get-var(selector, custom-property-name): string +function get-var(custom-property-name, default-value): string +``` + +Example - +```css +#my-element { + --cssx-text: get-var(--some-variable); +} ``` -## update + +#### update Update a css custom property on an element ```typescript @@ -25,24 +39,230 @@ function update(custom-property-name, string): void function update(selector, custom-property-name, string): string ``` +Example - +```css +#my-element { + --cssx-on-click: update(some-el, --text, attr(input-element, 'value')); -## js-eval -Evaluate any js expression. Easy escape hatch into writing the worst code humanly possible. + --cssx-children: input#input-element #some-el; +} -```typescript -function js-eval(string): string +#some-el { --text: "default"; } +#some-el::after { content: var(--text); } ``` -## if +### if If expression. You know how this one goes. If truthy, it'll pick the second argument, else the third. ```typescript function if(condition, any, any): any ``` +Example - +```css +#my-element { + --boolean: false; + + --cssx-on-update: + update(background-color, + if( + get-var(--boolean) + 'DarkGoldenRod', + 'PapayaWhip' + ) + ); +} +``` + +### map +A constructor function to create a map of key value pairs. + +```typescript +function map(...pair): map +``` + +Example - +```css +#my-element { + --cssx-children: instance( + div#some-element, + map(--prop1: "hello", --prop2: "world") + ); +} +``` + +### seq +> WIP Docs + +### call +Call a "function". A function is any series of expressions defined in a css custom property. + +NOTE: Every function call creates a new dom node for computing the result. Dom nodes are the call stack. + +```typescript +function call(var-identifier, map): any +``` + +Example - +```css +#my-element { + --factorial: if( + js-expr(string(get-var(--n), '> 1')), + js-expr(string( + get-var(--n), + ' * ', + call(--factorial, map(--n: js-expr(string(get-var(--n), ' - 1')))) + )), + 1 + ); + + --cssx-on-mount: js-expr(string( + 'console.log("', + call(--factorial, map(--n: 5)), + '")' + )); +} +``` + +Or let's just go nuts with functions. +Because we use named properties as arguments and css is cascading, all named properties are implicitly available to everything getting called. + +> Not a design choice, a design consequence. + +So `--left` and `--right` is implicitly available to `--binary-op`. + +> NOTE: `func` in `--binary-op` doesn't do anything. It's to make the developer feel better. + +```css +#my-element { + --binary-op: + func(--left, --op, --right) + js-expr(string(get-var(--left), get-var(--op), get-var(--right))); + --greater-than: call(--binary-op, map(--op: ' >= ')); + --minus: call(--binary-op, map(--op: ' - ')); + --multiply: call(--binary-op, map(--op: ' * ')); + + --factorial: if(call(--greater-than, map(--left: get-var(--n), --right: 1)), + call(--multiply, map( + --left: get-var(--n), + --right: call(--factorial, + map(--n: call(--minus, + map(--left: get-var(--n), --right: 1))) + ) + )), + 1 + ); +} +``` + +### string +Concatenate strings together / Cast a value to string explicitly + +```typescript +function string(...string): string +``` + +```css +#my-element { + --log-stuff: 'Stuff to log to console'; + --cssx-on-mount: js-expr(string('console.log("', get-var(--log-stuff), '")')); +} +``` -## delay +### quotify +Add quotes around a value + +```typescript +function quotify(string): `'${string}'` +``` + +```css +#my-element { + --log-stuff: 'Stuff to log to console'; + --cssx-on-mount: js-expr(string('console.log(', quotify(get-var(--log-stuff)), ')')); +} +``` + + +### unquotify +Remove quotes from a value. No example here, use your imagination. + +```typescript +function quotify(string): string +``` + + +### do +Evaluate a series of expressions in sequence and return the last value. + +```css +#my-element { + --cssx-on-mount: + if(get-var(--some-boolean), + do( + add-class(loading), + delay(1s), + remove-class(loading) + ), + noop(), + ) + ; +} +``` + + +### try +The standard try/catch as an expression. The error expression is scoped and gets access to a `--error` value. + +```css +form#my-form { + --cssx-on-submit: + prevent-default() + add-class(form, 'submitting') + try( + do( + request('/your-api/some-api', 'POST'), + add-class(form, 'submitted') + ), + js-eval(string('alert("', get-var(--error), '")')) + ) + remove-class(form, 'submitting') + ; +} +``` + +### let +Create a binding for use inside a scoped expression. + +`--random` is only available within the let binding +```css +#my-element { + --cssx-on-mount: + let(--random, js-eval('Math.random()'), + js-eval('alert("', get-var(--random),'")') + ) + ; +} +``` + + +=== + + +## Others + +### js-eval +Evaluate any js expression. Easy escape hatch directly to hell. + +```typescript +function js-eval(string): string +``` + +### request +> WIP Docs + +### delay Wait a bit. ```typescript @@ -56,36 +276,30 @@ Examples for input - - `delay(0.5s)`: wait for 500 milliseconds -## load-cssx - - -## set-attr - - -## attr - +=== -## prevent-default +## DOM -## request +### load-cssx +Load more of this abomination into your page -## add-children +### set-attr -## remove-element +### attr -## call-method +### add-children -## map +### remove-element -## call +### prevent-default -## func +### call-method diff --git a/docs/how-it-works.md b/docs/how-it-works.md new file mode 100644 index 0000000..c4d6fe3 --- /dev/null +++ b/docs/how-it-works.md @@ -0,0 +1,130 @@ +# How does it work? +Who knows really? It's just magic for the most part. + +## Creating the dom tree + +Everything starts with the `body` element (by default). + +In your css, you can use `body` or `html` or `:root`. As long as your root (body by default) inherits that property, it's all good. +```css +:root { + --cssx-children: div#my-element; +} +``` + +This will create a div inside `body` with the `id` (and `data-element` attribute) of `my-element`. + + +Let's go deeper... + +```css +:root { + --cssx-children: div#my-element; +} + +#my-element { + --cssx-children: header#div-a main#div-b; +} +``` + +Now `my-element`, gets 2 children. You can probably figure out what those would look like. + +> NOTE: The styles for `#my-element` has to be loaded into the dom before the + + +You may have already noticed a problem here. If you don't override the --cssx-children property, wouldn't all children of body get access to that? + +Well yeah, which is why, we have a `.cssx-layer` element between the parent and children. This element wraps all children and makes it so all the cssx property are unset. This can occasionally make styling a bit difficult but that's a YOU problem for trying to use this. + + +## Instances +Instances are sort of like components. You can instantiate elements and provide them some custom properties. + +NOTE: Instances get unique ids so instances and children of instances cannot not use the id selector for the definition. + +```css +#my-element { + --cssx-children: + instance(div#user-card, map(--name: "Sugom Afart", --age: 20)) + instance(div#user-card, map(--name: "Leeki Bahol", --age: 69)) + instance(div#user-card, map(--name: "Yamam Aho", --age: 40)) + ; +} + +[data-instance=user-card] { + --name: "default name"; + --age: 0; + + --cssx-children: div#name div#age; +} + +[data-element=name]::after { + /* Using the ::after element to set content via css */ + content: "Name: " var(--name); +} +[data-element=age] { + /* Using the --cssx-text property because css doesn't like numbers in `content` */ + --cssx-text: string("Age: ", get-var(--age)); +} +``` + + + +## Custom functions + +This is by far the most "fun" aspect of this project. Take a look at the docs for [call](./api/functions.md#call) for the api and examples. + +```css +#my-element { + --factorial: + func(--n) + if( + js-expr(string(get-var(--n), '> 1')), + js-expr(string( + get-var(--n), + ' * ', + call(--factorial, map(--n: js-expr(string(get-var(--n), ' - 1')))) + )), + 1 + ); + + --cssx-on-mount: js-expr(string( + 'console.log("', + call(--factorial, map(--n: 5)), + '")' + )); +} +``` + +NOTE: `func` is noop and just exists for documentation. You can also do `func(--a: string, --b: number)` and it'll be valid syntax but ignored at evaluation. So basically, typescript. + +The way this works is that it creates a new dom element inside the caller (`#my-element`), which then becomes the scope for the function. +Whatever arguments are passed to call will be added as css properties to this dom element. +Then the expressions inside the function is evaluated within the context of that element. + +This means that with `call(--factorial, map(--n: 5))` the dom tree would look something like this. + +```html +<div id="my-element"> + <div class="cssx-layer"></div> <!-- This is where the children would go... if you had any, you virgin --> + + <div style="display: none; --n: 5;"> + <div style="display: none; --n: 4;"> + <div style="display: none; --n: 3;"> + <div style="display: none; --n: 2;"> + <div style="display: none; --n: 1;"> + </div> + </div> + </div> + </div> + </div> +</div> +``` + +This is the call stack. This is immedietely deleted as soon as the required computation is completed. + +> PRO TIP 1: If you want the tree to persist even after the function is evaluated for debugging, add the `data-debug-stack` attribute to the caller element +> PRO TIP 2: You could style these nodes to have this tree show up in the ui and use the `--cssx-text` property to display the arguments for each recursive function call +> PRO TIP 3: If you're running into infinite loops, good luck. Also, you can add `delay(1s)` at the start to slow things down to debug. + + diff --git a/docs/how_it_works.md b/docs/how_it_works.md deleted file mode 100644 index 6329723..0000000 --- a/docs/how_it_works.md +++ /dev/null @@ -1,4 +0,0 @@ -# How does it work? - -WIP - diff --git a/docs/recipies.md b/docs/recipies.md index 52dddf4..133f69f 100644 --- a/docs/recipies.md +++ b/docs/recipies.md @@ -95,3 +95,9 @@ NOTE: Try to avoid doing this. Please refer to [./security.md](./security.md) fo } ``` + +## Debugging call stack + +> WIP docs + + diff --git a/examples/clock/style.css b/examples/clock/style.css index 07b8cc9..110d95b 100644 --- a/examples/clock/style.css +++ b/examples/clock/style.css @@ -84,8 +84,8 @@ body * { box-sizing: border-box; } top: 50%; left: 50%; transform-origin: 0% 50%; - transform: rotate(0deg); border-radius: 5px; + transform: rotate(0deg); --get-transform: string('rotate(', get-var(--angle), 'deg)'); diff --git a/package.json b/package.json index f8c62c5..2c5d06a 100644 --- a/package.json +++ b/package.json @@ -17,6 +17,7 @@ "format": "prettier --write './{src,tests}/**/*.{ts,html,css}'", "lint": "eslint ./src", "fix": "yarn lint --fix && yarn format", + "pub:patch": "yarn lint && yarn build && yarn publish --access=public --patch", "test": "jest" }, "devDependencies": { diff --git a/src/eval.ts b/src/eval.ts index 9a55828..636023b 100644 --- a/src/eval.ts +++ b/src/eval.ts @@ -82,11 +82,11 @@ export const evalExpr = async ( } const QUOTE_REGEX = /^['"](.*)(?=['"]$)['"]$/g -const dequotify = (s: string) => s.replace(QUOTE_REGEX, '$1') +const unquotify = (s: string) => s.replace(QUOTE_REGEX, '$1') export const evalValueToString = (val: EvalValue): string | undefined => match<string | undefined, EvalValue>(val, { - String: s => dequotify(s), + String: s => unquotify(s), Boolean: b => `${b}`, Number: n => `${n}`, VarIdentifier: s => s, @@ -105,7 +105,7 @@ const evalValueToNumber = (val: EvalValue): number | undefined => const evalValueToBoolean = (val: EvalValue): boolean => match<boolean, EvalValue>(val, { - String: s => !['false', '', '0'].includes(dequotify(s)), + String: s => !['false', '', '0'].includes(unquotify(s)), Boolean: b => b, Number: n => !!n, Value: v => !!v, @@ -282,6 +282,10 @@ const getFunctions = ( seq: async () => EvalValue.Lazy(args), + // noop + noop: async () => EvalValue.Void(), + func: async () => EvalValue.Void(), + call: async () => { const varId = match<string | undefined, EvalValue>( await evalExpr(args[0], actions), @@ -321,9 +325,9 @@ const getFunctions = ( const str = await evalExprAsString(args[0], actions) return EvalValue.String(`'${str || ''}'`) }, - dequotify: async () => { + unquotify: async () => { const str = await evalExprAsString(args[0], actions) - return EvalValue.String(dequotify(str || '')) + return EvalValue.String(unquotify(str || '')) }, try: async () => { diff --git a/src/index.ts b/src/index.ts index bc471ee..57ef6d0 100644 --- a/src/index.ts +++ b/src/index.ts @@ -296,7 +296,6 @@ const createLayer = async ( $childrenRoot, ) $childrenRoot.appendChild($child) - console.log($child.dataset.element, isNewElement, declaration) await manageElement($child, isNewElement) if (declaration.children.length > 0) { |
