@juo/blocks 1.4.5 → 1.4.6

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 +1 @@
1
- {"version":3,"file":"components.d.ts","sourceRoot":"","sources":["../../src/editor/components.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAgJ9C,qBAAa,YAAa,SAAQ,WAAW;IAC3C,OAAO,CAAC,KAAK,CAA8B;IAC3C,OAAO,CAAC,YAAY,CAAwB;IAC5C,OAAO,CAAC,WAAW,CAA4B;IAC/C,OAAO,CAAC,WAAW,CAA4B;IAC/C,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,uBAAuB,CAA0C;IAEzE,MAAM,KAAK,kBAAkB,aAE5B;;IASD,OAAO,CAAC,WAAW;IAMnB,OAAO,CAAC,aAAa;IA0ErB,iBAAiB;IAWjB,oBAAoB;IAUpB,OAAO,CAAC,UAAU;IAQlB,OAAO,CAAC,QAAQ;IAahB,OAAO,CAAC,SAAS;IAWjB,QAAQ,CAAC,KAAK,EAAE,aAAa;IAQ7B,OAAO,CAAC,iBAAiB;IAazB;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAaxB,OAAO,CAAC,iBAAiB;CAmD1B;AAMD,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,0BAA0B,EAAE,YAAY,CAAC;KAC1C;CACF"}
1
+ {"version":3,"file":"components.d.ts","sourceRoot":"","sources":["../../src/editor/components.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AA6O9C,qBAAa,YAAa,SAAQ,WAAW;IAC3C,OAAO,CAAC,KAAK,CAA8B;IAC3C,OAAO,CAAC,YAAY,CAAwB;IAC5C,OAAO,CAAC,WAAW,CAA4B;IAC/C,OAAO,CAAC,WAAW,CAA4B;IAC/C,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,uBAAuB,CAA0C;IAEzE,MAAM,KAAK,kBAAkB,aAE5B;;IASD,OAAO,CAAC,WAAW;IAMnB,OAAO,CAAC,aAAa;IAiFrB,iBAAiB;IAWjB,oBAAoB;IAUpB,OAAO,CAAC,UAAU;IAQlB,OAAO,CAAC,QAAQ;IAahB,OAAO,CAAC,SAAS;IAWjB,QAAQ,CAAC,KAAK,EAAE,aAAa;IAQ7B,OAAO,CAAC,iBAAiB;IASzB;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAaxB,OAAO,CAAC,iBAAiB;CAmD1B;AAMD,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,0BAA0B,EAAE,YAAY,CAAC;KAC1C;CACF"}
@@ -0,0 +1 @@
1
+ //# sourceMappingURL=components.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"components.test.d.ts","sourceRoot":"","sources":["../../src/editor/components.test.ts"],"names":[],"mappings":"AAEA,OAAO,cAAc,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../../src/editor/main.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,UAAU,EACf,KAAK,aAAa,EAGnB,MAAM,aAAa,CAAC;AAQrB,cAAc,YAAY,CAAC;AAC3B,cAAc,UAAU,CAAC;AACzB,cAAc,WAAW,CAAC;AAC1B,cAAc,cAAc,CAAC;AAiD7B;;;;;;GAMG;AACH,wBAAsB,eAAe,CACnC,IAAI,EAAE;IAAE,aAAa,EAAE,aAAa,CAAC;IAAC,UAAU,EAAE,UAAU,CAAA;CAAE,GAC7D,OAAO,CAAC,MAAM,IAAI,CAAC,CAiCrB"}
1
+ {"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../../src/editor/main.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,UAAU,EACf,KAAK,aAAa,EAGnB,MAAM,aAAa,CAAC;AAQrB,cAAc,YAAY,CAAC;AAC3B,cAAc,UAAU,CAAC;AACzB,cAAc,WAAW,CAAC;AAC1B,cAAc,cAAc,CAAC;AAoD7B;;;;;;GAMG;AACH,wBAAsB,eAAe,CACnC,IAAI,EAAE;IAAE,aAAa,EAAE,aAAa,CAAC;IAAC,UAAU,EAAE,UAAU,CAAA;CAAE,GAC7D,OAAO,CAAC,MAAM,IAAI,CAAC,CA4CrB"}
package/dist/editor.js CHANGED
@@ -293,32 +293,126 @@ function createEditorHandler(options) {
293
293
  }
294
294
  const styles = `
295
295
  <style>
296
+ :host {
297
+ display: block;
298
+ position: relative;
299
+ }
300
+
296
301
  .block-wrapper {
297
302
  position: relative;
298
- padding: 12px;
299
- background-color: white;
300
- border: 1px solid #B5B5B5;
301
- border-radius: 8px;
302
303
  box-sizing: border-box;
303
304
  }
304
305
 
305
- .block-wrapper:hover,
306
- .block-wrapper.active {
307
- border-color: #000000;
306
+ :host(:hover:not(.active)) .block-wrapper {
307
+ outline: 1px dashed #060606;
308
+ /* 4px gap between the block content and the dashed outline so the
309
+ * outline reads as a hover affordance rather than a touching border.
310
+ * Outline doesn't participate in layout, so this stays layout-neutral. */
311
+ outline-offset: 4px;
308
312
  }
309
313
 
310
- .block-wrapper__name {
314
+ /*
315
+ * Stacking model for the active state (no negative z-index, no isolation):
316
+ * - .block-wrapper__chrome z-index: 100 → visual frame above neighbours
317
+ * and any in-block UI that
318
+ * creates its own stacking
319
+ * context (overlays, sticky
320
+ * headers, etc.)
321
+ * - .block-wrapper__slot-host z-index: 101 → block content above chrome bg
322
+ * so blocks without their own
323
+ * background stay visible
324
+ * - .block-wrapper__name z-index: 102 → title bar above everything,
325
+ * always clickable
326
+ *
327
+ * IMPORTANT: every z-index here is scoped to :host(.active). Otherwise
328
+ * inactive sibling wrappers' slot-host (z-index: 101) would create
329
+ * stacking contexts at root level and paint *above* the active wrapper's
330
+ * chrome (z-index: 100), hiding it. Scoping ensures only the active
331
+ * wrapper participates in this stacking layer.
332
+ * Neighbouring wrappers stay at default (auto / 0) and naturally sit below.
333
+ */
334
+
335
+ /*
336
+ * Active-mode chrome — a card frame that visually wraps the block
337
+ * (white bg, gray border, drop shadow, padding around the block, and
338
+ * room at the top for the title bar). Drawn as a position:absolute
339
+ * overlay extending beyond the wrapper bounds so adjacent blocks are
340
+ * never pushed (it overlays them with the shadow effect instead).
341
+ */
342
+ .block-wrapper__chrome {
343
+ display: none;
344
+ position: absolute;
345
+ /* Top extends 44px above the block to fit a 12px / 20px / 12px stack:
346
+ * 12px gap, 20px title bar, 12px gap to the block. Sides + bottom keep
347
+ * the original 12px gap around the block. */
348
+ top: -44px;
349
+ left: -12px;
350
+ right: -12px;
351
+ bottom: -12px;
352
+ background: #ffffff;
353
+ border: 0.5px solid #b5b5b5;
354
+ border-radius: 6px;
355
+ box-shadow: 0 0 14px 0 rgba(0, 0, 0, 0.10);
356
+ /* No pointer-events: none here — otherwise clicks on the chrome's
357
+ * overflow padding (the 12px ring around the block and the 44px
358
+ * title-bar strip above it) would fall through to whatever's behind:
359
+ * a sibling wrapper (re-targeting selection) or empty body
360
+ * (deselecting the current block). Block content still receives
361
+ * clicks because slot-host (z-index: 101) paints above the chrome
362
+ * (z-index: 100), and the title bar wins via its own z-index: 102. */
363
+ }
364
+
365
+ :host(.active) .block-wrapper__chrome {
366
+ display: block;
367
+ z-index: 100;
368
+ }
369
+
370
+ /*
371
+ * Wraps the slotted block content. Stays as a plain in-flow div when
372
+ * inactive (no stacking context). Only when the host is .active do we
373
+ * promote it to z-index: 101 so block content paints above the chrome's
374
+ * white fill. Without this scoping, every inactive neighbour's slot-host
375
+ * would also be at z-index: 101 and would cover the active chrome.
376
+ */
377
+ :host(.active) .block-wrapper__slot-host {
311
378
  position: relative;
312
- display: flex;
313
- justify-content: space-between;
379
+ z-index: 101;
380
+ }
381
+
382
+ /*
383
+ * Title bar lives in the top region of the chrome with symmetric 12px
384
+ * padding from every chrome edge it touches and from the block:
385
+ * - top: -32 → 12px below chrome's top edge (-44),
386
+ * 12px above the block (height: 20 → bottom at -12)
387
+ * - left/right: 0 → 12px inside chrome's -12 left/right edges,
388
+ * visually flush with the block's horizontal edges
389
+ */
390
+ .block-wrapper__name {
391
+ position: absolute;
392
+ top: -32px;
393
+ left: 0;
394
+ right: 0;
395
+ display: none;
314
396
  align-items: center;
315
- gap: 6.82px;
316
- margin-bottom: 12px;
397
+ gap: 7px;
317
398
  font-size: 12px;
318
399
  font-weight: 500;
319
- color: #8A8A8A;
400
+ color: #8a8a8a;
320
401
  line-height: 100%;
321
- height: 15px
402
+ height: 20px;
403
+ box-sizing: border-box;
404
+ white-space: nowrap;
405
+ pointer-events: auto;
406
+ }
407
+
408
+ :host(.active) .block-wrapper__name {
409
+ display: flex;
410
+ z-index: 102;
411
+ }
412
+
413
+ .block-wrapper__icon {
414
+ display: inline-flex;
415
+ align-items: center;
322
416
  }
323
417
 
324
418
  .block-wrapper__actions {
@@ -326,7 +420,7 @@ const styles = `
326
420
  align-items: center;
327
421
  justify-content: flex-end;
328
422
  height: 100%;
329
- flex-grow: 1;
423
+ margin-left: auto;
330
424
  }
331
425
 
332
426
  .block-wrapper__actions button {
@@ -347,7 +441,6 @@ const styles = `
347
441
  color: #8A8A8A;
348
442
  }
349
443
 
350
-
351
444
  .block-wrapper__menu {
352
445
  display: none;
353
446
  position: absolute;
@@ -451,6 +544,8 @@ class BlockWrapper extends HTMLElement {
451
544
  setupTemplate() {
452
545
  const wrapper = document.createElement("div");
453
546
  wrapper.className = "block-wrapper";
547
+ const chrome = document.createElement("div");
548
+ chrome.className = "block-wrapper__chrome";
454
549
  const nameDiv = document.createElement("div");
455
550
  nameDiv.className = "block-wrapper__name";
456
551
  const iconContainer = document.createElement("div");
@@ -493,9 +588,13 @@ class BlockWrapper extends HTMLElement {
493
588
  nameDiv.appendChild(nameSpan);
494
589
  nameDiv.appendChild(actionsDiv);
495
590
  nameDiv.appendChild(menuEl);
591
+ wrapper.appendChild(chrome);
496
592
  wrapper.appendChild(nameDiv);
593
+ const slotHost = document.createElement("div");
594
+ slotHost.className = "block-wrapper__slot-host";
497
595
  const slot = document.createElement("slot");
498
- wrapper.appendChild(slot);
596
+ slotHost.appendChild(slot);
597
+ wrapper.appendChild(slotHost);
499
598
  this.shadowRoot.appendChild(wrapper);
500
599
  this.nameElement = nameSpan;
501
600
  this.menuElement = menuEl;
@@ -509,10 +608,10 @@ class BlockWrapper extends HTMLElement {
509
608
  connectedCallback() {
510
609
  const isInOverlay = this.closest('juo-extension-root[surface="overlay"]') !== null;
511
610
  if (isInOverlay) {
512
- const actions = this.shadowRoot.querySelector(
513
- ".block-wrapper__actions"
611
+ const name = this.shadowRoot.querySelector(
612
+ ".block-wrapper__name"
514
613
  );
515
- if (actions) actions.style.visibility = "hidden";
614
+ if (name) name.style.visibility = "hidden";
516
615
  }
517
616
  }
518
617
  disconnectedCallback() {
@@ -553,14 +652,11 @@ class BlockWrapper extends HTMLElement {
553
652
  }
554
653
  }
555
654
  updateActiveState(isActive) {
556
- const wrapper = this.shadowRoot.querySelector(
557
- ".block-wrapper"
558
- );
559
- if (!wrapper) return;
560
655
  if (isActive) {
561
- wrapper.classList.add("active");
656
+ this.classList.add("active");
562
657
  } else {
563
- wrapper.classList.remove("active");
658
+ this.classList.remove("active");
659
+ this.closeMenu();
564
660
  }
565
661
  }
566
662
  /**
@@ -651,8 +747,12 @@ async function serializeBlock(block) {
651
747
  locales
652
748
  };
653
749
  }
750
+ const EDITOR_BODY_TOP_PADDING_PX = 32;
654
751
  async function setupEditorMode(deps) {
655
752
  const { routerService, themeState } = deps;
753
+ const padStyle = document.createElement("style");
754
+ padStyle.textContent = `body { padding-top: ${EDITOR_BODY_TOP_PADDING_PX}px; }`;
755
+ document.head.appendChild(padStyle);
656
756
  const editor = createEditorBridge();
657
757
  const handler = createEditorHandler({
658
758
  themeState
@@ -676,6 +776,7 @@ async function setupEditorMode(deps) {
676
776
  );
677
777
  });
678
778
  return () => {
779
+ padStyle.remove();
679
780
  unsubscribe();
680
781
  editor.destroy();
681
782
  };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@juo/blocks",
3
3
  "private": false,
4
- "version": "1.4.5",
4
+ "version": "1.4.6",
5
5
  "type": "module",
6
6
  "files": [
7
7
  "dist"