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

Commit b3ed3ee

Browse files
committed
docs: comments for nuanced code
1 parent 8471226 commit b3ed3ee

File tree

6 files changed

+28
-39
lines changed

6 files changed

+28
-39
lines changed

src/browser.ts

+7
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,14 @@
1+
// This file is only provided in IIFE builds
2+
// Including this file doesn't allow Lucia to be tree shaken, which is
3+
// the main reasoning for omitting this file in CJS and ESM builds
4+
15
import * as Lucia from './index';
26

37
if (document.readyState === 'loading') {
48
document.addEventListener('DOMContentLoaded', () => {
9+
// Lucia allows for a custom initialization function
10+
// This is to support for delayed init, like for Turbo Drive
11+
512
// @ts-expect-error
613
const init = window.LuciaInit;
714

src/component.ts

-22
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
/* istanbul ignore next */
2-
32
import { Directives, DirectiveProps, Watchers, State, ASTNode } from './models/structs';
43

54
import { directives } from './core/directive';
@@ -8,7 +7,6 @@ import reactive from './core/reactive';
87
import render from './core/render';
98

109
import { setElementCustomProp } from './core/utils/elementCustomProp';
11-
import { DIRECTIVE_PREFIX } from './models/generics';
1210

1311
export class Component {
1412
public state: State;
@@ -35,7 +33,6 @@ export class Component {
3533
this.render();
3634

3735
setElementCustomProp(rootEl, 'component', this);
38-
this.handleMutations(rootEl);
3936

4037
return this.state;
4138
}
@@ -51,25 +48,6 @@ export class Component {
5148
public render(props: string[] = Object.keys(this.state)) {
5249
render(this.ast!, directives, this.state, props);
5350
}
54-
55-
/* istanbul ignore next */
56-
public handleMutations(el: HTMLElement) {
57-
const mutationObserver = new MutationObserver((mutationsList) => {
58-
for (const mutation of mutationsList) {
59-
const attrName = String(mutation.attributeName);
60-
if (
61-
mutation.type === 'attributes' &&
62-
attrName.startsWith(DIRECTIVE_PREFIX) &&
63-
attrName !== `${DIRECTIVE_PREFIX}for`
64-
) {
65-
this.ast = compile(el, this.state);
66-
this.render();
67-
}
68-
}
69-
});
70-
71-
mutationObserver.observe(el, { attributes: true, subtree: true });
72-
}
7351
}
7452

7553
export const component = (state?: State) => new Component(state);

src/core/compile.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ export const collectAndInitDirectives = (
7777

7878
if (eventDirectivePrefixRE().test(name)) returnable = false;
7979

80-
// for directive requires template
80+
// for directive requires a template
8181
if (name.includes('for') && getElementCustomProp(el, '__for_template') === undefined) {
8282
setElementCustomProp(el, '__for_template', String(el.innerHTML).trim());
8383
returnable = false;

src/core/directives/for.ts

+16-15
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ import adjustDeps from '../utils/adjustDeps';
1313
import computeExpression from '../utils/computeExpression';
1414

1515
export const forDirective = ({ el, data, state, node }: DirectiveProps) => {
16-
node = node!;
1716
const marker = getElementCustomProp(el, 'component');
1817

1918
setElementCustomProp(el, 'component', true);
@@ -25,25 +24,19 @@ export const forDirective = ({ el, data, state, node }: DirectiveProps) => {
2524
(state[target?.trim()] as unknown[]) ?? computeExpression(target?.trim(), el, true)(state);
2625
const ast = compile(el, state);
2726

28-
let template = getElementCustomProp(el, '__for_template');
27+
const template = getElementCustomProp(el, '__for_template');
2928
if (el.innerHTML.trim() === template) el.innerHTML = '';
3029

30+
// for directive is size-based, not content-based, since everything is compiled and rerendered
3131
const arrayDiff = currArray?.length - el.children.length;
3232

3333
if (currArray?.length === 0) el.innerHTML = '';
3434
else if (arrayDiff !== 0) {
3535
for (let i = Math.abs(arrayDiff); i > 0; --i) {
3636
if (arrayDiff < 0) el.removeChild(el.lastChild as Node);
3737
else {
38-
// Handle table cases
39-
const tag = template.startsWith('<th')
40-
? 'thead'
41-
: template.startsWith('<td') || template.startsWith('<tr')
42-
? 'tbody'
43-
: 'div';
44-
45-
const temp = document.createElement(tag);
46-
let content = template;
38+
let content = String(template);
39+
const isTable = /^[^\S]*?<(t(?:head|body|foot|r|d|h))/i.test(content);
4740

4841
if (item) {
4942
content = content.replace(
@@ -58,17 +51,25 @@ export const forDirective = ({ el, data, state, node }: DirectiveProps) => {
5851
);
5952
}
6053

61-
temp.innerHTML = content;
54+
// Needing to wrap table elements, else they disappear
55+
if (isTable) content = `<table>${content}</table>`;
56+
57+
const fragment = document.createRange().createContextualFragment(content)
58+
.firstElementChild!;
6259

63-
el.appendChild(temp.firstElementChild!);
60+
// fragment and fragment.firstElementChild return the same result
61+
// so we have to do it two times for the table, since we need
62+
// to unwrap the temporary wrap
63+
el.appendChild(isTable ? fragment.firstElementChild! : fragment);
6464
}
6565
}
6666
}
6767

6868
if (!marker) {
69-
adjustDeps(ast, data.deps, node, 'for');
69+
// Deps recompiled because child nodes may have additional deps
70+
adjustDeps(ast, data.deps, node!, 'for');
7071
el.removeAttribute(`${DIRECTIVE_PREFIX}for`);
7172
}
7273

73-
render(compile(el, state, true), directives, state, node.deps);
74+
render(compile(el, state, true), directives, state, node!.deps);
7475
};

src/core/utils/concurrent.ts

+3
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
// Concurrent allows us to delay render calls if the main thread is blocked
2+
// This is kind of like time slicing in React but less advanced
3+
14
export const concurrent = (generatorFunction: () => Generator<undefined, void, unknown>) => {
25
const generator = generatorFunction();
36
return function next() {

src/index.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,10 @@ import computeExpression from './core/utils/computeExpression';
1111

1212
export { component, compile, render, reactive, directives, computeExpression };
1313

14+
// This is generally used for browser builds only, but it can be accessed in bundling environments
1415
export const init = (element: HTMLElement | Document = document): void => {
1516
const stateDirective = `${DIRECTIVE_PREFIX}state`;
1617
const componentElements = element.querySelectorAll(`[${stateDirective}]`);
17-
// Filter out uninit scopes only
1818
const uninitializedComponents = [...componentElements].filter(
1919
(el) => getElementCustomProp(el as HTMLElement, 'component') === undefined
2020
);

0 commit comments

Comments
 (0)