Skip to content

Commit

Permalink
readonly spreadsheet cells
Browse files Browse the repository at this point in the history
  • Loading branch information
ChrisShank committed Dec 13, 2024
1 parent a69840c commit d2feab9
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 18 deletions.
6 changes: 6 additions & 0 deletions demo/spreadsheet-shape-projection.html
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,16 @@
folk-shape {
background: rgb(187, 178, 178);
}

h1 {
margin: 0;
width: fit-content;
}
</style>
</head>
<body>
<folk-space-projector>
<h1>Spatial projection into a spreadsheet</h1>
<folk-shape x="100" y="100" width="50" height="50"></folk-shape>
<folk-shape x="100" y="200" width="50" height="50"></folk-shape>
<folk-shape x="100" y="300" width="50" height="50" rotation="45"></folk-shape>
Expand Down
31 changes: 24 additions & 7 deletions src/folk-space-projector.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { css, PropertyValues } from '@lit/reactive-element';
import { FolkBaseSet } from './folk-base-set';
import { FolkShape } from './folk-shape';
import { FolkSpreadsheet, FolkSpreadSheetCell, templateCells } from './folk-spreadsheet';
import { CellTemplate, FolkSpreadsheet, FolkSpreadSheetCell, templateCells } from './folk-spreadsheet';
import { DOMRectTransform } from './common/DOMRectTransform';

FolkShape.define();
Expand Down Expand Up @@ -120,17 +120,31 @@ export class FolkSpaceProjector extends FolkBaseSet {
super.update(changedProperties);

if (changedProperties.has('sourceElements')) {
const cells = templateCells(this.sourceElements.size, 5, {});
this.#spreadsheet.setHTMLUnsafe(cells);
const cells: Record<string, CellTemplate> = {};

let row = 1;
for (const el of this.sourceElements) {
if (!(el instanceof FolkShape)) {
cells[`A${row}`] = { readonly: true };
cells[`B${row}`] = { readonly: true };
cells[`C${row}`] = { readonly: true };
cells[`D${row}`] = { readonly: true };
cells[`E${row}`] = { readonly: true };
}
row++;
}

const html = templateCells(this.sourceElements.size, 5, cells);
this.#spreadsheet.setHTMLUnsafe(html);
}

if (this.sourcesMap.size !== this.sourceElements.size) return;

this.#lock = true;
const rects = this.sourceRects;
for (let i = 0; i < rects.length; i += 1) {
const row = i + 1;
const rect = rects[i];
let row = 1;
for (const el of this.sourceElements) {
const rect = this.sourcesMap.get(el)!;

if (rect instanceof DOMRectTransform) {
const { x, y } = rect.toParentSpace(rect.topLeft);
this.#spreadsheet.getCell('A', row)!.expression = Math.round(x);
Expand All @@ -143,8 +157,11 @@ export class FolkSpaceProjector extends FolkBaseSet {
this.#spreadsheet.getCell('B', row)!.expression = Math.round(rect.y);
this.#spreadsheet.getCell('C', row)!.expression = Math.round(rect.width);
this.#spreadsheet.getCell('D', row)!.expression = Math.round(rect.height);
this.#spreadsheet.getCell('E', row)!.expression = 0;
}
row += 1;
}

Promise.resolve().then(() => {
this.#lock = false;
});
Expand Down
41 changes: 30 additions & 11 deletions src/folk-spreadsheet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,10 @@ const styles = css`
justify-content: end;
}
::slotted(folk-cell[readonly]) {
color: grey;
}
::slotted(folk-cell:hover) {
outline: 1px solid #1b73e8;
z-index: 5;
Expand All @@ -132,21 +136,30 @@ export function relativeColumnName(name: string, num: number) {
return alphabet[index + num];
}

export function templateCells(numberOfRows: number, numberOfColumns: number, expressions: Record<string, string> = {}) {
const cells: string[] = [];
export interface CellTemplate {
expression?: string;
readonly?: boolean;
}

export function templateCells(numberOfRows: number, numberOfColumns: number, cells: Record<string, CellTemplate> = {}) {
const html: string[] = [];
for (let i = 0; i < numberOfRows; i += 1) {
for (let j = 0; j < numberOfColumns; j += 1) {
const column = getColumnName(j);
const row = i + 1;
const expression = expressions[`${column}${row}`];
cells.push(
`<folk-cell column="${column}" row="${row}" tabindex="0" ${
expression ? `expression="${expression}"` : ''
}></folk-cell>`
const { expression, readonly } = cells[`${column}${row}`] || {};
html.push(
`<folk-cell
column="${column}"
row="${row}"
tabindex="0"
${expression ? `expression="${expression}"` : ''}
${readonly ? 'readonly' : ''}
></folk-cell>`
);
}
}
return cells.join('\n');
return html.join('\n');
}

declare global {
Expand All @@ -168,7 +181,7 @@ export class FolkSpreadsheet extends HTMLElement {

#shadow = this.attachShadow({ mode: 'open' });

#textarea: HTMLTextAreaElement | null = null;
#textarea!: HTMLTextAreaElement;

#editedCell: FolkSpreadSheetCell | null = null;

Expand Down Expand Up @@ -326,7 +339,7 @@ export class FolkSpreadsheet extends HTMLElement {
}

#focusTextarea(cell: FolkSpreadSheetCell) {
if (this.#textarea === null) return;
if (cell.readonly) return;
this.#editedCell = cell;
const gridColumn = getColumnIndex(cell.column) + 2;
const gridRow = cell.row + 1;
Expand All @@ -339,7 +352,6 @@ export class FolkSpreadsheet extends HTMLElement {

#resetTextarea() {
if (this.#editedCell === null) return;
if (this.#textarea === null) return;
this.#textarea.style.setProperty('--text-column', '0');
this.#textarea.style.setProperty('--text-row', '0');
this.#editedCell.expression = this.#textarea.value;
Expand Down Expand Up @@ -471,6 +483,13 @@ export class FolkSpreadSheetCell extends HTMLElement {
this.#evaluate();
}

get readonly() {
return this.hasAttribute('readonly');
}
set readonly(readonly) {
readonly ? this.setAttribute('readonly', '') : this.removeAttribute('readonly');
}

#value: any;
get value() {
return this.#value;
Expand Down

0 comments on commit d2feab9

Please sign in to comment.