-
Notifications
You must be signed in to change notification settings - Fork 5
/
about.html
186 lines (173 loc) · 26.3 KB
/
about.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
<!DOCTYPE html>
<html lang="en"><head>
<link rel="icon" href="/logo.svg">
<title>VanJS - About</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
@font-face {
font-family: 'Poppins';
font-style: normal;
font-weight: 400;
src: url(https://fonts.gstatic.com/s/poppins/v20/pxiEyp8kv8JHgFVrJJfedw.ttf) format('truetype');
}
</style>
<link rel="stylesheet" href="/code/w3-v1.css">
<link rel="stylesheet" href="/code/prism-v1.css">
<link rel="stylesheet" href="/vanjs.css">
</head>
<body class="line-numbers" data-prismjs-copy="📋">
<!-- Google tag (gtag.js) -->
<script async src="https://www.googletagmanager.com/gtag/js?id=G-Q0NB75RY7E"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'G-Q0NB75RY7E');
</script>
<script type="text/javascript" src="/code/prism-v1.js" defer></script>
<!-- Sidebar/menu -->
<nav class="w3-sidebar w3-red w3-collapse w3-top w3-large w3-padding" style="z-index:3;width:280px;font-weight:bold;" id="mySidebar"><br>
<a href="javascript:void(0)" onclick="w3_close()" class="w3-button w3-hide-large w3-display-topleft" style="width:100%;font-size:22px">Close Menu</a>
<div class="w3-container">
<h1 class="w3-padding-16 w3-xxxlarge">
<img src="/logo.svg" alt="VanJS" width="192px" height="192px">
</h1>
</div>
<div id="nav" class="w3-bar-block"><a href="/" onclick="w3_close()" class="w3-bar-item w3-button w3-hover-white">Home</a><a href="/start" onclick="w3_close()" class="w3-bar-item w3-button w3-hover-white">Getting Started</a><a href="/tutorial" onclick="w3_close()" class="w3-bar-item w3-button w3-hover-white">Tutorial</a><a href="/demo" onclick="w3_close()" class="w3-bar-item w3-button w3-hover-white">VanJS by Example</a><a href="/convert" onclick="w3_close()" class="w3-bar-item w3-button w3-hover-white">HTML/MD to VanJS</a><a href="/vanui" onclick="w3_close()" class="w3-bar-item w3-button w3-hover-white">VanUI</a><a href="/minivan" onclick="w3_close()" class="w3-bar-item w3-button w3-hover-white">Mini-Van</a><a href="/ssr" onclick="w3_close()" class="w3-bar-item w3-button w3-hover-white">SSR & Hydration</a><a href="/x" onclick="w3_close()" class="w3-bar-item w3-button w3-hover-white">X</a><a href="/advanced" onclick="w3_close()" class="w3-bar-item w3-button w3-hover-white">Advanced Topics</a><a href="/media" onclick="w3_close()" class="w3-bar-item w3-button w3-hover-white">Media Coverage</a><a href="/about" onclick="w3_close()" class="w3-bar-item w3-button w3-hover-white current">About</a></div>
</nav>
<!-- Top menu on small screens -->
<header class="w3-container w3-top w3-hide-large w3-red w3-xlarge w3-padding">
<a href="javascript:void(0)" class="w3-button w3-red w3-margin-right" onclick="w3_open()">☰</a>
<span id="title-bar">About</span>
</header>
<!-- Overlay effect when opening sidebar on small screens -->
<div class="w3-overlay w3-hide-large" onclick="w3_close()" style="cursor:pointer" title="close side menu" id="myOverlay"></div>
<!-- !PAGE CONTENT! -->
<div class="w3-main" style="margin-left:300px;">
<div id="page">
<div id="content"><h1 class="w3-xxlarge"><b>VanJS</b>: About</h1><blockquote><i>大道至简 (The profound truth is utmost simplicity)</i></blockquote><h2 class="w3-xxlarge w3-text-red" id="story"><a class="self-link" href="#story">Meet the Author - the Story behind VanJS</a></h2><hr style="width:50px;border:5px solid red" class="w3-round"><div style="overflow: auto;"><img style="float: left; width: 150px; margin-right: 20px;" src="/tao.jpeg" alt="Tao Xin"><p>Hello all,</p><p>I'm <a href="https://www.linkedin.com/in/taoxin/" class="w3-hover-opacity">Tao Xin (辛韬)</a>, a senior staff software engineer at Google, and I'm the founder of <b>VanJS</b>. I would like to talk about 2 central questions about <b>VanJS</b>: What <b>VanJS</b> really is, and why I think it's good to the world.</p><p>So, what is <b>VanJS</b>? Well, it's a reactive UI framework. It's <b>more than 100 times</b> smaller than React. It doesn't require installation, configuration, dependencies or transpiling to use. But I think, in a nutshell, the best way to describe it is: <i><b>VanJS</b> is the <b>scripting language</b> for UI, just like <code class="symbol">bash</code> is the scripting language for terminal.</i></p><p>Ever since the birth of GUI, there is no shortage of UI frameworks: MFC, Win Form, WPF, Qt, Flutter, SwiftUI, Jetpack Compose, React, React Native, to name a few. They enabled us to build highly sophisticated UI apps. But on the other hand, frameworks and tools themselves could be the entry barrier for UI programming: high-specialized IDEs, lengthy tutorials, mysterious problems that might arise here and there, being forced to program in a designated style, and most importantly, ONLY people with specialized skills can work on it. Even JavaScript, with "<i>Script</i>" in its name, is trying to become a compiled language: JSX, TSX, transpiling, and plugins/extensions to allow us to work with the transpiled code.</p><p>On the flip side, the default way for programmers to interact with computers remains the same for over 50 years - shells, CLI programs, and sometimes, ASCII arts. Why? Is terminal inherently better than GUI? Or does it just make programmers look cooler? I think the fundamental reason that lies behind, is the power of scripting, the power to start coding immediately in any environment, the power to build useful things with just a few lines of code, the power to easily assemble various code snippets together.</p><p><i>Being the scripting language for UI</i>, is the fundamental principle that guides the design of <b>VanJS</b>. It's based on JavaScript so that it can work in as many environments as possibles, not only for websites, but also for webviews which most major OSes support. It has declarative composing API and reactive state binding as it enables an easier way to describe comprehensive UI logic within just a few lines of code. It has strictly 0 dependencies so that it can be used right after the code is typed. It's JSX-free thus REPL can be easily done in the browser console.</p><p>So, why is <b>VanJS</b> good to the world? I think the world needs a scripting way to build UI, and there are way more scenarios where UI can be more beneficial than people might have realized, for personal utilities, for teamwide tools, and for user-facing products as well. We are quite used to the categorization between front-end engineers and back-end engineers, and we are quite used to the notion that back-end engineers will never do UI. We think only a very small number of people need to know how to build UI.</p><p>But, is it really the case? I've been a back-end engineer for more than a decade. I had been leading a team which manages 100+ data processing pipelines and datasets produced by them. I felt, for many times, that we really needed a way to visualize the status of the pipelines and datasets. "<i>But, ...</i>", pushbacks would immediately arise after the idea, "<i>We're not a front end team. We shouldn't do it. We don't have the expertise.</i>", I think here, "<i>We don't have the expertise</i>", doesn't really mean the team is not technical capable of programming the UI logic. What it actually means is, "<i>We don't really have the experience of dealing with mysterious, and oftentimes undocumented issues here and there that might only occur in our specific development environment, and we can't accurately estimate the amount of time needed to get them resolved.</i>" We tried to hire an intern to do the work, but the work couldn't finish because of waves of issues in the internal build systems.</p><p>I am never a front-end engineer, and I haven't used any UI framework. But I built lots of UI apps, and I will continue doing it, in a scripting way. And I believe anyone can do that as well.</p><p>I'm hoping open sourcing <b>VanJS</b> can help us one step closer to that vision. Hope you can enjoy!</p><p>Thanks!</p><p>-- Tao Xin</p><blockquote><i>"Who do you truly serve?"<br>"The Realm. Someone must."<br><br>-- George R. R. Martin, Game of Thrones: S1E8</i></blockquote></div><h2 class="w3-xxlarge w3-text-red" id="copyright-and-compliance-disclaimer"><a class="self-link" href="#copyright-and-compliance-disclaimer">Copyright and Compliance Disclaimer</a></h2><hr style="width:50px;border:5px solid red" class="w3-round"><p><b>VanJS</b> was built by Tao Xin during his personal time while being employed as a full-time employee at Google. The project was submitted to Invention Assignment Review Committee at Google where Google, upon reviewing the designated scopes, waived its copyright claims. Thus the copyright of <b>VanJS</b> belongs to its creator, all rights reserved. <b>VanJS</b> is open sourced under MIT license. <b>VanJS</b> aims to build a better world by reducing the entry barrier for UI programming, with no intention or plan on commercialization whatsoever.</p><p>The project was developed, and will be maintained with strict compliance to Google's Outside Work Guidelines as well as requirements imposed by Google's copyright waiver. <b>VanJS</b> was created, and will continue to be maintained, without any use of internal Alphabet resources, including but not limited to, corporate hardware equipments, software licenses, internal tools, internal corporate mailing lists, corporate accounts, proprietary or confidential information, trademarks or brand features of any Alphabet company. Alphabet does not sponsor, endorse or in any form affiliate with <b>VanJS</b> project. To comply with the conflict of interests provisions, Tao Xin does not advocate the adoption of <b>VanJS</b> within Alphabet.</p><h2 class="w3-xxlarge w3-text-red" id="reliability"><a class="self-link" href="#reliability">How Do We Ensure the Reliability of VanJS?</a></h2><hr style="width:50px;border:5px solid red" class="w3-round"><p>As a new UI framework, we put heavy focus on the reliability of the framework. For every single release of <b>VanJS</b>, below is the list of tests that we will run through:</p><ul><li>A browser-based test suite, with 500+ test cases, covering different versions of <b>VanJS</b> files (<code class="symbol">.min.js</code>, <code class="symbol">.debug.js</code>, <code class="symbol">.nomodule.min.js</code>, etc.), including the coverage of advanced behavior such as <a href="/advanced#gc" class="w3-hover-opacity">garbage collection</a>, as well as error messages shown in the debug mode.</li><li>Examples used in <a href="/tutorial" class="w3-hover-opacity">VanJS tutorial</a> are also covered in the browser-based test suite.</li><li>The browser-based test suite was implemented in TypeScript, thus TypeScript integration is covered.</li><li><a href="/demo" class="w3-hover-opacity">Sample applications</a> will keep working in every single <b>VanJS</b> release, including applications implemented in TypeScript (which covers TypeScript integration).</li></ul><p>For every single release of <b>Mini-Van</b>, below is the list of tests that we will run through:</p><ul><li>A browser-based test suite, with 60 test cases, covering different versions of <b>Mini-Van</b> files (<code class="symbol">.min.js</code>, <code class="symbol">.nomodule.min.js</code>, etc.).</li><li>The browser-based test suite was implemented in TypeScript, thus TypeScript integration is covered.</li><li>A Deno test suite for <code class="symbol">van-plate</code> mode, covering Deno integration.</li><li>The entire site of vanjs.org was generated with <b>Mini-Van</b> with TypeScript files defining all web pages. Source code can be found <a href="https://github.com/vanjs-org/vanjs-org.github.io/tree/master/sitegen" class="w3-hover-opacity">here</a>.</li></ul><p>For every single release of <b>VanX</b>, below is the list of tests that we will run through:</p><ul><li>A browser-based test suite, with 100+ test cases, covering different versions of <b>VanX</b> files, including the coverage of advanced behavior such as <a href="/advanced#gc" class="w3-hover-opacity">garbage collection</a>.</li><li>The browser-based test suite was implemented in TypeScript, thus TypeScript integration is covered.</li><li>Sample applications in <a href="https://vanjs.org/x" class="w3-hover-opacity">https://vanjs.org/x</a> will keep working in every single <b>VanX</b> release.</li></ul><h2 class="w3-xxlarge w3-text-red" id="coding-style"><a class="self-link" href="#coding-style">A Note on Coding Styles</a></h2><hr style="width:50px;border:5px solid red" class="w3-round"><p>The sample code snippets throughout this website follow a minimalist approach when it comes to coding styles. When readability is not impacted, we are leaning towards the choice that leads to more concise code, with the belief that brevity and simplicity generally make the code easier to read and write. This means that we're consciously choosing certain coding styles throughout this website: such as omitting optional semicolons, naked if statements, usage of ternary operator when appropriate, etc.</p><p>On the other hand, we acknowledge that different people might hold a somewhat different opinion regarding certain coding style choices, and some are among hotly debated issues among programmers. We understand the arguments from the other side that certain coding styles, might occasionally lead to slightly more misleading error messages for incorrect implementation in limited situations. As an <b>unopinionated</b> framework, <b>VanJS</b> doesn't take side on coding styles. If some style in the sample code doesn't align with your personal preference or your team's common practice, feel free to make the corresponding styling changes after copy/past-ing the sample code.</p><h2 class="w3-xxlarge w3-text-red" id="source-guide"><a class="self-link" href="#source-guide">A Guide to Reading VanJS Codebase</a></h2><hr style="width:50px;border:5px solid red" class="w3-round"><p>We believe that <b>VanJS</b> is a good illustration of how modern UI frameworks work under the hood. The simplicity in its design, and conciseness in its implementation make it the perfect learning material for the core fundamentals of reactive UI programming, as well as advanced techniques in modern JavaScript. Here we recommend this <a href="https://www.youtube.com/watch?v=Oh2IEVqarHs" class="w3-hover-opacity">7-minute video</a> which breaks down and elucidates the underlying principles of <b>VanJS</b> codebase.</p><p>On the other hand, we do realize that some parts of <b>VanJS</b> codebase might be hard to read for some people. We believe that this is mostly because <b>VanJS</b> has chosen some programming techniques and language constructs that are not frequently used in the JavaScript community, despite their usefulness. Here we provide a brief explanation of those in the hope of easing the understanding of <b>VanJS</b> codebase, its official extensions, and its sample applications.</p><p>JavaScript language features:</p><ul><li><code class="symbol"><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy" class="w3-hover-opacity">Proxy</a></code>: A type of JavaScript objects that allow you to intercept and redefine common operations of another object, such as getting and setting properties. The <code class="symbol">van.tags</code> object in <b>VanJS</b> leverages this technique to allow you declaring DOM trees like HTML but without the need of JSX. The operation of getting any properties of <code class="symbol">van.tags</code> will be intercepted and redefined to a function that creates an HTML element with the property name as its tag name. e.g.: <code class="language-js">van.tags.div()</code> will create a <code class="language-html"><div></code> element. In addition, the <a href="/x#reactive-object" class="w3-hover-opacity">reactive object</a> in <b>VanX</b> leverages <code class="symbol">Proxy</code> so that getting and setting its fields will be redefined to getting and setting values of the underlying states.</li><li><a href="https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Objects/Object_prototypes" class="w3-hover-opacity">prototype</a>: The foundation of OOP in JavaScript. Any object in JavaScript can specify a prototype object so that property access falls back to the prototype if the property doesn't exist in the object itself. Prototype is a lightweight alternative to <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes" class="w3-hover-opacity">classes</a> in JavaScript. <b>VanJS</b> is using prototype instead of classes to keep its size small.</li></ul><p>Less frequently used JavaScript syntaxes:</p><ul><li><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Conditional_operator" class="w3-hover-opacity">Ternary operator</a>: Ternary operator is way to define conditional computations. Sometimes it can be used as an alternative to <code class="symbol">if...else</code> statement for more concise and declarative code. For instance, the following code:<pre><code class="language-js">const getFruits(hasApple, hasOrange) = () => {
const fruits = []
if (hasApple) {
fruits.push("apple")
}
if (hasOrange) {
fruits.push("orange")
}
return fruits
}
</code></pre> can be simplified with ternary operators:<pre><code class="language-js">const getFruits(hasApple, hasOrange) = () => [].concat(
hasApple ? "apple" : [],
hasOrange ? "orange": [],
)
</code></pre>Even more complex <code class="symbol">if...else if...else</code> statement can be simplified with ternary operators as well. For instance, the following code in the <code class="symbol"><a href="/demo#calculator" class="w3-hover-opacity">Calculator App</a></code>:<pre><code class="language-js">const calc = (lhs, op, rhs) =>
!op || lhs === null ? rhs :
op === "+" ? lhs + rhs :
op === "-" ? lhs - rhs :
op === "x" ? lhs * rhs : lhs / rhs
</code></pre> is the simplified version of:<pre><code class="language-js">const calc = (lhs, op, rhs) => {
if (!op || lhs === null) {
return rhs
} else if (op === "+") {
return lhs + rhs
} else if (op === "-") {
return lhs - rhs
} else if (op === "x") {
return lhs * rhs
} else {
return lhs / rhs
}
}
</code></pre></li><li><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Comma_operator" class="w3-hover-opacity">Comma operator (,)</a>: Comma operator evaluates each of its operands sequentially and returns the last value. <b>VanJS</b> leverages comma operators in a few places to make the code concise. For instance, the logic of binding a state to a DOM property:<pre><code class="language-js">bind(() => {
setter(v.val)
return dom
})
</code></pre> is simplified to <code class="language-js">bind(() => (setter(v.val), dom))</code> in <code class="symbol"><a href="https://github.com/vanjs-org/van/blob/main/src/van.js" class="w3-hover-opacity">van.js</a></code> (don't confuse this with calling a function with 2 arguments).</li><li><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Nullish_coalescing" class="w3-hover-opacity">Nullish coalescing operator (??)</a>: Nullish coalescing expression <code class="language-js">a ?? b</code> means:<pre><code class="language-js">if (a !== null && a !== undefined) {
return a
} else {
return b
}
</code></pre><b>VanJS</b> leverages this operator in a few places to simplify code. One notable example in <code class="symbol"><a href="https://github.com/vanjs-org/van/blob/main/src/van.js" class="w3-hover-opacity">van.js</a></code> is function <code class="symbol">addAndScheduleOnFirst</code>:<pre><code class="language-js">let addAndScheduleOnFirst = (set, s, f, waitMs) =>
(set ?? (setTimeout(f, waitMs), new Set)).add(s)
</code></pre>which is equivalent to:<pre><code class="language-js">let addAndScheduleOnFirst = (set, s, f, waitMs) => {
if (set === null || set === undefined) {
setTimeout(f, waitMs)
set = new Set
}
set.add(s)
return set
}
</code></pre></li><li><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Logical_AND#short-circuit_evaluation" class="w3-hover-opacity">Short-circuit evaluation for <code class="symbol">&&</code> and <code class="symbol">||</code></a>: Sometimes, we're leveraging the short-circuit evaluation for <code class="symbol">&&</code> and <code class="symbol">||</code> to simplify code. For instance, in <code class="symbol"><a href="https://github.com/vanjs-org/van/blob/main/x/src/van-x.js" class="w3-hover-opacity">van-x.js</a></code>, <code class="language-js">refDelete(obj[statesSym], name) && onDelete(obj, name)</code> is equivalent to:<pre><code class="language-js">if (refDelete(obj[statesSym], name)) {
onDelete(obj, name)
}
</code></pre></li></ul><h2 class="w3-xxlarge w3-text-red" id="name"><a class="self-link" href="#name">How Did VanJS Get Its Name?</a></h2><hr style="width:50px;border:5px solid red" class="w3-round"><p><b>VanJS</b> is short for <b>Van</b>illa <b>J</b>ava<b>S</b>cript, which is a metaphor that <b>VanJS</b> provides an abbreviated way to write Vanilla JavaScript code. Meanwhile, the logo of <b>VanJS</b> is a symbolic vanilla ice cream, which means <b>VanJS</b> = <b>Vanilla</b> JavaScript + syntax <b>Sugar</b>.</p><p>Under the hood, <b>VanJS</b> stays truthful to Vanilla JavaScript as close as possible, as there is no transpiling, virtual DOM or any hidden logic. <b>VanJS</b> code can be translated to Vanilla JavaScript code in a very straightforward way. For instance, the following <b>VanJS</b> code:</p><pre><code class="language-js">a({href: "https://vanjs.org"}, "🍦 VanJS")</code></pre><p>is just an abbreviated/sugared form of following code in Vanilla Javascript:</p><pre><code class="language-js">const anchorDom = document.createElement("a")
anchorDom.href = "https://vanjs.org"
anchorDom.appendChild(new Text("🍦 VanJS"))
</code></pre><p>whereas</p><pre><code class="language-js">ul(
li("🗺️World"),
li(a({href: "https://vanjs.org/"}, "🍦VanJS")),
)
</code></pre><p>is an abbreviated/sugared form of:</p><pre><code class="language-js">const listDom = document.createElement("ul")
const itemDom1 = document.createElement("li")
itemDom1.appendChild(new Text("🗺️World"))
listDom.appendChild(itemDom1)
const itemDom2 = document.createElement("li")
const anchorDom = document.createElement("a")
anchorDom.href = "https://vanjs.org"
anchorDom.appendChild(new Text("🍦 VanJS"))
itemDom2.appendChild(anchorDom)
listDom.appendChild(itemDom2)
</code></pre></div>
<aside id="toc"><ul><li><a href="#story" class="w3-hover-opacity">Meet the Author - the Story behind VanJS</a></li><li><a href="#copyright-and-compliance-disclaimer" class="w3-hover-opacity">Copyright and Compliance Disclaimer</a></li><li><a href="#reliability" class="w3-hover-opacity">How Do We Ensure the Reliability of VanJS?</a></li><li><a href="#coding-style" class="w3-hover-opacity">A Note on Coding Styles</a></li><li><a href="#source-guide" class="w3-hover-opacity">A Guide to Reading VanJS Codebase</a></li><li><a href="#name" class="w3-hover-opacity">How Did VanJS Get Its Name?</a></li></ul></aside>
</div>
</div>
<script>
// Script to open and close sidebar
const w3_open = () => {
document.getElementById("mySidebar").style.display = "block"
document.getElementById("myOverlay").style.display = "block"
}
const w3_close = () => {
document.getElementById("mySidebar").style.display = "none"
document.getElementById("myOverlay").style.display = "none"
}
const tocDom = document.getElementById("toc")
// Tracks the current toc item
const trackToc = () => {
const allHeadings = [...document.querySelectorAll("h2,h3")]
const currentHeadingIndex = allHeadings.findIndex(h => h.getBoundingClientRect().top >= 0)
let currentHeading
if (currentHeadingIndex < 0) currentHeading = allHeadings[allHeadings.length - 1]; else {
currentHeading = allHeadings[currentHeadingIndex]
if (currentHeadingIndex > 0 && currentHeading.getBoundingClientRect().top > innerHeight)
currentHeading = allHeadings[currentHeadingIndex - 1]
}
for (const e of document.querySelectorAll("#toc li a"))
if (e.href.split("#")[1] === currentHeading?.id) {
e.classList.add("current-heading")
const {top: tocTop, bottom: tocBottom} = tocDom.getBoundingClientRect()
const {top: eTop, bottom: eBottom} = e.getBoundingClientRect()
if (eBottom > tocBottom) tocDom.scrollTop += eBottom - tocBottom
else if (eTop < tocTop) tocDom.scrollTop -= tocTop - eTop
} else
e.classList.remove("current-heading")
}
trackToc()
document.addEventListener("scroll", trackToc)
addEventListener("resize", trackToc)
const copy = e => {
const file = e.previousElementSibling.innerText
const importLine = file.includes("nomodule") ?
`<script type="text/javascript" src="https://cdn.jsdelivr.net/gh/vanjs-org/van/public/${file}"><\/script>` :
`import van from "https://cdn.jsdelivr.net/gh/vanjs-org/van/public/${file}"`
navigator.clipboard.writeText(importLine)
.then(() => e.querySelector(".tooltip").innerText = "Copied")
.catch(() => e.querySelector(".tooltip").innerText = "Copy failed")
}
const resetTooltip = e => e.querySelector(".tooltip").innerText = "Copy import line"
</script>
<script src="https://guru-widget.pages.dev/guru_widget.latest.min.js" data-text="Ask AI" data-link="https://gurubase.io/g/vanjs" data-bg-color="rgba(244, 67, 54, 0.3)" data-icon-url="/ask_ai.svg" data-font-color="#ffffff" data-margins="{"bottom": "1rem", "left": "1430px", "right": "unset"}">
</script>
<!-- Place this tag in your head or just before your close body tag. -->
<script async defer src="https://buttons.github.io/buttons.js"></script>
<link rel="prefetch" href="/code/prism-v1.js" as="script"><link rel="prefetch" href="https://www.gstatic.com/charts/loader.js" as="script"><link rel="prefetch" href="/code/diff.min.js" as="script"><link rel="prefetch" href="/code/van-1.5.2.nomodule.min.js" as="script"><link rel="prefetch" href="/code/van-x-0.6.2.nomodule.min.js" as="script"></body></html>