@blokkli/editor 2.0.0-alpha.15 → 2.0.0-alpha.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,4 +1,4 @@
1
- export default function (callback: (entries: IntersectionObserverEntry[]) => void): {
1
+ export default function (callback: (entries: IntersectionObserverEntry[]) => void, options?: IntersectionObserverInit): {
2
2
  observe: (el: HTMLElement) => void;
3
3
  unobserve: (el: HTMLElement) => void;
4
4
  init: () => void;
@@ -1,9 +1,10 @@
1
- export default function(callback) {
1
+ export default function(callback, options = {}) {
2
2
  let observer = null;
3
3
  let collected = [];
4
4
  function init() {
5
5
  observer = new IntersectionObserver(callback, {
6
- threshold: 0
6
+ threshold: 0,
7
+ ...options
7
8
  });
8
9
  for (const el of collected) {
9
10
  observer.observe(el);
@@ -139,7 +139,12 @@ export default function(ui, debug, definitions) {
139
139
  }
140
140
  }
141
141
  }
142
- const intersectionObserver = useDelayedIntersectionObserver(intersectionCallback);
142
+ const intersectionObserver = useDelayedIntersectionObserver(
143
+ intersectionCallback,
144
+ {
145
+ rootMargin: "400px 0px 400px 0px"
146
+ }
147
+ );
143
148
  const registeredFieldTypes = computed(() => {
144
149
  const fields = Object.values(registeredFields);
145
150
  const found = /* @__PURE__ */ new Set();
@@ -8,10 +8,16 @@ type RectangleBufferRect = Rectangle & {
8
8
  };
9
9
  type RectangleBufferCollectorOptions = {
10
10
  padding?: number;
11
+ deferredMode?: boolean;
11
12
  };
12
13
  type PlacedRectangle = Rectangle & {
13
14
  originalY: number;
14
15
  };
16
+ type PendingRect<T> = {
17
+ rect: Omit<T, 'index'>;
18
+ type: number;
19
+ checkOverlap: boolean;
20
+ };
15
21
  export declare class RectangleBufferCollector<T extends RectangleBufferRect> {
16
22
  gl?: WebGLRenderingContext;
17
23
  added: Set<string>;
@@ -26,10 +32,13 @@ export declare class RectangleBufferCollector<T extends RectangleBufferRect> {
26
32
  index: number;
27
33
  bufferInfo: BufferInfo | null;
28
34
  placedRects: PlacedRectangle[];
29
- constructor(gl?: WebGLRenderingContext, _options?: RectangleBufferCollectorOptions);
35
+ deferredMode: boolean;
36
+ pendingRects: PendingRect<T>[];
37
+ constructor(gl?: WebGLRenderingContext, options?: RectangleBufferCollectorOptions);
30
38
  reset(): void;
31
- getIdealPosition(x: number, y: number, width: number, height: number): Rectangle;
39
+ getIdealPosition(x: number, y: number, width: number, height: number, isEmptyField?: boolean): Rectangle;
32
40
  addRectangle(rect: Omit<T, 'index'>, type: number, checkOverlap?: boolean): void;
41
+ processPendingRects(): void;
33
42
  getIndex(id: string): number | undefined;
34
43
  updateRectangle(): void;
35
44
  createBufferInfo(): BufferInfo | null;
@@ -14,12 +14,18 @@ export class RectangleBufferCollector {
14
14
  index = 0;
15
15
  bufferInfo = null;
16
16
  placedRects = [];
17
- constructor(gl, _options) {
17
+ deferredMode = false;
18
+ pendingRects = [];
19
+ constructor(gl, options) {
18
20
  this.gl = gl;
21
+ this.deferredMode = options?.deferredMode || false;
19
22
  }
20
23
  reset() {
21
24
  this.added = /* @__PURE__ */ new Set();
22
- this.rects = {};
25
+ if (!this.deferredMode) {
26
+ this.rects = {};
27
+ }
28
+ this.placedRects = [];
23
29
  this.positions = [];
24
30
  this.indices = [];
25
31
  this.rectId = [];
@@ -29,8 +35,10 @@ export class RectangleBufferCollector {
29
35
  this.radius = [];
30
36
  this.index = 0;
31
37
  this.bufferInfo = null;
38
+ this.pendingRects = [];
32
39
  }
33
- getIdealPosition(x, y, width, height) {
40
+ getIdealPosition(x, y, width, height, isEmptyField = false) {
41
+ const MIN_HEIGHT = 5;
34
42
  const rect = {
35
43
  x,
36
44
  y,
@@ -40,19 +48,63 @@ export class RectangleBufferCollector {
40
48
  };
41
49
  const intersections = [];
42
50
  for (let i = 0; i < this.placedRects.length; i++) {
43
- if (intersects(rect, this.placedRects[i])) {
44
- intersections.push(this.placedRects[i]);
51
+ const placed = this.placedRects[i];
52
+ const testRect = { ...rect, height: Math.max(height, MIN_HEIGHT) };
53
+ const testPlaced = {
54
+ ...placed,
55
+ height: Math.max(placed.height, MIN_HEIGHT)
56
+ };
57
+ if (intersects(testRect, testPlaced)) {
58
+ intersections.push(placed);
45
59
  }
46
60
  }
47
61
  if (intersections.length === 0) {
48
62
  this.placedRects.push(rect);
49
63
  return rect;
50
64
  }
51
- intersections.sort((a, b) => b.originalY - a.originalY);
65
+ intersections.sort((a, b) => a.originalY - b.originalY);
66
+ if (isEmptyField) {
67
+ for (let i = 0; i < intersections.length; i++) {
68
+ const existingRect = intersections[i];
69
+ const rectsAbove = this.placedRects.filter(
70
+ (r) => r.y + r.height <= existingRect.y && r.x < x + width && r.x + r.width > x
71
+ );
72
+ let prevBottom = 0;
73
+ if (rectsAbove.length > 0) {
74
+ prevBottom = Math.max(...rectsAbove.map((r) => r.y + r.height));
75
+ }
76
+ const nextTop = existingRect.y;
77
+ const availableSpace = nextTop - prevBottom;
78
+ if (availableSpace >= height) {
79
+ const centeredY = prevBottom + (availableSpace - height) / 2;
80
+ const centeredRect = { ...rect, y: centeredY };
81
+ let hasIntersection = false;
82
+ for (const placed of this.placedRects) {
83
+ const testCentered = {
84
+ ...centeredRect,
85
+ height: Math.max(height, MIN_HEIGHT)
86
+ };
87
+ const testPlaced = {
88
+ ...placed,
89
+ height: Math.max(placed.height, MIN_HEIGHT)
90
+ };
91
+ if (intersects(testCentered, testPlaced)) {
92
+ hasIntersection = true;
93
+ break;
94
+ }
95
+ }
96
+ if (!hasIntersection) {
97
+ rect.y = centeredY;
98
+ this.placedRects.push(rect);
99
+ return rect;
100
+ }
101
+ }
102
+ }
103
+ }
52
104
  for (let i = 0; i < intersections.length; i++) {
53
105
  const existingRect = intersections[i];
54
106
  let iterations = 0;
55
- const direction = y > existingRect.originalY ? -1 : 1;
107
+ const direction = y < existingRect.originalY ? -1 : 1;
56
108
  while (intersects(rect, existingRect) && iterations < 10) {
57
109
  rect.y = y + direction * (10 * (iterations + 1));
58
110
  iterations++;
@@ -65,6 +117,10 @@ export class RectangleBufferCollector {
65
117
  return rect;
66
118
  }
67
119
  addRectangle(rect, type, checkOverlap = false) {
120
+ if (this.deferredMode) {
121
+ this.pendingRects.push({ rect, type, checkOverlap });
122
+ return;
123
+ }
68
124
  const { x, y, width, height } = checkOverlap ? this.getIdealPosition(rect.x, rect.y, rect.width, rect.height) : rect;
69
125
  this.positions.push(
70
126
  x,
@@ -119,6 +175,105 @@ export class RectangleBufferCollector {
119
175
  this.added.add(rect.id);
120
176
  this.index++;
121
177
  }
178
+ processPendingRects() {
179
+ if (!this.deferredMode) {
180
+ return;
181
+ }
182
+ if (!this.pendingRects.length) {
183
+ return;
184
+ }
185
+ const sortedPending = [...this.pendingRects].sort(
186
+ (a, b) => a.rect.y - b.rect.y
187
+ );
188
+ const passes = [
189
+ sortedPending.filter((p) => !p.rect.id.includes(":empty:")),
190
+ // Non-empty rects
191
+ sortedPending.filter((p) => p.rect.id.includes(":empty:"))
192
+ // Empty rects
193
+ ];
194
+ for (const pass of passes) {
195
+ for (const { rect, type, checkOverlap } of pass) {
196
+ if (this.added.has(rect.id)) {
197
+ continue;
198
+ }
199
+ let finalPosition;
200
+ const existing = this.rects[rect.id];
201
+ if (existing) {
202
+ finalPosition = {
203
+ x: existing.x,
204
+ y: existing.y,
205
+ width: existing.width,
206
+ height: existing.height
207
+ };
208
+ } else if (checkOverlap) {
209
+ const isEmptyField = rect.id.includes(":empty:");
210
+ finalPosition = this.getIdealPosition(
211
+ rect.x,
212
+ rect.y,
213
+ rect.width,
214
+ rect.height,
215
+ isEmptyField
216
+ );
217
+ } else {
218
+ finalPosition = {
219
+ x: rect.x,
220
+ y: rect.y,
221
+ width: rect.width,
222
+ height: rect.height
223
+ };
224
+ }
225
+ const { x, y, width, height } = finalPosition;
226
+ this.positions.push(
227
+ x,
228
+ y,
229
+ // Lower left corner
230
+ 0,
231
+ x + width,
232
+ y,
233
+ // Lower right corner
234
+ 1,
235
+ x + width,
236
+ y + height,
237
+ // Upper right corner
238
+ 2,
239
+ x,
240
+ y + height,
241
+ // Upper left corner
242
+ 3
243
+ );
244
+ const baseIndex = 4 * this.index;
245
+ this.indices.push(
246
+ baseIndex,
247
+ baseIndex + 1,
248
+ baseIndex + 2,
249
+ baseIndex,
250
+ baseIndex + 2,
251
+ baseIndex + 3
252
+ );
253
+ const r = rect.radius || [4, 4, 4, 4];
254
+ this.radius.push(...r, ...r, ...r, ...r);
255
+ this.rectId.push(this.index, this.index, this.index, this.index);
256
+ this.types.push(type, type, type, type);
257
+ this.quad.push(x, y, width, height);
258
+ this.quad.push(x, y, width, height);
259
+ this.quad.push(x, y, width, height);
260
+ this.quad.push(x, y, width, height);
261
+ const state = rect.state || 0;
262
+ this.state.push(state, state, state, state);
263
+ this.rects[rect.id] = {
264
+ ...rect,
265
+ index: this.index,
266
+ x,
267
+ y,
268
+ width,
269
+ height
270
+ };
271
+ this.added.add(rect.id);
272
+ this.index++;
273
+ }
274
+ this.pendingRects = [];
275
+ }
276
+ }
122
277
  getIndex(id) {
123
278
  return this.rects[id]?.index;
124
279
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blokkli/editor",
3
- "version": "2.0.0-alpha.15",
3
+ "version": "2.0.0-alpha.16",
4
4
  "description": "Interactive page building experience for Nuxt",
5
5
  "repository": "blokkli/editor",
6
6
  "type": "module",