Published
Edited
Jun 24, 2020
Fork of Table
Insert cell
Insert cell
Insert cell
Insert cell
mutable data = [
["= 12", "", "= html`Min:`", "= _.min(A)"],
["= A1 ** 4", "= new Date(\"1996-10-15\")", "= html`Max:`", "= _.max(A)"],
["= A1 * A2", "= B2.getYear()", "= html`Sum:`", "= _.sum(A)"]
]
Insert cell
render(
this,
htm`<div style=${{ display: 'flex', paddingBottom: 12 }}>
<${Table}
value=${data}
onChange=${data => {
mutable data = data;
}}
selected_cell=${selected_cell}
onSelectedChange=${selected => {
mutable selected_cell = selected;
}}
/>
</div>`
)
Insert cell
safe = fn => {
try {
return [null, fn()];
} catch (error) {
return [error, null];
}
}
Insert cell
Table = ({ value: rows, onChange, selected_cell, onSelectedChange }) => {
let values = build_runtime(rows);

let reference_names = null;
let error = null;
if (selected_cell != null) {
try {
let column_index = selected_cell.column.charCodeAt(0) - 65;
let current_cell = rows[selected_cell.row - 1][column_index];
if (current_cell.startsWith('=')) {
let code = current_cell.slice(1);
let cell_ast = parser.parseCell(code);
reference_names = (cell_ast.references || [])
.map(x => x.name)
.filter(x => x.match(/[A-Z]\d?/));
}
} catch (err) {
error = err;
}
}

return htm`
<div class="list-table" style=${{ width: width }}>
<div class="row">
<div style=${{ width: 50 }}></div>

${rows[0].map(
(column, _column_index) => htm`
<div class="table-column-header" style=${{
width: 200
}}>${String.fromCharCode(65 + _column_index)}</div>
`
)}
</div>

${rows.map((row, _row_index) => {
let row_index = _row_index + 1;
return htm`<div class="row">
<div class="table-row-header" style=${{
width: 50
}}>${row_index}</div>

${row.map((value, _column_index) => {
let column_index = String.fromCharCode(65 + _column_index);
let cell_name = `${column_index}${row_index}`;
return htm`
<${Cell}
derived_from=${reference_names != null &&
reference_names.some(x => cell_name.startsWith(x))}
column=${column_index}
row=${row_index}
selected_cell=${selected_cell}
value=${value}
display=${values[`${column_index}${row_index}`]}
onClick=${() => {
onSelectedChange({ column: column_index, row: row_index });
}}
onBlur=${() => {
onSelectedChange(null);
}}
style=${{ width: 200 }}
onChange=${value => {
onChange(
immer.default(rows, draft => {
draft[_row_index][_column_index] = value;
})
);
}}
/>
`;
})}
</div>`;
})}
</div>
`;
}
Insert cell
Cell = ({
column,
row,
selected_cell,
style,
value,
display,
onChange,
onBlur,
derived_from,
...props
}) => {
let column_selected = selected_cell && selected_cell.column === column;
let row_selected = selected_cell && selected_cell.row === row;
let border = 'solid gray 1px';

let editting = column_selected && row_selected;

return htm`
<div
style=${{
border: border,
backgroundColor:
row_selected || column_selected ? 'rgba(0,0,0,.05)' : 'transparent',
boxShadow: derived_from ? 'inset 0 0 0 3px green' : 'none',
...style
}}
...${props}
>
${
editting
? htm`
<${CodeEditor}
value=${String(value)}
onChange=${value => {
onChange(value);
}}
onBlur=${() => {
onBlur();
}}
/>
`
: htm`<${Inspector} style=${{
pointerEvents: 'none'
}} value=${display} />`
}
</div>
`;
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
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