Skip to content
This repository has been archived by the owner on May 19, 2023. It is now read-only.

Commit

Permalink
Merge pull request #137 from aidenybai/staging
Browse files Browse the repository at this point in the history
Staging
  • Loading branch information
aidenybai authored Apr 27, 2021
2 parents 9dded9b + 5eddbc8 commit 94f7b11
Show file tree
Hide file tree
Showing 16 changed files with 66 additions and 40 deletions.
9 changes: 9 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
root = true

[*]
indent_style = space
indent_size = 2
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
4 changes: 2 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ package-lock.json
yarn-error.log

# Tests
*.html
/*.html
coverage

# Build source
Expand All @@ -15,4 +15,4 @@ dist/
.DS_Store

# Misc
scratch.md
scratch.md
1 change: 1 addition & 0 deletions .vscode/extensions.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{
"recommendations": [
"editorconfig.editorconfig",
"esbenp.prettier-vscode",
"dbaeumer.vscode-eslint",
"aidenybai.lucia",
Expand Down
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
MIT License

Copyright (c) 2020-present The Hack Foundation
Copyright (c) 2020-2021 Aiden Bai

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
12 changes: 6 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,15 @@ It also integrates well with module bundlers like [Webpack](https://webpack.js.o

## Todo App Example

Below is an extremely simple implementation of a todo app using Lucia, utilizing zero JavaScript. Tasks can be added by submitting the form with the input. No, your eyes aren't fooling you - it's really that simple.
Below is an extremely simple implementation of a todo app using Lucia, utilizing zero JavaScript. Tasks can be added by submitting the form with the input. No, your eyes aren't fooling youit's really that simple.

```html
<div l-state="{ value: '', todo: [] }">
<!-- two-way-binds `value` prop to value -->
<!-- oninput: set `value` to input.value -->
<input l-model="value" />
<!-- captures click event, pushing current `value` to `todo` -->
<!-- onclick: add the current `value` to the `todo` array -->
<button @click="todo.push(value)">Create</button>
<!-- joins array together -->
<!-- joins `todo` array together -->
<ul l-for="task in todo">
<li l-text="this.task"></li>
</ul>
Expand All @@ -42,7 +42,7 @@ Below is an extremely simple implementation of a todo app using Lucia, utilizing

## Sponsors

<a href="https://hackclub.com/bank" target="_blank"><img width="30%" src="https://cdn.glitch.com/747f5921-6fdc-45db-8eaa-ac12523e0e6c%2Fhackclub-bank.svg?v=1566159701206" alt="Hack Club Bank"></a>
<a href="https://hackclub.com/bank" target="_blank"><img height="60" src="https://cdn.glitch.com/747f5921-6fdc-45db-8eaa-ac12523e0e6c%2Fhackclub-bank.svg?v=1566159701206" alt="Hack Club Bank"></a>

**Want your logo here? [→ Sponsor Lucia](https://bank.hackclub.com/donations/start/lucia)**

Expand All @@ -68,4 +68,4 @@ _Lucia originates from the Latin word "lux", meaning "light, illuminance"_

---

© 2020-present The Hack Foundation.
© 2020-2021 Aiden Bai.
4 changes: 2 additions & 2 deletions docs/codebase/WORKFLOW.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,13 @@ Lucia is written in [TypeScript](https://www.typescriptlang.org) and should be r

### Iterating

You can create a `*.html` (e.g. `test.html`) file at root to test changes in realtime. We recommend using `live-server` to hot-reload the webpage on change, and edit as necessary.
You can create a `*.html` (e.g. `test.html`) file at root to test changes in realtime. We recommend using [`live-server`](https://www.npmjs.com/package/live-server) to hot-reload the webpage on change, and edit as necessary.

Below is a sample for a Lucia starter:

```html
<!DOCTYPE html>
<html lang="en">
<html>
<head>
<script src="./dist/lucia.dev.js"></script>
</head>
Expand Down
5 changes: 3 additions & 2 deletions rollup.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import babel from '@rollup/plugin-babel';
import strip from '@rollup/plugin-strip';
import beep from '@rollup/plugin-beep';

const name = 'Lucia';
const legacy = () => {
return babel({
extensions: ['.ts'],
Expand Down Expand Up @@ -48,7 +49,7 @@ export const build = (input, config) => {
buildOutput.push({
file: config.output[0],
format: config.format,
name: 'Lucia',
name,
globals: {},
strict: true,
});
Expand All @@ -58,7 +59,7 @@ export const build = (input, config) => {
file: config.output[1],
format: config.format,
plugins: [terser({ format: { comments: false } })],
name: 'Lucia',
name,
globals: {},
strict: true,
});
Expand Down
2 changes: 1 addition & 1 deletion scripts/dev.sh
Original file line number Diff line number Diff line change
@@ -1 +1 @@
esbuild src/browser.ts --bundle --watch --sourcemap --outfile=dist/lucia.js
esbuild src/browser.ts --bundle --watch --sourcemap --outfile=dist/lucia.dev.js
3 changes: 3 additions & 0 deletions src/component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ export class Component {

setElementCustomProp(rootEl, COMPONENT_FLAG, this);

const mountedEvent = new CustomEvent('mounted');
rootEl.dispatchEvent(mountedEvent);

return this.state;
}

Expand Down
6 changes: 3 additions & 3 deletions src/core/directives/bind.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ export const bindDirective = ({ el, parts, data, state }: DirectiveProps): void
return el.setAttribute('class', formatAcceptableWhitespace(rawClasses));
} else if (el.hasAttribute('class')) {
/* istanbul ignore next */
return el.removeAttribute('class');
if (el.hasAttribute('class')) return el.removeAttribute('class');
}
}
break;
Expand All @@ -47,7 +47,7 @@ export const bindDirective = ({ el, parts, data, state }: DirectiveProps): void
case 'style': {
// Accept object and set properties based on boolean state value
const styles = data.compute(state);
el.removeAttribute('style');
if (el.hasAttribute('style')) el.removeAttribute('style');
Object.entries(styles).forEach(([styleName, styleValue]) => {
el.style[styleName] = styleValue;
});
Expand All @@ -70,7 +70,7 @@ export const bindDirective = ({ el, parts, data, state }: DirectiveProps): void
} else if (attributes) {
el.setAttribute(parts[1], attributes);
} else {
el.removeAttribute(parts[1]);
if (el.hasAttribute(parts[1])) el.removeAttribute(parts[1]);
}
break;
}
Expand Down
14 changes: 8 additions & 6 deletions src/core/directives/html.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,17 @@ import { getElementCustomProp, setElementCustomProp } from '../utils/elementCust
export const htmlDirective = ({ el, data, state, node }: DirectiveProps): void => {
node = node!;
const marker = getElementCustomProp(el, COMPONENT_FLAG);
const ret = data.compute(state) ?? data.value;

// Handle naked prop in expression case
el.innerHTML = data.compute(state) ?? data.value;
if (ret !== el.innerHTML) {
el.innerHTML = ret;

const ast = compile(el, state, true);
const ast = compile(el, state, true);

if (!marker) adjustDeps(ast, data.deps, node, 'html');
if (!marker) adjustDeps(ast, data.deps, node, 'html');

render(ast, directives, state, data.deps);
render(ast, directives, state, data.deps);

setElementCustomProp(el, COMPONENT_FLAG, true);
setElementCustomProp(el, COMPONENT_FLAG, true);
}
};
3 changes: 2 additions & 1 deletion src/core/directives/show.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { DirectiveProps } from '../../models/structs';

