Skip to content

Commit 8118b76

Browse files
authored
sync-3 (#46)
* refactor attempt * fixes * simplify * tad simpler * simpler again * simplerrr * patch resolution architecture instead of adhoc implicit structure * simplr * simpler * simplerrrrrr * cleanup * faster * crude double-reflection to fix old demo bug * fix the stuff i broke * minor code quality bits * unexport * types * use HAST types * types cleanup
1 parent 4cd6ca1 commit 8118b76

22 files changed

+517
-1001
lines changed

package-lock.json

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/dom/src/CustomAttribute.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,16 @@ export class CustomAttribute<E extends Element = Element> {
44
static define() {
55
if (customAttributes.isDefined(this.attributeName)) return;
66

7-
customAttributes.define(this.attributeName, this);
7+
// Auto-generate accessor on Element.prototype: folk-sync → folkSync
8+
const attrName = this.attributeName;
9+
const propName = attrName.replace(/-([a-z])/g, (_, c) => c.toUpperCase());
10+
Object.defineProperty(Element.prototype, propName, {
11+
get() {
12+
return customAttributes.get(this, attrName);
13+
},
14+
});
15+
16+
customAttributes.define(attrName, this);
817
}
918

1019
readonly #ownerElement: E;

packages/labs/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,7 @@
116116
"webcola": "^3.4.0"
117117
},
118118
"devDependencies": {
119+
"@types/hast": "^3.0.4",
119120
"@types/wicg-file-system-access": "^2023.10.7",
120121
"expect": "^29.7.0",
121122
"mitata": "^1.0.34",

packages/labs/src/BiMap.ts

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
/** Bidirectional map that keeps two maps in sync */
2+
export class BiMap<A, B> {
3+
#aToB = new Map<A, B>();
4+
#bToA = new Map<B, A>();
5+
6+
set(a: A, b: B): void {
7+
this.#aToB.set(a, b);
8+
this.#bToA.set(b, a);
9+
}
10+
11+
getByA(a: A): B | undefined {
12+
return this.#aToB.get(a);
13+
}
14+
15+
getByB(b: B): A | undefined {
16+
return this.#bToA.get(b);
17+
}
18+
19+
hasA(a: A): boolean {
20+
return this.#aToB.has(a);
21+
}
22+
23+
hasB(b: B): boolean {
24+
return this.#bToA.has(b);
25+
}
26+
27+
deleteByA(a: A): boolean {
28+
const b = this.#aToB.get(a);
29+
if (b === undefined) return false;
30+
this.#aToB.delete(a);
31+
this.#bToA.delete(b);
32+
return true;
33+
}
34+
35+
deleteByB(b: B): boolean {
36+
const a = this.#bToA.get(b);
37+
if (a === undefined) return false;
38+
this.#bToA.delete(b);
39+
this.#aToB.delete(a);
40+
return true;
41+
}
42+
43+
clear(): void {
44+
this.#aToB.clear();
45+
this.#bToA.clear();
46+
}
47+
}

packages/labs/src/dom-json.ts

Lines changed: 0 additions & 41 deletions
This file was deleted.

packages/labs/src/folk-lsp-attribute.ts

Lines changed: 7 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { CustomAttribute, customAttributes } from '@folkjs/dom/CustomAttribute';
1+
import { CustomAttribute } from '@folkjs/dom/CustomAttribute';
22
import { css, html } from '@folkjs/dom/tags';
33
import {
44
CompletionRequest,
@@ -19,6 +19,12 @@ import { RefID } from './utils/ref-id';
1919
export const VALID_LSP_LANGUAGES = ['js', 'ts', 'json', 'css'] as const;
2020
export type LSPLanguage = (typeof VALID_LSP_LANGUAGES)[number];
2121

22+
declare global {
23+
interface Element {
24+
folkLsp: FolkLSPAttribute | undefined;
25+
}
26+
}
27+
2228
// TODOs
2329
// incremental updates
2430
// - input event only tells us what text is added.
@@ -69,18 +75,6 @@ class LanguageServerPool {
6975
export class FolkLSPAttribute extends CustomAttribute<HTMLElement> {
7076
static override attributeName = 'folk-lsp';
7177

72-
static override define() {
73-
if (!customAttributes.isDefined(this.attributeName)) {
74-
Object.defineProperty(Element.prototype, 'lsp', {
75-
get() {
76-
return customAttributes.get(this, FolkLSPAttribute.attributeName) as FolkLSPAttribute | undefined;
77-
},
78-
});
79-
}
80-
81-
super.define();
82-
}
83-
8478
static #highlightRegistry = {
8579
'folk-lsp-error': new Highlight(),
8680
'folk-lsp-warning': new Highlight(),

packages/labs/src/folk-observer.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -182,18 +182,18 @@ export class FolkObserver {
182182
if (target instanceof FolkShape) {
183183
target.addEventListener('transform', this.#onTransform);
184184
callback({ target, contentRect: target.getTransformDOMRect() });
185-
} else if (target.shape !== undefined) {
185+
} else if (target.folkShape !== undefined) {
186186
target.addEventListener('transform', this.#onTransform);
187-
callback({ target, contentRect: target.shape as unknown as DOMRectReadOnly });
187+
callback({ target, contentRect: target.folkShape as unknown as DOMRectReadOnly });
188188
} else {
189189
this.#vo.observe(target);
190190
}
191191
} else {
192192
const contentRect =
193193
target instanceof FolkShape
194194
? target.getTransformDOMRect()
195-
: target.shape !== undefined
196-
? (target.shape as unknown as DOMRectReadOnly)
195+
: target.folkShape !== undefined
196+
? (target.folkShape as unknown as DOMRectReadOnly)
197197
: target.getBoundingClientRect();
198198
callback({ target, contentRect });
199199
}
@@ -223,7 +223,7 @@ export class FolkObserver {
223223
callbacks.delete(callback);
224224

225225
if (callbacks.size === 0) {
226-
if (target instanceof FolkShape || target.shape !== undefined) {
226+
if (target instanceof FolkShape || target.folkShape !== undefined) {
227227
target.removeEventListener('transform', this.#onTransform);
228228
} else {
229229
this.#vo.unobserve(target);

packages/labs/src/folk-region.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -42,19 +42,19 @@ export class FolkRegion extends ReactiveElement {
4242
#onTransform = (event: TransformEvent) => {
4343
const el = event.target as Element;
4444

45-
if (this === el || this.shape === undefined || el.shape === undefined) return;
45+
if (this === el || this.folkShape === undefined || el.folkShape === undefined) return;
4646

47-
const overlap = R.overlap(getAbsoluteRectangle(this.shape), getAbsoluteRectangle(el.shape));
47+
const overlap = R.overlap(getAbsoluteRectangle(this.folkShape), getAbsoluteRectangle(el.folkShape));
4848
if (this.contains(el) && overlap < 0.49) {
4949
this.parentElement!.moveBefore!(el, null);
5050

51-
el.shape!.x += this.shape!.x;
52-
el.shape!.y += this.shape!.y;
51+
el.folkShape!.x += this.folkShape!.x;
52+
el.folkShape!.y += this.folkShape!.y;
5353
} else if (!this.contains(el) && overlap > 0.51) {
5454
this.moveBefore!(el, null);
5555

56-
el.shape!.x -= this.shape!.x;
57-
el.shape!.y -= this.shape!.y;
56+
el.folkShape!.x -= this.folkShape!.x;
57+
el.folkShape!.y -= this.folkShape!.y;
5858
}
5959
};
6060
}

packages/labs/src/folk-shape-attribute.ts

Lines changed: 6 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { IPointTransform, TransformStack } from '@folkjs/canvas';
2-
import { CustomAttribute, customAttributes } from '@folkjs/dom/CustomAttribute';
2+
import { CustomAttribute } from '@folkjs/dom/CustomAttribute';
33
import { ResizeManager } from '@folkjs/dom/ResizeManger';
44
import { css } from '@folkjs/dom/tags';
55
import * as M from '@folkjs/geometry/Matrix2D';
@@ -11,30 +11,20 @@ import { ShapeConnectedEvent, ShapeDisconnectedEvent, TransformEvent, type Shape
1111

1212
declare global {
1313
interface Element {
14-
shape: FolkShapeAttribute | undefined;
14+
folkShape: FolkShapeAttribute | undefined;
1515
}
1616
}
1717

1818
const resizeManager = new ResizeManager();
1919

20+
// Define FolkShapeOverlay before FolkShapeAttribute class initialization
21+
// since FolkShapeAttribute.#overlay uses document.createElement('folk-shape-overlay')
22+
FolkShapeOverlay.define();
23+
2024
// TODO: if an auto position/size is defined as a style then we should probably save it and set it back
2125
export class FolkShapeAttribute extends CustomAttribute implements Shape2DObject, IPointTransform {
2226
static override attributeName = 'folk-shape';
2327

24-
static override define() {
25-
if (!customAttributes.isDefined(this.attributeName)) {
26-
FolkShapeOverlay.define();
27-
28-
Object.defineProperty(Element.prototype, 'shape', {
29-
get() {
30-
return customAttributes.get(this, FolkShapeAttribute.attributeName) as FolkShapeAttribute | undefined;
31-
},
32-
});
33-
}
34-
35-
super.define();
36-
}
37-
3828
static #overlay = document.createElement('folk-shape-overlay');
3929

4030
static styles = css`

packages/labs/src/folk-shape-overlay.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -258,9 +258,9 @@ export class FolkShapeOverlay extends ReactiveElement {
258258
if (this.#shape === null) {
259259
const el = document.querySelector('[folk-shape]');
260260

261-
if (el?.shape === undefined) return;
261+
if (el?.folkShape === undefined) return;
262262

263-
this.open(el.shape, el as HTMLElement);
263+
this.open(el.folkShape, el as HTMLElement);
264264
}
265265

266266
this.focus();
@@ -330,7 +330,7 @@ export class FolkShapeOverlay extends ReactiveElement {
330330
}
331331

332332
if (event instanceof FocusEvent) {
333-
if (event.relatedTarget !== this.shape?.ownerElement) {
333+
if (event.relatedTarget !== this.#ownerElement) {
334334
this.#spatialTabMode = false;
335335
this.close();
336336
}

0 commit comments

Comments
 (0)