Public
Edited
Oct 1, 2023
Insert cell
Insert cell
Insert cell
Insert cell
html`You picked <b>${range}</b>!`
Insert cell
Insert cell
rmd = function (template) {
return (strings = [],...args) => {
const values = args.map(d => d.subscribe !=null ? html`${d}`: d);
return template(strings,...values);
}
}(md)
Insert cell
rmd`MD

- ${CountingComponent()}
- **${rangeSignal}**`
Insert cell
html`You picked <b>${rangeSignal}</b>!`
Insert cell
Insert cell
Insert cell
rangeSignal = {
// Create a signal
const s = signal(50);

// Update the signal on input events from the range slider
const changed = (e) => (s.value = e.target.value);
viewof range.addEventListener("input", changed);
invalidation.then(() => viewof range.removeEventListener("input", changed));

// Return the signal
return s;
}
Insert cell
Insert cell
{
const root = html`<div />`;
const dispose = mount(() => html`You picked <b>${rangeSignal}</b>!`, root);
invalidation.then(dispose);
return root;
}
Insert cell
Insert cell
{
const root = html`<div />`;
// When this cell is invalidated, run the dispose function returned by mount
invalidation.then(mount(() => html`<div>${CountingComponent()} and ${rangeSignal} and ${CountingComponent()}</div>`, root));
//invalidation.then(mount(CountingComponent, root));
return root;
}
Insert cell
CountingComponent = () => {
const count = signal(0);
const interval = setInterval(() => (count.value = count.value + 1), 1000);
const cleanup = () => {console.log("cleared...."); clearInterval(interval);}
return onUnmount(html`<div>Count value is <b>${count}</b>!</div>`, cleanup);
}
Insert cell
Insert cell
{
const root = html`<div />`;
invalidation.then(mount(TodoList, root));
return root;
}
Insert cell
function TodoList() {
const todos = signal([]);
const text = signal("");
const setText = (e) => (text.value = e.target.value);
const addTodo = (e) => {
e.preventDefault();
if (text.value === "") return;
todos.value = todos.value.concat({ text: text.value });
text.value = "";
};
return html`
<form onsubmit=${addTodo}>
<label>
<div><b><small>Add to-do:</small></b></div>
<input value=${text} oninput=${setText} />
</label>
<button type="submit">Add</button>
<ul>
${computed(() => {
const todosValue = todos.value;
return todosValue.map((todo) => html`<li>${todo.text}</li>`);
})}
</ul>
</form>
`;
}
Insert cell
Insert cell
Insert cell
Insert cell
{
const currentTime = rangeSignal
const slider = Inputs.range([0, 10], { step: 1 });
const formatSatisfaction = (v) => {
return v < 3 ? ":-(" : v < 5 ? ":-|" : v < 7 ? ":-)" : ":-*";
// return [v < 3 ? ":-(" : v < 5 ? ":-|" : v < 7 ? ":-)" : ":-*", " ", v];
};

return rmd`
This markdown cell shows how static markdown can be combined with dynamic values without cells reloading.

Current GMT Time: ${currentTime}

| Your satisfaction level is from 10)
|-------------
| ${slider} | <big>a</big>

|Please leave a comment: | Raw content of your comment:
|------------------------|-------------
| | <pre style="max-height: 150px; overflow: auto; font-size: 0.5em;">${commentsSignal}</pre>


|Your Formatted Comment Preview:
|-------------------------------------
| ${computed(() => md([commentsSignal.value]))}

*Thank you for watching!*

---
`;
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
rhtl = import(await FileAttachment("bundle@1.js").url())
Insert cell
listDiff = function(opts) {
//The MIT License (MIT)

//Copyright (c) 2015 Simon Friis Vindum

var actions = [],
aIdx = {},
bIdx = {},
a = opts.old,
b = opts.cur,
key = opts.extractKey,
i, j;
// Create a mapping from keys to their position in the old list
for (i = 0; i < a.length; i++) {
aIdx[key(a[i])] = i;
}
// Create a mapping from keys to their position in the new list
for (i = 0; i < b.length; i++) {
bIdx[key(b[i])] = i;
}
for (i = j = 0; i !== a.length || j !== b.length;) {
var aElm = a[i], bElm = b[j];
if (aElm === null) {
// This is a element that has been moved to earlier in the list
i++;
} else if (b.length <= j) {
// No more elements in new, this is a delete
opts.remove(i);
i++;
} else if (a.length <= i) {
// No more elements in old, this is an addition
opts.add(bElm, i);
j++;
} else if (key(aElm) === key(bElm)) {
// No difference, we move on
i++; j++;
} else {
// Look for the current element at this location in the new list
// This gives us the idx of where this element should be
var curElmInNew = bIdx[key(aElm)];
// Look for the the wanted elment at this location in the old list
// This gives us the idx of where the wanted element is now
var wantedElmInOld = aIdx[key(bElm)];
if (curElmInNew === undefined) {
// Current element is not in new list, it has been removed
opts.remove(i);
i++;
} else if (wantedElmInOld === undefined) {
// New element is not in old list, it has been added
opts.add(bElm, i);
j++;
} else {
// Element is in both lists, it has been moved
opts.move(wantedElmInOld, i);
a[wantedElmInOld] = null;
j++;
}
}
}
return actions;
};
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more