export const showDirective = ({ el, data, state }: DirectiveProps): void => {
el.style.display = data.compute(state) ? '' : 'none';
const ret = data.compute(state);
if (ret !== el.style.display) el.style.display = ret ? '' : 'none';
if (el.style.length === 0) el.removeAttribute('style');
};
5 changes: 4 additions & 1 deletion src/core/directives/text.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import { DirectiveProps } from '../../models/structs';

export const textDirective = ({ el, data, state }: DirectiveProps): void => {
el.textContent = data.compute(state) ?? data.value;
const ret = data.compute(state) ?? data.value;
if (ret !== el.textContent) {
el.textContent = ret;
}
};
6 changes: 6 additions & 0 deletions src/core/render.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,12 @@ const render = (
}
}
}

// Effect is like a watcher but detects changes to an el
if (node.directives['on:effect']) {
const effectEvent = new CustomEvent('effect');
node.el.dispatchEvent(effectEvent);
}
}
})();
};
Expand Down
24 changes: 12 additions & 12 deletions src/core/utils/computeExpression.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,17 @@ import { UnknownKV } from '../../models/generics';
import { Refs } from '../../models/structs';
import { expressionPropRE } from './patterns';

export const resolveStateInExpression = (unresolvedExpression: string, deps?: string[]): string => {
export const resolveStateInExpression = (
unresolvedExpression: string,
deps: string[] = []
): string => {
// This dynamically appends `$state.` to the front of standalone props, allowing the
// user to write less and us to compile and run faster without with() {}
if (deps) {
let expression = unresolvedExpression;
deps.forEach((dep) => {
expression = expression.replace(expressionPropRE(dep), `$state.${dep}`);
});
return expression;
} else {
return `with($state){${unresolvedExpression}}`;
}
let expression = unresolvedExpression;
deps.forEach((dep) => {
if (dep !== expression) expression = expression.replace(expressionPropRE(dep), `$state.${dep}`);
});
return expression;
};

export const computeExpression = (
Expand All @@ -31,8 +30,9 @@ export const computeExpression = (
// This "revives" a function from a string, only using the new Function syntax once during compilation.
// This is because raw function is ~50,000x faster than new Function
const computeFunction = new Function(
`return function(${specialPropertiesNames.join(',')}){${resolvedExpression}}`
`'use strict';return function(${specialPropertiesNames.join(',')}){${resolvedExpression}}`
)();

const emit = (name: string, options?: CustomEventInit, dispatchGlobal = true) => {
const event = new CustomEvent(name, options);
const target = dispatchGlobal ? window : el || window;
Expand All @@ -43,7 +43,7 @@ export const computeExpression = (
try {
const value = state[expression];
if (value) {
return typeof value === 'function' ? value() : value;
return typeof value === 'function' ? value.bind(state)() : value;
} else {
return computeFunction(state, el, emit, event, refs);
}
Expand Down
6 changes: 3 additions & 3 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2514,9 +2514,9 @@ error-ex@^1.3.1:
is-arrayish "^0.2.1"

esbuild@^0.11.1:
version "0.11.8"
resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.11.8.tgz#dcab565c3a61f2395aba37a78e93d5ab882bd865"
integrity sha512-dUZj5etA0e+SChqRMswgUj8TAj5ay7z06/BD32t0pRWgMDh8S/NTW7e7O1jLVIDeAECsRXkIzG2o+jpBwchq7w==
version "0.11.15"
resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.11.15.tgz#d92250e1755294f84bc7a83ed191e60baadf7b6a"
integrity sha512-Hh40byWZZgYbiLhcoOWiOUIy8yUYQeCEA4F9feWytToD2jGfJ1X4VPf5dsqj6vRL29H3YmFqZsxIJa5q0ifB3g==

escalade@^3.1.1:
version "3.1.1"
Expand Down

0 comments on commit 94f7b11

Please # to comment.