Public
Edited
Jun 27, 2020
Fork of Table
1 star
Insert cell
Insert cell
import {
notebook,
notebook_styles
} from "@dralletje/functions-are-notebooks-with-custom-runtime"
Insert cell
ObservableHq = require("@observablehq/runtime@4")
Insert cell
notebook_styles
Insert cell
Insert cell
mutable selected_cell = null
Insert cell
mutable codes = ({
can_drink: `age > 18`,
name: `[firstName, lastName].filter(Boolean).join(' ')`,
thing: `{ let test = 2; return test }`
})
Insert cell
class Ref {
constructor(table_name, id) {
this.table_name = table_name;
this.id = id;
return new Proxy(this, {
get: () => {
}
})
}
}
Insert cell
Person = TableRuntime({
rows: [
{ id: 0, name: 'Michiel', age: 23, rolemodel: new Ref('Person', 1) },
{ id: 1, name: 'Jelmar', age: 23, rolemodel: null },
{ id: 2, name: 'Laurens', age: 25, rolemodel: null }
],
columns: [
{ name: 'name', type: 'constant' },
{ name: 'age', type: 'constant' },
{ name: 'rolemodel', type: 'reference', to: 'Person' },
{ name: 'can_drink', type: 'derive', code: 'age > 22' }
]
})
Insert cell
is_internal_property = key =>
key === 'then' ||
key === 'constructor' ||
key === 'next' ||
typeof key === 'symbol'
Insert cell
TableRuntime = ({ rows, columns }) => {
return new Proxy(
{ rows, columns },
{
get: (target, key) => {
if (is_internal_property(key)) return null;

if (key === 'rows') return rows;
if (key === 'columns') return columns;
console.log('key:', key);
return key;
}
}
);
}
Insert cell
tables = ({
Person: Person
})
Insert cell
get_column = (row, column) => {
if (column.type === 'constant') {
return row[column.name];
} else if (column.type === 'derive') {
return column.code;
} else if (column.type === 'reference') {
}
}
Insert cell
get_row = async (runtime, id) => {
let row = runtime.rows.find(x => x.id === id);

return Object.fromEntries(
await Promise.all(
runtime.columns.map(column => [column.name, get_column(row, column)])
)
);
}
Insert cell
get_row(Person, 2)
Insert cell
Model = ({ name, columns }) => {
return new Proxy(
{},
{
get: (target, key) => {
if (['then', 'next'].includes(key)) return null;
if (columns[key]) {
return columns[key];
} else {
throw new Error(`Unknown key '${key}' used on table '${name}'`);
}
}
}
);
}
Insert cell
Company = Model({
name: 'Company',
columns: { topics: company => [1, 2, 3] }
})
Insert cell
Topic = Model({
name: 'Company',
columns: { new__todos: topic => [2, 3, 4] }
})
Insert cell
_ = require('lodash')
Insert cell
fn = client => {
let company = client.company;
let topics = company[Company.topics];
let todos = _.flatMap(topics.map(topic => topic[Topic.new__todos]));
return todos;
}
Insert cell
fn({
company: {
[Company.topics]: [{ [Topic.new__todos]: [2, 3, 4] }]
}
})
Insert cell
derive_from_row = ({ column, row }) => {
if (column.type === 'constant') {
return row[column.name];
} else {
let parsed = code_to_derive(column.code);
}
}
Insert cell
Insert cell
x = ({ hey: 10 })
Insert cell
Insert cell
Notebook = ({ item, codes, column, onCodesChange, ...props }) => {
let ref = React.useRef();
let value = React.useRef(new Mutable(item));

React.useEffect(() => {
let code_with_derived = `
${Object.keys(item)
.map(key => `${key} = row.${key};`)
.join('\n\n')}

${Object.entries(codes)
.map(([key, code]) => `${key} = ${code}`)
.join('\n\n')}
`;

value.current.value = item;
let hmmm = notebook_direct(code_with_derived)({
// replacements: {
row: value.current.generator
// },
// onCodeChange: changed_cell => {
// let new_codes = { ...codes };
// delete new_codes[changed_cell.old_name];
// new_codes[changed_cell.new_name] = changed_cell.code.replace(
// /^[^=]+=/,
// ''
// );

// console.log('new_codes:', new_codes);
// onCodesChange(new_codes);
// }
});
if (ref.current.firstChild) {
ref.current.firstChild.remove();
}
ref.current.appendChild(hmmm);
}, [codes]);

React.useEffect(() => {
value.current.value = item;
console.log('value.current.value:', value.current.value);
}, [item, codes]);

return htm`<div ref=${ref} ...${props} />`;
}
Insert cell
Row = ({ data, index, selected, onSelectedChange, codes, onCodeChange }) => {
let string = `
${Object.entries(codes)
.map(([key, code]) => `${key} = ${code};`)
.join('\n\n')}
`;
let result = notebook(string)({ ...data }, false);

return htm`<tr>
${keys.map(
column => htm`
<${Cell}
column=${column}
row=${index}
value=${data[column]}
selected_cell=${selected}
onClick=${() => {
onSelectedChange({ column, row: index });
}}
/>
`
)}

${Object.entries(codes).map(
([column, code]) => htm`
<${Cell}
column=${column}
row=${index}
selected_cell=${selected}
value=${result[column]}
onClick=${() => {
onSelectedChange({ column, row: index });
}}
/>
`
)}
</tr>`;
}
Insert cell
Table = ({ selected_cell, onSelectedChange, codes, onCodesChange }) => {
return htm`
<table class="list-table" style=${{ width: width / 2 }}>
<tr>
${keys.map(key => htm`<td style=${{ fontWeight: 'bold' }}>${key}</td>`)}
${Object.keys(codes).map(
key => htm`<td style=${{ fontWeight: 'bold' }}>${key}</td>`
)}
</tr>
${array.map(
(data, index) =>
htm`<${Row}
onSelectedChange=${onSelectedChange}
data=${data}
index=${index}
selected=${selected_cell} codes=${codes}
onCodesChange=${onCodesChange}
/>`
)}
</table>
${selected_cell &&
codes[selected_cell.column] &&
htm`
<${Notebook}
style=${{ width: width / 2 }}
item=${array[selected_cell.row]}
codes=${codes}
column=${selected_cell.column}
onCodesChange=${onCodesChange}
/>
`}
`;
}
Insert cell
Insert cell
Cell = ({ column, row, selected_cell, value, ...props }) => {
let column_selected = selected_cell && selected_cell.column === column;
let row_selected = selected_cell && selected_cell.row === row;
let border = 'solid gray 1px';

return htm`
<td
style=${{
// border: 'solid 1px transparent',
// borderTop: row_selected ? border : 'none',
// borderBottom: row_selected ? border : 'none',
// borderLeft: column_selected ? border : 'none',
// borderRight: column_selected ? border : 'none',
border: border,
backgroundColor:
row_selected || column_selected ? 'rgba(0,0,0,.05)' : 'transparent'
}}
...${props}
>
<${Inspector} value=${value} />
</td>
`;
}
Insert cell
notebook_direct = code => {
let string_parts = [code];
string_parts.raw = [code];
return notebook({})(string_parts);
}
Insert cell
Inspector = ({ value }) => {
let container_ref = React.useRef();
let inspector = React.useRef();

React.useEffect(() => {
if (inspector.current == null) {
inspector.current = new ObservableHq.Inspector(container_ref.current);
}
inspector.current.fulfilled(value);
}, [value]);
return htm`<div ref=${container_ref} />`;
}
Insert cell
code_to_derive = code_or_ast => {
try {
let cell_ast =
typeof code_or_ast === "string"
? parser.parseCell(code_or_ast)
: code_or_ast;
let cell_code =
typeof code_or_ast === "string"
? code_or_ast.trim()
: code_or_ast.input.slice(code_or_ast.start, code_or_ast.end).trim();

let reference_names = (cell_ast.references || []).map(x => x.name);

if (cell_ast.id == null) {
return {
using: reference_names,
derive: new Function(
...reference_names,
`return ` + generate(cell_ast.body)
)
};
} else if (cell_ast.body.type === 'BlockStatement') {
return {
using: reference_names,
derive: new Function(...reference_names, generate(cell_ast.body))
};
} else if (cell_ast.body.type === 'ImportDeclaration') {
throw new Error('Imports not yet supported!');
let import_ast = cell_ast.body;
return import_ast.specifiers.map(specifier => {
return {
define: specifier.local.name,
module: import_ast.source.value
};
});
} else {
return {
using: reference_names,
derive: new Function(
...reference_names,
`return ` + generate(cell_ast.body)
)
};
}
} catch (error) {
error.stack = '';
return {
using: [],
derive: () => error
};
}
}
Insert cell
Insert cell
Insert cell
Insert cell
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