@elaraai/e3-ui-components 1.0.82 → 1.0.84

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.
package/dist/index.cjs CHANGED
@@ -4863,7 +4863,7 @@ function createInMemoryFunctionApi(functions2) {
4863
4863
  name: def.name,
4864
4864
  inputTypes: def.inputTypes,
4865
4865
  outputType: def.outputType,
4866
- runner: east.variant("east_node", { platforms: [] })
4866
+ runner: east.variant("east_node", { platforms: [], decode: east.variant("lazy", null) })
4867
4867
  }));
4868
4868
  },
4869
4869
  async call(_workspace, fnName, req) {
@@ -4876,7 +4876,9 @@ function createInMemoryFunctionApi(functions2) {
4876
4876
  stdout: "",
4877
4877
  stderr: "",
4878
4878
  stdoutTruncated: false,
4879
- stderrTruncated: false
4879
+ stderrTruncated: false,
4880
+ // A named function call reads no dataset.
4881
+ inputs: []
4880
4882
  };
4881
4883
  }
4882
4884
  };
@@ -8465,6 +8467,16 @@ var faMinus = {
8465
8467
  iconName: "minus",
8466
8468
  icon: [448, 512, [8211, 8722, 10134, "subtract"], "f068", "M0 256c0-17.7 14.3-32 32-32l384 0c17.7 0 32 14.3 32 32s-14.3 32-32 32L32 288c-17.7 0-32-14.3-32-32z"]
8467
8469
  };
8470
+ var faMagnifyingGlass = {
8471
+ prefix: "fas",
8472
+ iconName: "magnifying-glass",
8473
+ icon: [512, 512, [128269, "search"], "f002", "M416 208c0 45.9-14.9 88.3-40 122.7L502.6 457.4c12.5 12.5 12.5 32.8 0 45.3s-32.8 12.5-45.3 0L330.7 376C296.3 401.1 253.9 416 208 416 93.1 416 0 322.9 0 208S93.1 0 208 0 416 93.1 416 208zM208 352a144 144 0 1 0 0-288 144 144 0 1 0 0 288z"]
8474
+ };
8475
+ var faArrowsUpToLine = {
8476
+ prefix: "fas",
8477
+ iconName: "arrows-up-to-line",
8478
+ icon: [448, 512, [], "e4c2", "M32 0C14.3 0 0 14.3 0 32S14.3 64 32 64l384 0c17.7 0 32-14.3 32-32S433.7 0 416 0L32 0zm86.6 137.4c-12.5-12.5-32.8-12.5-45.3 0l-64 64c-12.5 12.5-12.5 32.8 0 45.3s32.8 12.5 45.3 0L64 237.3 64 480c0 17.7 14.3 32 32 32s32-14.3 32-32l0-242.7 9.4 9.4c12.5 12.5 32.8 12.5 45.3 0s12.5-32.8 0-45.3l-64-64zm256 0c-12.5-12.5-32.8-12.5-45.3 0l-64 64c-12.5 12.5-12.5 32.8 0 45.3s32.8 12.5 45.3 0l9.4-9.4 0 242.7c0 17.7 14.3 32 32 32s32-14.3 32-32l0-242.7 9.4 9.4c12.5 12.5 32.8 12.5 45.3 0s12.5-32.8 0-45.3l-64-64z"]
8479
+ };
8468
8480
  var faEquals = {
8469
8481
  prefix: "fas",
8470
8482
  iconName: "equals",
@@ -8475,6 +8487,16 @@ var faChevronUp = {
8475
8487
  iconName: "chevron-up",
8476
8488
  icon: [448, 512, [], "f077", "M201.4 105.4c12.5-12.5 32.8-12.5 45.3 0l192 192c12.5 12.5 12.5 32.8 0 45.3s-32.8 12.5-45.3 0L224 173.3 54.6 342.6c-12.5 12.5-32.8 12.5-45.3 0s-12.5-32.8 0-45.3l192-192z"]
8477
8489
  };
8490
+ var faFolderOpen = {
8491
+ prefix: "fas",
8492
+ iconName: "folder-open",
8493
+ icon: [576, 512, [128194, 128449, 61717], "f07c", "M56 225.6L32.4 296.2 32.4 96c0-35.3 28.7-64 64-64l138.7 0c13.8 0 27.3 4.5 38.4 12.8l38.4 28.8c5.5 4.2 12.3 6.4 19.2 6.4l117.3 0c35.3 0 64 28.7 64 64l0 16-365.4 0c-41.3 0-78 26.4-91.1 65.6zM477.8 448L99 448c-32.8 0-55.9-32.1-45.5-63.2l48-144C108 221.2 126.4 208 147 208l378.8 0c32.8 0 55.9 32.1 45.5 63.2l-48 144c-6.5 19.6-24.9 32.8-45.5 32.8z"]
8494
+ };
8495
+ var faArrowsUpDown = {
8496
+ prefix: "fas",
8497
+ iconName: "arrows-up-down",
8498
+ icon: [256, 512, ["arrows-v"], "f07d", "M150.6-22.6c-12.5-12.5-32.8-12.5-45.3 0l-96 96c-12.5 12.5-12.5 32.8 0 45.3s32.8 12.5 45.3 0L96 77.3 96 434.7 54.6 393.4c-12.5-12.5-32.8-12.5-45.3 0s-12.5 32.8 0 45.3l96 96c6 6 14.1 9.4 22.6 9.4s16.6-3.4 22.6-9.4l96-96c12.5-12.5 12.5-32.8 0-45.3s-32.8-12.5-45.3 0l-41.4 41.4 0-357.5 41.4 41.4c12.5 12.5 32.8 12.5 45.3 0s12.5-32.8 0-45.3l-96-96z"]
8499
+ };
8478
8500
  var faCode = {
8479
8501
  prefix: "fas",
8480
8502
  iconName: "code",
@@ -8485,6 +8507,16 @@ var faTerminal = {
8485
8507
  iconName: "terminal",
8486
8508
  icon: [512, 512, [], "f120", "M9.4 118.6c-12.5-12.5-12.5-32.8 0-45.3s32.8-12.5 45.3 0l160 160c12.5 12.5 12.5 32.8 0 45.3l-160 160c-12.5 12.5-32.8 12.5-45.3 0s-12.5-32.8 0-45.3L146.7 256 9.4 118.6zM224 384l256 0c17.7 0 32 14.3 32 32s-14.3 32-32 32l-256 0c-17.7 0-32-14.3-32-32s14.3-32 32-32z"]
8487
8509
  };
8510
+ var faFolder = {
8511
+ prefix: "fas",
8512
+ iconName: "folder",
8513
+ icon: [512, 512, [128193, 128447, 61716, "folder-blank"], "f07b", "M64 448l384 0c35.3 0 64-28.7 64-64l0-240c0-35.3-28.7-64-64-64L298.7 80c-6.9 0-13.7-2.2-19.2-6.4L241.1 44.8C230 36.5 216.5 32 202.7 32L64 32C28.7 32 0 60.7 0 96L0 384c0 35.3 28.7 64 64 64z"]
8514
+ };
8515
+ var faArrowsToDot = {
8516
+ prefix: "fas",
8517
+ iconName: "arrows-to-dot",
8518
+ icon: [512, 512, [], "e4be", "M256 0c17.7 0 32 14.3 32 32l0 32 32 0c12.9 0 24.6 7.8 29.6 19.8s2.2 25.7-6.9 34.9l-64 64c-12.5 12.5-32.8 12.5-45.3 0l-64-64c-9.2-9.2-11.9-22.9-6.9-34.9S179.1 64 192 64l32 0 0-32c0-17.7 14.3-32 32-32zM169.4 393.4l64-64c12.5-12.5 32.8-12.5 45.3 0l64 64c9.2 9.2 11.9 22.9 6.9 34.9S332.9 448 320 448l-32 0 0 32c0 17.7-14.3 32-32 32s-32-14.3-32-32l0-32-32 0c-12.9 0-24.6-7.8-29.6-19.8s-2.2-25.7 6.9-34.9zM32 224l32 0 0-32c0-12.9 7.8-24.6 19.8-29.6s25.7-2.2 34.9 6.9l64 64c12.5 12.5 12.5 32.8 0 45.3l-64 64c-9.2 9.2-22.9 11.9-34.9 6.9S64 332.9 64 320l0-32-32 0c-17.7 0-32-14.3-32-32s14.3-32 32-32zm297.4 54.6c-12.5-12.5-12.5-32.8 0-45.3l64-64c9.2-9.2 22.9-11.9 34.9-6.9S448 179.1 448 192l0 32 32 0c17.7 0 32 14.3 32 32s-14.3 32-32 32l-32 0 0 32c0 12.9-7.8 24.6-19.8 29.6s-25.7 2.2-34.9-6.9l-64-64zM256 224a32 32 0 1 1 0 64 32 32 0 1 1 0-64z"]
8519
+ };
8488
8520
  var faArrowUp = {
8489
8521
  prefix: "fas",
8490
8522
  iconName: "arrow-up",
@@ -8520,16 +8552,31 @@ var faPen = {
8520
8552
  iconName: "pen",
8521
8553
  icon: [512, 512, [128394], "f304", "M352.9 21.2L308 66.1 445.9 204 490.8 159.1C504.4 145.6 512 127.2 512 108s-7.6-37.6-21.2-51.1L455.1 21.2C441.6 7.6 423.2 0 404 0s-37.6 7.6-51.1 21.2zM274.1 100L58.9 315.1c-10.7 10.7-18.5 24.1-22.6 38.7L.9 481.6c-2.3 8.3 0 17.3 6.2 23.4s15.1 8.5 23.4 6.2l127.8-35.5c14.6-4.1 27.9-11.8 38.7-22.6L412 237.9 274.1 100z"]
8522
8554
  };
8555
+ var faMobileScreen = {
8556
+ prefix: "fas",
8557
+ iconName: "mobile-screen",
8558
+ icon: [384, 512, ["mobile-android-alt"], "f3cf", "M16 64C16 28.7 44.7 0 80 0L304 0c35.3 0 64 28.7 64 64l0 384c0 35.3-28.7 64-64 64L80 512c-35.3 0-64-28.7-64-64L16 64zM128 440c0 13.3 10.7 24 24 24l80 0c13.3 0 24-10.7 24-24s-10.7-24-24-24l-80 0c-13.3 0-24 10.7-24 24zM304 64l-224 0 0 304 224 0 0-304z"]
8559
+ };
8523
8560
  var faChevronDown = {
8524
8561
  prefix: "fas",
8525
8562
  iconName: "chevron-down",
8526
8563
  icon: [448, 512, [], "f078", "M201.4 406.6c12.5 12.5 32.8 12.5 45.3 0l192-192c12.5-12.5 12.5-32.8 0-45.3s-32.8-12.5-45.3 0L224 338.7 54.6 169.4c-12.5-12.5-32.8-12.5-45.3 0s-12.5 32.8 0 45.3l192 192z"]
8527
8564
  };
8565
+ var faArrowDownZA = {
8566
+ prefix: "fas",
8567
+ iconName: "arrow-down-z-a",
8568
+ icon: [512, 512, ["sort-alpha-desc", "sort-alpha-down-alt"], "f881", "M230.6 390.6l-80 80c-12.5 12.5-32.8 12.5-45.3 0l-80-80c-12.5-12.5-12.5-32.8 0-45.3s32.8-12.5 45.3 0L96 370.7 96 64c0-17.7 14.3-32 32-32s32 14.3 32 32l0 306.7 25.4-25.4c12.5-12.5 32.8-12.5 45.3 0s12.5 32.8 0 45.3zM288 64c0-17.7 14.3-32 32-32l128 0c12.9 0 24.6 7.8 29.6 19.8s2.2 25.7-6.9 34.9L397.3 160 448 160c17.7 0 32 14.3 32 32s-14.3 32-32 32l-128 0c-12.9 0-24.6-7.8-29.6-19.8s-2.2-25.7 6.9-34.9L370.8 96 320 96c-17.7 0-32-14.3-32-32zM412.6 273.7l80 160c7.9 15.8 1.5 35-14.3 42.9s-35 1.5-42.9-14.3l-7.2-14.3-88.4 0-7.2 14.3c-7.9 15.8-27.1 22.2-42.9 14.3s-22.2-27.1-14.3-42.9l80-160c5.4-10.8 16.5-17.7 28.6-17.7s23.2 6.8 28.6 17.7zM384 359.6l-20.2 40.4 40.4 0-20.2-40.4z"]
8569
+ };
8528
8570
  var faTriangleExclamation = {
8529
8571
  prefix: "fas",
8530
8572
  iconName: "triangle-exclamation",
8531
8573
  icon: [512, 512, [9888, "exclamation-triangle", "warning"], "f071", "M256 0c14.7 0 28.2 8.1 35.2 21l216 400c6.7 12.4 6.4 27.4-.8 39.5S486.1 480 472 480L40 480c-14.1 0-27.2-7.4-34.4-19.5s-7.5-27.1-.8-39.5l216-400c7-12.9 20.5-21 35.2-21zm0 352a32 32 0 1 0 0 64 32 32 0 1 0 0-64zm0-192c-18.2 0-32.7 15.5-31.4 33.7l7.4 104c.9 12.5 11.4 22.3 23.9 22.3 12.6 0 23-9.7 23.9-22.3l7.4-104c1.3-18.2-13.1-33.7-31.4-33.7z"]
8532
8574
  };
8575
+ var faLock = {
8576
+ prefix: "fas",
8577
+ iconName: "lock",
8578
+ icon: [384, 512, [128274], "f023", "M128 96l0 64 128 0 0-64c0-35.3-28.7-64-64-64s-64 28.7-64 64zM64 160l0-64C64 25.3 121.3-32 192-32S320 25.3 320 96l0 64c35.3 0 64 28.7 64 64l0 224c0 35.3-28.7 64-64 64L64 512c-35.3 0-64-28.7-64-64L0 224c0-35.3 28.7-64 64-64z"]
8579
+ };
8533
8580
  var faDownload = {
8534
8581
  prefix: "fas",
8535
8582
  iconName: "download",
@@ -8545,16 +8592,36 @@ var faCopy = {
8545
8592
  iconName: "copy",
8546
8593
  icon: [448, 512, [], "f0c5", "M192 0c-35.3 0-64 28.7-64 64l0 256c0 35.3 28.7 64 64 64l192 0c35.3 0 64-28.7 64-64l0-200.6c0-17.4-7.1-34.1-19.7-46.2L370.6 17.8C358.7 6.4 342.8 0 326.3 0L192 0zM64 128c-35.3 0-64 28.7-64 64L0 448c0 35.3 28.7 64 64 64l192 0c35.3 0 64-28.7 64-64l0-16-64 0 0 16-192 0 0-256 16 0 0-64-16 0z"]
8547
8594
  };
8595
+ var faCaretDown = {
8596
+ prefix: "fas",
8597
+ iconName: "caret-down",
8598
+ icon: [320, 512, [], "f0d7", "M140.3 376.8c12.6 10.2 31.1 9.5 42.8-2.2l128-128c9.2-9.2 11.9-22.9 6.9-34.9S301.4 192 288.5 192l-256 0c-12.9 0-24.6 7.8-29.6 19.8S.7 237.5 9.9 246.6l128 128 2.4 2.2z"]
8599
+ };
8600
+ var faDesktop = {
8601
+ prefix: "fas",
8602
+ iconName: "desktop",
8603
+ icon: [512, 512, [128421, 61704, "desktop-alt"], "f390", "M64 32C28.7 32 0 60.7 0 96L0 352c0 35.3 28.7 64 64 64l144 0-16 48-72 0c-13.3 0-24 10.7-24 24s10.7 24 24 24l272 0c13.3 0 24-10.7 24-24s-10.7-24-24-24l-72 0-16-48 144 0c35.3 0 64-28.7 64-64l0-256c0-35.3-28.7-64-64-64L64 32zM96 96l320 0c17.7 0 32 14.3 32 32l0 160c0 17.7-14.3 32-32 32L96 320c-17.7 0-32-14.3-32-32l0-160c0-17.7 14.3-32 32-32z"]
8604
+ };
8548
8605
  var faArrowDown = {
8549
8606
  prefix: "fas",
8550
8607
  iconName: "arrow-down",
8551
8608
  icon: [384, 512, [8595], "f063", "M169.4 502.6c12.5 12.5 32.8 12.5 45.3 0l160-160c12.5-12.5 12.5-32.8 0-45.3s-32.8-12.5-45.3 0L224 402.7 224 32c0-17.7-14.3-32-32-32s-32 14.3-32 32l0 370.7-105.4-105.4c-12.5-12.5-32.8-12.5-45.3 0s-12.5 32.8 0 45.3l160 160z"]
8552
8609
  };
8610
+ var faArrowDownAZ = {
8611
+ prefix: "fas",
8612
+ iconName: "arrow-down-a-z",
8613
+ icon: [512, 512, ["sort-alpha-asc", "sort-alpha-down"], "f15d", "M230.6 390.6l-80 80c-12.5 12.5-32.8 12.5-45.3 0l-80-80c-12.5-12.5-12.5-32.8 0-45.3s32.8-12.5 45.3 0L96 370.7 96 64c0-17.7 14.3-32 32-32s32 14.3 32 32l0 306.7 25.4-25.4c12.5-12.5 32.8-12.5 45.3 0s12.5 32.8 0 45.3zm182-340.9c50.7 101.3 77.3 154.7 80 160 7.9 15.8 1.5 35-14.3 42.9s-35 1.5-42.9-14.3l-7.2-14.3-88.4 0-7.2 14.3c-7.9 15.8-27.1 22.2-42.9 14.3s-22.2-27.1-14.3-42.9c2.7-5.3 29.3-58.7 80-160 5.4-10.8 16.5-17.7 28.6-17.7s23.2 6.8 28.6 17.7zM384 135.6l-20.2 40.4 40.4 0-20.2-40.4zM288 320c0-17.7 14.3-32 32-32l128 0c12.9 0 24.6 7.8 29.6 19.8s2.2 25.7-6.9 34.9L397.3 416 448 416c17.7 0 32 14.3 32 32s-14.3 32-32 32l-128 0c-12.9 0-24.6-7.8-29.6-19.8s-2.2-25.7 6.9-34.9l73.4-73.4-50.7 0c-17.7 0-32-14.3-32-32z"]
8614
+ };
8553
8615
  var faCircleInfo = {
8554
8616
  prefix: "fas",
8555
8617
  iconName: "circle-info",
8556
8618
  icon: [512, 512, ["info-circle"], "f05a", "M256 512a256 256 0 1 0 0-512 256 256 0 1 0 0 512zM224 160a32 32 0 1 1 64 0 32 32 0 1 1 -64 0zm-8 64l48 0c13.3 0 24 10.7 24 24l0 88 8 0c13.3 0 24 10.7 24 24s-10.7 24-24 24l-80 0c-13.3 0-24-10.7-24-24s10.7-24 24-24l24 0 0-64-24 0c-13.3 0-24-10.7-24-24s10.7-24 24-24z"]
8557
8619
  };
8620
+ var faTabletScreenButton = {
8621
+ prefix: "fas",
8622
+ iconName: "tablet-screen-button",
8623
+ icon: [448, 512, ["tablet-alt"], "f3fa", "M0 64C0 28.7 28.7 0 64 0L384 0c35.3 0 64 28.7 64 64l0 384c0 35.3-28.7 64-64 64L64 512c-35.3 0-64-28.7-64-64L0 64zM256 432a32 32 0 1 0 -64 0 32 32 0 1 0 64 0zM384 64l-320 0 0 288 320 0 0-288z"]
8624
+ };
8558
8625
  function createDefaultRecordApi(apiUrl, repo, getToken) {
8559
8626
  const opts = () => ({ token: getToken() });
8560
8627
  return {
@@ -8566,7 +8633,7 @@ function createDefaultRecordApi(apiUrl, repo, getToken) {
8566
8633
  args: req.args,
8567
8634
  actor: east.none,
8568
8635
  limits: east.none
8569
- }, opts());
8636
+ }, opts(), req.idempotencyKey);
8570
8637
  },
8571
8638
  async history(workspace, record, limit2, from2) {
8572
8639
  return e3ApiClient.workspaceRecordHistory(apiUrl, repo, workspace, record, limit2, opts(), from2);
@@ -8620,7 +8687,9 @@ function errorOfMutationResult(result) {
8620
8687
  case "conflict":
8621
8688
  return {
8622
8689
  kind: east.variant("conflict", { attempts: outcome.value.attempts }),
8623
- message: `compare-and-swap conflicted after ${outcome.value.attempts} attempts; try again`,
8690
+ // A write the record no longer matches would disagree again: only
8691
+ // a lost race is worth trying again as it was.
8692
+ message: outcome.value.detail.type === "some" ? `the write no longer matches the record (${outcome.value.detail.value}); re-read it and resubmit` : `compare-and-swap conflicted after ${outcome.value.attempts} attempts; try again`,
8624
8693
  stderr: ""
8625
8694
  };
8626
8695
  default:
@@ -8646,13 +8715,13 @@ class RecordRuntime extends TrackedChannelStore {
8646
8715
  __publicField(this, "signatureCache", /* @__PURE__ */ new Map());
8647
8716
  // History per channel, fetched once + refreshed on commit.
8648
8717
  __publicField(this, "histories", /* @__PURE__ */ new Map());
8649
- __publicField(this, "historyInFlight", /* @__PURE__ */ new Set());
8718
+ __publicField(this, "historyInFlight", /* @__PURE__ */ new Map());
8650
8719
  // Channels whose last history fetch failed. Guards `history()` from
8651
8720
  // re-issuing the request on every render (a failing endpoint would
8652
8721
  // otherwise spin); cleared on the next commit / on clear() so a later
8653
8722
  // mutation retries.
8654
8723
  __publicField(this, "historyFailed", /* @__PURE__ */ new Set());
8655
- // Compiled-handle cache (issue #106 perf): buildHandle compiles 8 + (one per
8724
+ // Compiled-handle cache (issue #106 perf): buildHandle compiles 8 + (two per
8656
8725
  // mutation) East.functions per bind, and binds re-run every reactive frame.
8657
8726
  // The method IR is a pure function of the record name (which fixes the handle
8658
8727
  // type), and the methods resolve cache/api/ws LIVE, so a cached handle still
@@ -8730,11 +8799,17 @@ class RecordRuntime extends TrackedChannelStore {
8730
8799
  }
8731
8800
  return null;
8732
8801
  }
8733
- /** Fetch a record's history once per channel (deduped); notify on settle. */
8734
- fetchHistory(workspace, record, key) {
8735
- if (this.historyInFlight.has(key)) return;
8736
- this.historyInFlight.add(key);
8737
- void (async () => {
8802
+ /**
8803
+ * Fetch a record's history once per channel (deduped); notify on settle.
8804
+ *
8805
+ * @param again - Fetch once more after a fetch in flight, which may have
8806
+ * read the chain before what the caller fetches it for
8807
+ * @returns The fetch, settled once the history or its failure is in
8808
+ */
8809
+ fetchHistory(workspace, record, key, again = false) {
8810
+ const inFlight = this.historyInFlight.get(key);
8811
+ if (inFlight !== void 0) return again ? inFlight.then(() => this.fetchHistory(workspace, record, key)) : inFlight;
8812
+ const fetch = (async () => {
8738
8813
  const api3 = this.api;
8739
8814
  try {
8740
8815
  if (!api3) throw new Error("no RecordApi installed");
@@ -8748,43 +8823,67 @@ class RecordRuntime extends TrackedChannelStore {
8748
8823
  this.notify(key);
8749
8824
  }
8750
8825
  })();
8826
+ this.historyInFlight.set(key, fetch);
8827
+ return fetch;
8751
8828
  }
8752
8829
  // ----- closure semantics -------------------------------------------------
8753
- launchMutation(workspace, record, mutation, argTypes, args) {
8830
+ /**
8831
+ * Run one mutation on the record's channel, and settle to the server's
8832
+ * outcome.
8833
+ *
8834
+ * @remarks
8835
+ * The channel shows the write as it shows every launch, latest-wins; the
8836
+ * outcome returned is the server's own, whatever became of the channel. A
8837
+ * commit refreshes the record's bytes and drops its history. A conflict
8838
+ * fetches both again before the outcome settles, so an awaiting caller
8839
+ * reads the state and the history its write lost to.
8840
+ *
8841
+ * @param idempotencyKey - The write's request id, when it has one
8842
+ * @returns The outcome
8843
+ */
8844
+ runMutation(workspace, record, mutation, argTypes, args, idempotencyKey) {
8754
8845
  const key = recordChannelKey(workspace, record);
8755
8846
  const { entry, settle } = this.beginLaunch(key, (e3) => {
8756
8847
  delete e3.error;
8757
8848
  });
8758
8849
  const run = (async () => {
8759
- var _a2;
8850
+ var _a2, _b2;
8760
8851
  const invalid = await this.validate(workspace, record, mutation, argTypes);
8761
8852
  if (invalid) {
8762
8853
  settle((e3) => {
8763
8854
  e3.status = "failed";
8764
8855
  e3.error = invalid;
8765
8856
  });
8766
- return;
8857
+ return invalid.kind.type === "transport" ? east.variant("transport", { message: invalid.message }) : east.variant("invalid", { message: invalid.message });
8767
8858
  }
8768
8859
  const api3 = this.api;
8769
8860
  if (!api3) {
8861
+ const error3 = transportError("no RecordApi installed");
8770
8862
  settle((e3) => {
8771
8863
  e3.status = "failed";
8772
- e3.error = transportError("no RecordApi installed");
8864
+ e3.error = error3;
8773
8865
  });
8774
- return;
8866
+ return east.variant("transport", { message: error3.message });
8775
8867
  }
8776
8868
  let result;
8777
8869
  try {
8778
8870
  const encoded = args.map((arg, i) => east.encodeBeast2For(argTypes[i])(arg));
8779
- result = await api3.mutate(workspace, record, mutation, { args: encoded });
8871
+ result = await api3.mutate(
8872
+ workspace,
8873
+ record,
8874
+ mutation,
8875
+ idempotencyKey === void 0 ? { args: encoded } : { args: encoded, idempotencyKey }
8876
+ );
8780
8877
  } catch (err) {
8878
+ const error3 = transportError(err instanceof Error ? err.message : String(err));
8781
8879
  settle((e3) => {
8782
8880
  e3.status = "failed";
8783
- e3.error = transportError(err instanceof Error ? err.message : String(err));
8881
+ e3.error = error3;
8784
8882
  });
8785
- return;
8883
+ return east.variant("transport", { message: error3.message });
8786
8884
  }
8787
- if (result.outcome.type === "committed") {
8885
+ const outcome = result.outcome;
8886
+ if (outcome.type === "committed") {
8788
8887
  settle((e3) => {
8789
8888
  e3.status = "committed";
8790
8889
  delete e3.error;
@@ -8798,13 +8897,21 @@ class RecordRuntime extends TrackedChannelStore {
8798
8897
  e3.status = "failed";
8799
8898
  e3.error = errorOfMutationResult(result);
8800
8899
  });
8900
+ if (outcome.type === "conflict") {
8901
+ this.histories.delete(key);
8902
+ this.historyFailed.delete(key);
8903
+ await Promise.all([(_b2 = this.cache) == null ? void 0 : _b2.refresh(workspace), this.fetchHistory(workspace, record, key, true)]);
8904
+ }
8801
8905
  }
8906
+ return outcome;
8802
8907
  })();
8803
- entry.inflight = run;
8804
- void run.finally(() => {
8908
+ const inflight = run.then(() => void 0, () => void 0);
8909
+ entry.inflight = inflight;
8910
+ void inflight.then(() => {
8805
8911
  const current = this.entries.get(key);
8806
- if (current && current.inflight === run) delete current.inflight;
8912
+ if (current && current.inflight === inflight) delete current.inflight;
8807
8913
  });
8914
+ return run;
8808
8915
  }
8809
8916
  /**
8810
8917
  * The low-level primitives backing handle methods, bound to THIS runtime.
@@ -8850,7 +8957,7 @@ class RecordRuntime extends TrackedChannelStore {
8850
8957
  runtime.track(key);
8851
8958
  const cached = runtime.histories.get(key);
8852
8959
  if (cached === void 0) {
8853
- if (!runtime.historyFailed.has(key)) runtime.fetchHistory(ws, name, key);
8960
+ if (!runtime.historyFailed.has(key)) void runtime.fetchHistory(ws, name, key);
8854
8961
  return east.none;
8855
8962
  }
8856
8963
  return east.some(cached);
@@ -8894,8 +9001,21 @@ class RecordRuntime extends TrackedChannelStore {
8894
9001
  const obj = argsStruct;
8895
9002
  const argTypes = fields.map((f2) => f2.type);
8896
9003
  const args = fields.map((f2) => obj[f2.name]);
8897
- runtime.launchMutation(runtime.resolveWorkspace(), recordNameArg, mutationNameArg, argTypes, args);
9004
+ void runtime.runMutation(runtime.resolveWorkspace(), recordNameArg, mutationNameArg, argTypes, args);
8898
9005
  return null;
9006
+ }),
9007
+ internal$1.RecordBindPrimitives.commit.implement((argsStructType) => async (recordNameArg, mutationNameArg, requestArg, argsStruct) => {
9008
+ const fields = argsStructType.value;
9009
+ const obj = argsStruct;
9010
+ const request = requestArg;
9011
+ return runtime.runMutation(
9012
+ runtime.resolveWorkspace(),
9013
+ recordNameArg,
9014
+ mutationNameArg,
9015
+ fields.map((f2) => f2.type),
9016
+ fields.map((f2) => obj[f2.name]),
9017
+ request === "" ? void 0 : request
9018
+ );
8899
9019
  })
8900
9020
  ];
8901
9021
  }
@@ -8907,6 +9027,7 @@ class RecordRuntime extends TrackedChannelStore {
8907
9027
  * serializable East data (issue #106).
8908
9028
  */
8909
9029
  buildHandle(handleType, name) {
9030
+ var _a2;
8910
9031
  const cached = this.handleCache.get(name);
8911
9032
  if (cached) return cached;
8912
9033
  const sig = signatureOfRecordHandleType(handleType);
@@ -8916,6 +9037,7 @@ class RecordRuntime extends TrackedChannelStore {
8916
9037
  const statusRet = fnOut(fields, "status");
8917
9038
  const historyRet = fnOut(fields, "history");
8918
9039
  const mfields = fields.find((f2) => f2.name === "mutate").type.value;
9040
+ const cfields = (_a2 = fields.find((f2) => f2.name === "commit")) == null ? void 0 : _a2.type.value;
8919
9041
  const nameExpr = east.East.value(name, east.StringType);
8920
9042
  const platform2 = this.buildPrimitives();
8921
9043
  const P2 = internal$1.RecordBindPrimitives;
@@ -8933,6 +9055,7 @@ class RecordRuntime extends TrackedChannelStore {
8933
9055
  $3.return(P2.mutateCancel(nameExpr));
8934
9056
  }), platform2)
8935
9057
  };
9058
+ const commit = {};
8936
9059
  for (const [mutationName, argTypes] of sig.mutations) {
8937
9060
  const argTypesEast = argTypes.map((t4) => east.fromEastTypeValue(t4));
8938
9061
  const ArgsStruct = east.StructType(Object.fromEntries(argTypesEast.map((t4, i) => [`arg${i}`, t4])));
@@ -8944,6 +9067,14 @@ class RecordRuntime extends TrackedChannelStore {
8944
9067
  });
8945
9068
  $3.return(P2.mutate([ArgsStruct], nameExpr, mutationNameExpr, east.East.value(obj, ArgsStruct)));
8946
9069
  }), platform2);
9070
+ if (cfields === void 0) continue;
9071
+ commit[mutationName] = east.East.compileAsync(east.East.asyncFunction([east.StringType, ...argTypesEast], fnOut(cfields, mutationName), ($3, request, ...args) => {
9072
+ const obj = {};
9073
+ args.forEach((a2, i) => {
9074
+ obj[`arg${i}`] = a2;
9075
+ });
9076
+ $3.return(P2.commit([ArgsStruct], nameExpr, mutationNameExpr, request, east.East.value(obj, ArgsStruct)));
9077
+ }), platform2);
8947
9078
  }
8948
9079
  const handle = {
8949
9080
  read: east.East.compile(east.East.function([], stateTypeEast, ($3) => {
@@ -8956,6 +9087,7 @@ class RecordRuntime extends TrackedChannelStore {
8956
9087
  $3.return(P2.history(nameExpr));
8957
9088
  }), platform2),
8958
9089
  mutate,
9090
+ ...cfields !== void 0 && { commit },
8959
9091
  start: east.East.compile(east.East.function([], east.NullType, ($3) => {
8960
9092
  $3.return(P2.start(nameExpr));
8961
9093
  }), platform2),
@@ -9000,7 +9132,7 @@ function createScopedRecordPlatform(records) {
9000
9132
  ];
9001
9133
  }
9002
9134
  function createInMemoryRecordApi(cache3, workspace, defs2) {
9003
- const compiled = /* @__PURE__ */ new Map();
9135
+ const compiled2 = /* @__PURE__ */ new Map();
9004
9136
  for (const def of defs2) {
9005
9137
  const stateType = east.toEastTypeValue(def.stateType);
9006
9138
  const mutations = /* @__PURE__ */ new Map();
@@ -9016,12 +9148,12 @@ function createInMemoryRecordApi(cache3, workspace, defs2) {
9016
9148
  at: /* @__PURE__ */ new Date(0),
9017
9149
  delta: east.none
9018
9150
  };
9019
- compiled.set(def.name, { stateType, mutations, commits: [genesis], seq: 0 });
9151
+ compiled2.set(def.name, { stateType, mutations, commits: [genesis], seq: 0 });
9020
9152
  void cache3.write(workspace, recordPath(def.name), east.encodeBeast2For(stateType)(def.initial));
9021
9153
  }
9022
9154
  return {
9023
9155
  async describe(_ws, record) {
9024
- const c2 = compiled.get(record);
9156
+ const c2 = compiled2.get(record);
9025
9157
  if (!c2) throw new Error(`no in-memory record "${record}"`);
9026
9158
  return {
9027
9159
  name: record,
@@ -9029,14 +9161,24 @@ function createInMemoryRecordApi(cache3, workspace, defs2) {
9029
9161
  };
9030
9162
  },
9031
9163
  async mutate(ws, record, mutation, req) {
9032
- const c2 = compiled.get(record);
9164
+ var _a2;
9165
+ const c2 = compiled2.get(record);
9033
9166
  if (!c2) throw new Error(`no in-memory record "${record}"`);
9034
9167
  const m2 = c2.mutations.get(mutation);
9035
9168
  if (!m2) return { outcome: east.variant("invalid", { message: `no mutation "${mutation}"` }) };
9169
+ if (req.idempotencyKey !== void 0 && ((_a2 = c2.keyed) == null ? void 0 : _a2.key) === req.idempotencyKey) return c2.keyed.result;
9036
9170
  const current = cache3.read(ws, recordPath(record));
9037
9171
  const state = current !== void 0 ? east.decodeBeast2For(c2.stateType)(current) : void 0;
9038
9172
  const args = req.args.map((bytes, i) => east.decodeBeast2For(m2.argTypes[i])(bytes));
9039
- const next2 = m2.reduce(state, ...args);
9173
+ let next2;
9174
+ try {
9175
+ next2 = m2.reduce(state, ...args);
9176
+ } catch (err) {
9177
+ if (err instanceof east.ConflictError) {
9178
+ return { outcome: east.variant("conflict", { attempts: 1n, detail: east.some(`primary: ${err.message}`) }) };
9179
+ }
9180
+ return { outcome: east.variant("failed", { exitCode: 1n, stderr: err instanceof Error ? err.message : String(err) }) };
9181
+ }
9040
9182
  await cache3.write(ws, recordPath(record), east.encodeBeast2For(c2.stateType)(next2));
9041
9183
  c2.seq += 1;
9042
9184
  const hash2 = `${record}-${c2.seq}`.padEnd(64, "0");
@@ -9049,10 +9191,12 @@ function createInMemoryRecordApi(cache3, workspace, defs2) {
9049
9191
  at: /* @__PURE__ */ new Date(0),
9050
9192
  delta: east.none
9051
9193
  });
9052
- return { outcome: east.variant("committed", { commitHash: hash2, stateHash: `${record}-state-${c2.seq}`.padEnd(64, "0") }) };
9194
+ const result = { outcome: east.variant("committed", { commitHash: hash2, stateHash: `${record}-state-${c2.seq}`.padEnd(64, "0") }) };
9195
+ c2.keyed = req.idempotencyKey !== void 0 ? { key: req.idempotencyKey, result } : void 0;
9196
+ return result;
9053
9197
  },
9054
9198
  async history(_ws, record, limit2) {
9055
- const c2 = compiled.get(record);
9199
+ const c2 = compiled2.get(record);
9056
9200
  if (!c2) throw new Error(`no in-memory record "${record}"`);
9057
9201
  const commits = limit2 !== void 0 ? c2.commits.slice(0, limit2) : c2.commits;
9058
9202
  return { commits };
@@ -64198,6 +64342,1711 @@ const EastChakraDecisionJournal = React.memo(function EastChakraDecisionJournal2
64198
64342
  ] });
64199
64343
  });
64200
64344
  eastUiComponents.implementUIComponent(internal$1.DecisionJournal.Component, EastChakraDecisionJournal);
64345
+ const studioMessages = {
64346
+ statusDraft: () => "Draft",
64347
+ statusLive: () => "Live",
64348
+ statusLiveEdited: () => "Live · edited",
64349
+ statusTemplate: () => "Template",
64350
+ publish: () => "Publish",
64351
+ noPageOpen: () => "No page open",
64352
+ noPageOpenHint: ({ project, page }) => `${project} has no page ${page}. Open a page from the palette's Pages tab, or start one from the page library.`,
64353
+ components: () => "Components",
64354
+ componentNoun: () => ({ singular: "component", plural: "components" }),
64355
+ pageNoun: () => ({ singular: "page", plural: "pages" }),
64356
+ logicFixed: () => "Logic fixed by the developer",
64357
+ category: () => "Category",
64358
+ tags: () => "Tags",
64359
+ collections: () => "Collections",
64360
+ inspector: () => "Inspector",
64361
+ spanBadge: ({ span }) => `${span}/12`,
64362
+ noComponent: ({ key }) => `No component "${key}"`,
64363
+ noComponentHint: () => "This surface lists no component with this key.",
64364
+ twoComponents: ({ key }) => `Two components share the key "${key}"`,
64365
+ twoComponentsHint: () => "A surface lists each component once.",
64366
+ notPublished: ({ page }) => `${page} is not published yet`,
64367
+ notPublishedHint: () => "Publish it to show it here.",
64368
+ noPage: ({ page }) => `No page ${page}`,
64369
+ noPageHint: ({ project }) => `The project ${project} has no page by this name.`,
64370
+ blankSummary: () => "12-col · empty",
64371
+ placements: ({ n: n2, count }) => `${count} ${n2 === 1 ? "component" : "components"}`,
64372
+ openInBuilder: () => "Open in builder →",
64373
+ newPageFromTemplate: () => "New page from template",
64374
+ selectedComponent: () => "Selected component",
64375
+ logicChanged: () => "logic changed since this page went live",
64376
+ data: () => "Data",
64377
+ readsNothing: () => "reads no data",
64378
+ configuration: () => "Configuration",
64379
+ fixedByDeveloper: () => "fixed by developer",
64380
+ noDescription: () => "No description",
64381
+ layout: () => "Layout",
64382
+ columnSpan: () => "Column span",
64383
+ spanOf: ({ span }) => `${span} / 12`,
64384
+ decreaseSpan: () => "Decrease span",
64385
+ increaseSpan: () => "Increase span",
64386
+ row: () => "Row",
64387
+ height: () => "Height",
64388
+ auto: () => "Auto",
64389
+ px: ({ px }) => `${px} px`,
64390
+ align: () => "Align",
64391
+ alignTop: () => "Top",
64392
+ alignCenter: () => "Center",
64393
+ alignStretch: () => "Stretch",
64394
+ published: () => "Published component · logic immutable",
64395
+ nothingSelected: () => "Nothing selected",
64396
+ nothingSelectedHint: () => "Click a component on the grid to see what it reads and its layout.",
64397
+ searchLibrary: ({ pages, templates, np, nt }) => `Search ${pages} ${np === 1 ? "page" : "pages"} and ${templates} ${nt === 1 ? "template" : "templates"}…`,
64398
+ searchLabel: () => "Search pages and templates",
64399
+ clearSearch: () => "Clear search",
64400
+ sortByName: () => "Sort · Name",
64401
+ nameAz: () => "Name A–Z",
64402
+ nameZa: () => "Name Z–A",
64403
+ newPageIn: ({ project }) => `New page in ${project}`,
64404
+ newPage: () => "New page",
64405
+ projects: () => "Projects",
64406
+ pages: () => "Pages",
64407
+ live: () => "Live",
64408
+ draft: () => "Draft",
64409
+ templates: () => "Templates",
64410
+ cloneToStart: () => "clone to start a page",
64411
+ pagesIn: ({ shown, total, project, narrowed }) => narrowed ? `${shown} of ${total} in ${project}` : `${total} in ${project}`,
64412
+ pageName: () => "Page name",
64413
+ pageNameMissing: () => "Give the page a name to create it.",
64414
+ template: () => "Template",
64415
+ blankGrid: () => "Blank grid",
64416
+ createPage: () => "Create page",
64417
+ cancel: () => "Cancel",
64418
+ nameTaken: ({ name }) => `${name} is already a page or a template here.`,
64419
+ saveAsTemplate: () => "Save as template",
64420
+ templateName: () => "Template name",
64421
+ templateNameMissing: () => "Give the template a name to save it.",
64422
+ saveTemplate: () => "Save template",
64423
+ templateNameFor: ({ page }) => `${page} template`,
64424
+ templateOpen: () => "A template is open — open a page to save it as a template",
64425
+ preview: () => "Preview",
64426
+ devices: () => "Device",
64427
+ device: ({ device }) => device === "desktop" ? "Desktop" : device === "tablet" ? "Tablet" : "Mobile",
64428
+ env: () => "Env",
64429
+ exit: () => "Exit",
64430
+ readyToPublish: () => "Ready to publish",
64431
+ upToDate: () => "Up to date",
64432
+ templateNotPublished: () => "Templates are not published",
64433
+ version: ({ version: version2 }) => `v${version2}`,
64434
+ liveVersion: () => "live",
64435
+ templateKind: () => "template",
64436
+ changesSince: ({ n: n2, count, version: version2 }) => `${count} ${n2 === 1 ? "change" : "changes"} since ${version2}`,
64437
+ changesFirst: ({ n: n2, count }) => `${count} ${n2 === 1 ? "change" : "changes"} · first version`,
64438
+ noChangesSince: ({ version: version2 }) => `No changes since ${version2}`,
64439
+ changeVerb: ({ change }) => {
64440
+ switch (change) {
64441
+ case "added":
64442
+ return "Added";
64443
+ case "removed":
64444
+ return "Removed";
64445
+ case "moved":
64446
+ return "Moved";
64447
+ case "resized":
64448
+ case "height":
64449
+ return "Resized";
64450
+ case "aligned":
64451
+ return "Aligned";
64452
+ case "retitled":
64453
+ return "Retitled";
64454
+ }
64455
+ },
64456
+ logicUnchanged: () => "Component logic unchanged — only layout changed. Safe to publish.",
64457
+ logicChangedIn: ({ version: version2, components: components2 }) => {
64458
+ const names = components2.length < 2 ? components2.join("") : `${components2.slice(0, -1).join(", ")} and ${components2.at(-1)}`;
64459
+ const its = components2.length === 1 ? "its" : "their";
64460
+ return `Logic changed since ${version2} in ${names} — ${its} placements publish with ${its} new code`;
64461
+ },
64462
+ audience: () => "Audience",
64463
+ rollout: () => "Rollout",
64464
+ saveAsDraft: () => "Save as draft",
64465
+ publishTo: ({ version: version2, env }) => version2 === void 0 ? "Publish" : env === void 0 ? `Publish ${version2}` : `Publish ${version2} to ${env}`
64466
+ };
64467
+ const StudioMessagesContext = React.createContext(studioMessages);
64468
+ function useStudioMessages() {
64469
+ return React.useContext(StudioMessagesContext);
64470
+ }
64471
+ function StudioMessagesProvider({ messages, children: children2 }) {
64472
+ const parent4 = useStudioMessages();
64473
+ const value = React.useMemo(() => ({ ...parent4, ...messages }), [parent4, messages]);
64474
+ return React.createElement(StudioMessagesContext.Provider, { value }, children2);
64475
+ }
64476
+ const LEAST_SPAN = 2;
64477
+ const HEIGHTS = [160, 240, 320, 400, 480];
64478
+ const ALIGNS = [
64479
+ { align: "top", icon: faArrowsUpToLine, name: (m2) => m2.alignTop() },
64480
+ { align: "center", icon: faArrowsToDot, name: (m2) => m2.alignCenter() },
64481
+ { align: "stretch", icon: faArrowsUpDown, name: (m2) => m2.alignStretch() }
64482
+ ];
64483
+ function RowField({ row, onRow, css: css2, id: id3 }) {
64484
+ const [text, setText] = React.useState(String(row));
64485
+ React.useEffect(() => {
64486
+ setText(String(row));
64487
+ }, [row]);
64488
+ const commit = () => {
64489
+ const asked = Number.parseInt(text, 10);
64490
+ if (!Number.isInteger(asked) || asked < 1 || asked === row) {
64491
+ setText(String(row));
64492
+ return;
64493
+ }
64494
+ onRow(asked);
64495
+ };
64496
+ const onKeyDown = (e3) => {
64497
+ if (e3.key === "Enter") {
64498
+ e3.preventDefault();
64499
+ commit();
64500
+ } else if (e3.key === "Escape") {
64501
+ e3.preventDefault();
64502
+ setText(String(row));
64503
+ } else if (e3.key === "ArrowUp") {
64504
+ e3.preventDefault();
64505
+ onRow(row + 1);
64506
+ } else if (e3.key === "ArrowDown" && row > 1) {
64507
+ e3.preventDefault();
64508
+ onRow(row - 1);
64509
+ }
64510
+ };
64511
+ return /* @__PURE__ */ jsxRuntime.jsx(
64512
+ react.chakra.input,
64513
+ {
64514
+ id: id3,
64515
+ css: css2,
64516
+ value: text,
64517
+ inputMode: "numeric",
64518
+ autoComplete: "off",
64519
+ "data-inspector-row": "",
64520
+ onChange: (e3) => setText(e3.target.value.replace(/[^0-9]/g, "")),
64521
+ onBlur: commit,
64522
+ onKeyDown
64523
+ }
64524
+ );
64525
+ }
64526
+ const StudioInspector = React.memo(function StudioInspector2({ value }) {
64527
+ const styles2 = react.useSlotRecipe({ key: "studioInspector" })();
64528
+ const stepper = react.useSlotRecipe({ key: "stepper" })({ tone: "brand", size: "md" });
64529
+ const seg = react.useSlotRecipe({ key: "seg" })();
64530
+ const input = react.useRecipe({ key: "input" })({ variant: "numeric", size: "sm" });
64531
+ const m2 = useStudioMessages();
64532
+ const words = eastUiComponents.useFormatters();
64533
+ const rowId = React.useId();
64534
+ const selection2 = value.selection.type === "some" ? value.selection.value : void 0;
64535
+ const onRequest = value.onRequest;
64536
+ const key = selection2 == null ? void 0 : selection2.key;
64537
+ const ask = React.useCallback((change) => {
64538
+ if (key === void 0) return;
64539
+ try {
64540
+ onRequest({ key, change });
64541
+ } catch (err) {
64542
+ console.error("[Studio.Builder] the inspector's layout request failed:", err);
64543
+ }
64544
+ }, [key, onRequest]);
64545
+ const height2 = selection2 !== void 0 && selection2.layout.height.type === "some" ? Number(selection2.layout.height.value) : void 0;
64546
+ const heights = React.useMemo(() => react.createListCollection({
64547
+ items: [
64548
+ { value: "auto", label: m2.auto(), px: void 0 },
64549
+ ...[.../* @__PURE__ */ new Set([...HEIGHTS, ...height2 !== void 0 ? [height2] : []])].sort((a2, b2) => a2 - b2).map((px) => ({ value: String(px), label: m2.px({ px: words.bare(px) }), px }))
64550
+ ]
64551
+ }), [height2, m2, words]);
64552
+ if (selection2 === void 0) {
64553
+ return /* @__PURE__ */ jsxRuntime.jsx(react.Box, { css: styles2.root, "data-studio-inspector": "", children: /* @__PURE__ */ jsxRuntime.jsxs(react.Box, { css: styles2.empty, "data-inspector": "empty", children: [
64554
+ /* @__PURE__ */ jsxRuntime.jsx(react.Box, { as: "span", css: styles2.emptyTitle, children: m2.nothingSelected() }),
64555
+ /* @__PURE__ */ jsxRuntime.jsx(react.Box, { as: "span", css: styles2.emptyHint, children: m2.nothingSelectedHint() })
64556
+ ] }) });
64557
+ }
64558
+ const layout4 = selection2.layout;
64559
+ const span = Number(layout4.span);
64560
+ const most = Number(layout4.most);
64561
+ const description = selection2.description.type === "some" ? selection2.description.value : void 0;
64562
+ const aligned = layout4.align.type;
64563
+ const heightKey = height2 === void 0 ? "auto" : String(height2);
64564
+ return /* @__PURE__ */ jsxRuntime.jsxs(react.Box, { css: styles2.root, "data-studio-inspector": "", children: [
64565
+ /* @__PURE__ */ jsxRuntime.jsxs(react.Box, { css: styles2.selection, "data-inspector": "selection", children: [
64566
+ /* @__PURE__ */ jsxRuntime.jsx(react.Box, { as: "span", css: styles2.eyebrow, children: m2.selectedComponent() }),
64567
+ /* @__PURE__ */ jsxRuntime.jsx(react.Box, { as: "span", css: styles2.name, "data-inspector-name": "", children: selection2.name }),
64568
+ /* @__PURE__ */ jsxRuntime.jsx(react.Box, { as: "span", css: styles2.meta, "data-inspector-meta": "", children: selection2.component }),
64569
+ selection2.changed && /* @__PURE__ */ jsxRuntime.jsxs(react.Box, { as: "span", css: styles2.warning, "data-inspector-changed": "", children: [
64570
+ /* @__PURE__ */ jsxRuntime.jsx(FontAwesomeIcon, { icon: faTriangleExclamation }),
64571
+ m2.logicChanged()
64572
+ ] })
64573
+ ] }),
64574
+ /* @__PURE__ */ jsxRuntime.jsxs(react.Box, { css: styles2.data, "data-inspector": "data", children: [
64575
+ /* @__PURE__ */ jsxRuntime.jsx(react.Box, { as: "span", css: styles2.eyebrow, children: m2.data() }),
64576
+ selection2.reads.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(react.Box, { as: "ul", css: styles2.reads, "aria-label": m2.data(), children: selection2.reads.map((path2) => {
64577
+ const keypath = e3Types.pathToString(path2);
64578
+ return /* @__PURE__ */ jsxRuntime.jsx(react.Box, { as: "li", css: styles2.read, children: keypath }, keypath);
64579
+ }) }) : /* @__PURE__ */ jsxRuntime.jsx(react.Box, { as: "span", css: styles2.noReads, children: m2.readsNothing() })
64580
+ ] }),
64581
+ /* @__PURE__ */ jsxRuntime.jsxs(react.Box, { css: styles2.config, "data-inspector": "config", children: [
64582
+ /* @__PURE__ */ jsxRuntime.jsxs(react.Box, { css: styles2.configHead, children: [
64583
+ /* @__PURE__ */ jsxRuntime.jsx(react.Box, { as: "span", css: styles2.eyebrow, children: m2.configuration() }),
64584
+ /* @__PURE__ */ jsxRuntime.jsxs(react.Box, { as: "span", css: styles2.lockNote, children: [
64585
+ /* @__PURE__ */ jsxRuntime.jsx(FontAwesomeIcon, { icon: faLock }),
64586
+ m2.fixedByDeveloper()
64587
+ ] })
64588
+ ] }),
64589
+ /* @__PURE__ */ jsxRuntime.jsx(react.Box, { as: "p", css: styles2.description, "data-empty": description === void 0 ? "" : void 0, children: description ?? m2.noDescription() })
64590
+ ] }),
64591
+ /* @__PURE__ */ jsxRuntime.jsxs(react.Box, { css: styles2.layout, "data-inspector": "layout", children: [
64592
+ /* @__PURE__ */ jsxRuntime.jsx(react.Box, { as: "span", css: styles2.eyebrow, children: m2.layout() }),
64593
+ /* @__PURE__ */ jsxRuntime.jsxs(react.Box, { css: styles2.field, children: [
64594
+ /* @__PURE__ */ jsxRuntime.jsx(react.Box, { as: "span", css: styles2.fieldLabel, children: m2.columnSpan() }),
64595
+ /* @__PURE__ */ jsxRuntime.jsxs(react.Box, { css: stepper.root, role: "group", "aria-label": m2.columnSpan(), children: [
64596
+ /* @__PURE__ */ jsxRuntime.jsx(
64597
+ react.chakra.button,
64598
+ {
64599
+ type: "button",
64600
+ css: stepper.button,
64601
+ "aria-label": m2.decreaseSpan(),
64602
+ title: m2.decreaseSpan(),
64603
+ disabled: span <= LEAST_SPAN,
64604
+ onClick: () => ask(east.variant("span", BigInt(span - 1))),
64605
+ children: /* @__PURE__ */ jsxRuntime.jsx(FontAwesomeIcon, { icon: faMinus })
64606
+ }
64607
+ ),
64608
+ /* @__PURE__ */ jsxRuntime.jsx(react.Box, { as: "output", css: stepper.value, "data-inspector-span": "", children: m2.spanOf({ span: words.number(span) }) }),
64609
+ /* @__PURE__ */ jsxRuntime.jsx(
64610
+ react.chakra.button,
64611
+ {
64612
+ type: "button",
64613
+ css: stepper.button,
64614
+ "aria-label": m2.increaseSpan(),
64615
+ title: m2.increaseSpan(),
64616
+ disabled: span >= most,
64617
+ onClick: () => ask(east.variant("span", BigInt(span + 1))),
64618
+ children: /* @__PURE__ */ jsxRuntime.jsx(FontAwesomeIcon, { icon: faPlus })
64619
+ }
64620
+ )
64621
+ ] })
64622
+ ] }),
64623
+ /* @__PURE__ */ jsxRuntime.jsxs(react.Box, { css: styles2.field, children: [
64624
+ /* @__PURE__ */ jsxRuntime.jsx(react.chakra.label, { css: styles2.fieldLabel, htmlFor: rowId, children: m2.row() }),
64625
+ /* @__PURE__ */ jsxRuntime.jsx(RowField, { row: Number(layout4.row), onRow: (row) => ask(east.variant("row", BigInt(row))), css: [input, styles2.rowField], id: rowId })
64626
+ ] }),
64627
+ /* @__PURE__ */ jsxRuntime.jsxs(react.Box, { css: styles2.field, children: [
64628
+ /* @__PURE__ */ jsxRuntime.jsx(react.Box, { as: "span", css: styles2.fieldLabel, children: m2.height() }),
64629
+ /* @__PURE__ */ jsxRuntime.jsxs(
64630
+ react.Select.Root,
64631
+ {
64632
+ collection: heights,
64633
+ value: [heightKey],
64634
+ size: "sm",
64635
+ variant: "numeric",
64636
+ css: styles2.heightField,
64637
+ onValueChange: (details) => {
64638
+ const picked = heights.items.find((item) => item.value === details.value[0]);
64639
+ if (picked === void 0 || picked.value === heightKey) return;
64640
+ const px = picked.px;
64641
+ queueMicrotask(() => ask(east.variant("height", px === void 0 ? east.none : east.some(BigInt(px)))));
64642
+ },
64643
+ children: [
64644
+ /* @__PURE__ */ jsxRuntime.jsx(react.Select.HiddenSelect, {}),
64645
+ /* @__PURE__ */ jsxRuntime.jsxs(react.Select.Control, { children: [
64646
+ /* @__PURE__ */ jsxRuntime.jsx(react.Select.Trigger, { "aria-label": m2.height(), "data-inspector-height": "", children: /* @__PURE__ */ jsxRuntime.jsx(react.Select.ValueText, {}) }),
64647
+ /* @__PURE__ */ jsxRuntime.jsx(react.Select.IndicatorGroup, { children: /* @__PURE__ */ jsxRuntime.jsx(react.Select.Indicator, {}) })
64648
+ ] }),
64649
+ /* @__PURE__ */ jsxRuntime.jsx(react.Portal, { children: /* @__PURE__ */ jsxRuntime.jsx(react.Select.Positioner, { children: /* @__PURE__ */ jsxRuntime.jsx(react.Select.Content, { children: heights.items.map((item) => /* @__PURE__ */ jsxRuntime.jsxs(react.Select.Item, { item, children: [
64650
+ item.label,
64651
+ /* @__PURE__ */ jsxRuntime.jsx(react.Select.ItemIndicator, {})
64652
+ ] }, item.value)) }) }) })
64653
+ ]
64654
+ }
64655
+ )
64656
+ ] }),
64657
+ /* @__PURE__ */ jsxRuntime.jsxs(react.Box, { css: styles2.field, children: [
64658
+ /* @__PURE__ */ jsxRuntime.jsx(react.Box, { as: "span", css: styles2.fieldLabel, children: m2.align() }),
64659
+ /* @__PURE__ */ jsxRuntime.jsx(react.Box, { css: seg.root, role: "group", "aria-label": m2.align(), children: ALIGNS.map(({ align, icon: icon3, name }) => /* @__PURE__ */ jsxRuntime.jsx(
64660
+ react.chakra.button,
64661
+ {
64662
+ type: "button",
64663
+ css: seg.item,
64664
+ "data-state": aligned === align ? "on" : "off",
64665
+ "aria-pressed": aligned === align,
64666
+ "aria-label": name(m2),
64667
+ title: name(m2),
64668
+ onClick: () => ask(east.variant("align", east.variant(align, null))),
64669
+ children: /* @__PURE__ */ jsxRuntime.jsx(FontAwesomeIcon, { icon: icon3 })
64670
+ },
64671
+ align
64672
+ )) })
64673
+ ] })
64674
+ ] }),
64675
+ /* @__PURE__ */ jsxRuntime.jsxs(react.Box, { css: styles2.footer, "data-inspector": "footer", children: [
64676
+ /* @__PURE__ */ jsxRuntime.jsx(FontAwesomeIcon, { icon: faLock }),
64677
+ m2.published()
64678
+ ] })
64679
+ ] });
64680
+ });
64681
+ const encodeKey = east.encodeBeast2For(internal$1.StudioKeyType);
64682
+ const decodeKey = east.decodeBeast2For(internal$1.StudioKeyType);
64683
+ function useOpenPage(key, first2) {
64684
+ const store = eastUiComponents.StateRuntime.getStore();
64685
+ const subscribe = React.useCallback((notify3) => store.subscribe(key, notify3), [store, key]);
64686
+ const snapshot = React.useCallback(() => store.read(key), [store, key]);
64687
+ const bytes = React.useSyncExternalStore(subscribe, snapshot);
64688
+ const open = React.useMemo(() => bytes === void 0 ? first2 : decodeKey(bytes), [bytes, first2]);
64689
+ const write = React.useCallback((next2) => {
64690
+ store.write(key, encodeKey(next2));
64691
+ }, [store, key]);
64692
+ return [open, write];
64693
+ }
64694
+ const pageEqual = east.equivalentFor(internal$1.StudioPageComponent.schema);
64695
+ const keyEqual$1 = east.equalFor(internal$1.StudioKeyType);
64696
+ function StudioComponentView({ component: component2, storageKey }) {
64697
+ const render3 = React.useCallback(() => component2.render(), [component2]);
64698
+ const { result } = eastUiComponents.useTrackedEvaluation(render3);
64699
+ if (!result.ok) {
64700
+ const message = result.error instanceof Error ? result.error.message : String(result.error);
64701
+ return /* @__PURE__ */ jsxRuntime.jsx(eastUiComponents.BannerView, { status: "error", title: component2.name, description: message });
64702
+ }
64703
+ return /* @__PURE__ */ jsxRuntime.jsx(eastUiComponents.EastChakraComponent, { value: result.value, storageKey });
64704
+ }
64705
+ function StudioPlacement({ component: key, listed, storageKey }) {
64706
+ const m2 = useStudioMessages();
64707
+ if (listed.length > 1) {
64708
+ return /* @__PURE__ */ jsxRuntime.jsx(eastUiComponents.BannerView, { status: "error", title: m2.twoComponents({ key }), description: m2.twoComponentsHint() });
64709
+ }
64710
+ const component2 = listed[0];
64711
+ if (component2 === void 0) {
64712
+ return /* @__PURE__ */ jsxRuntime.jsx(
64713
+ eastUiComponents.EmptyStateView,
64714
+ {
64715
+ icon: { prefix: "fas", name: "puzzle-piece" },
64716
+ title: m2.noComponent({ key }),
64717
+ description: m2.noComponentHint()
64718
+ }
64719
+ );
64720
+ }
64721
+ return /* @__PURE__ */ jsxRuntime.jsx(StudioComponentView, { component: component2, storageKey });
64722
+ }
64723
+ function StudioLayout({ cells, components: components2, storageKey }) {
64724
+ const listed = React.useMemo(() => {
64725
+ const byKey = /* @__PURE__ */ new Map();
64726
+ for (const component2 of components2) {
64727
+ const same2 = byKey.get(component2.key);
64728
+ if (same2 === void 0) byKey.set(component2.key, [component2]);
64729
+ else same2.push(component2);
64730
+ }
64731
+ return byKey;
64732
+ }, [components2]);
64733
+ const tiles = React.useMemo(() => cells.map((cell) => {
64734
+ var _a2;
64735
+ const first2 = (_a2 = listed.get(cell.component)) == null ? void 0 : _a2[0];
64736
+ return {
64737
+ key: cell.key,
64738
+ row: cell.row,
64739
+ span: cell.span,
64740
+ height: cell.height,
64741
+ align: cell.align,
64742
+ frame: first2 === void 0 ? true : first2.frame.type === "card",
64743
+ cell
64744
+ };
64745
+ }), [cells, listed]);
64746
+ return /* @__PURE__ */ jsxRuntime.jsx(
64747
+ eastUiComponents.SnapGridTiles,
64748
+ {
64749
+ cells: tiles,
64750
+ content: (tile) => /* @__PURE__ */ jsxRuntime.jsx(StudioPlacement, { component: tile.cell.component, listed: listed.get(tile.cell.component) ?? [], storageKey: `${storageKey}.${tile.key}` })
64751
+ }
64752
+ );
64753
+ }
64754
+ const EastChakraStudioPage = React.memo(function EastChakraStudioPage2({ value, storageKey }) {
64755
+ const m2 = useStudioMessages();
64756
+ const key = value.page;
64757
+ let entry;
64758
+ for (const [at, found] of value.pages) {
64759
+ if (keyEqual$1(at, key)) {
64760
+ entry = found;
64761
+ break;
64762
+ }
64763
+ }
64764
+ if (entry === void 0) {
64765
+ return /* @__PURE__ */ jsxRuntime.jsx(
64766
+ eastUiComponents.EmptyStateView,
64767
+ {
64768
+ icon: { prefix: "fas", name: "file-circle-question" },
64769
+ title: m2.noPage({ page: key.page }),
64770
+ description: m2.noPageHint({ project: key.project })
64771
+ }
64772
+ );
64773
+ }
64774
+ const layout4 = entry.type === "template" ? entry.value : value.version.type === "draft" ? entry.value.draft : entry.value.live.type === "some" ? entry.value.live.value.page : void 0;
64775
+ if (layout4 === void 0) {
64776
+ return /* @__PURE__ */ jsxRuntime.jsx(
64777
+ eastUiComponents.EmptyStateView,
64778
+ {
64779
+ icon: { prefix: "fas", name: "file-circle-question" },
64780
+ title: m2.notPublished({ page: key.page }),
64781
+ description: m2.notPublishedHint()
64782
+ }
64783
+ );
64784
+ }
64785
+ return /* @__PURE__ */ jsxRuntime.jsx(StudioLayout, { cells: layout4.cells, components: value.components, storageKey });
64786
+ }, (prev2, next2) => pageEqual(prev2.value, next2.value) && prev2.storageKey === next2.storageKey);
64787
+ eastUiComponents.implementUIComponent(internal$1.StudioPageComponent, EastChakraStudioPage);
64788
+ const StudioPalette = React.memo(function StudioPalette2({
64789
+ components: components2,
64790
+ cards,
64791
+ pages,
64792
+ open,
64793
+ ids,
64794
+ onSelect,
64795
+ onOpen,
64796
+ storageKey
64797
+ }) {
64798
+ const m2 = useStudioMessages();
64799
+ const words = eastUiComponents.useFormatters();
64800
+ const componentsLibrary = React.useMemo(() => ({
64801
+ id: ids.components,
64802
+ hint: east.none,
64803
+ items: components2.map((component2) => {
64804
+ const card = cards.get(component2.key);
64805
+ return {
64806
+ key: component2.key,
64807
+ label: component2.name,
64808
+ sublabel: card === void 0 ? east.none : east.some(card.meta),
64809
+ icon: east.some(component2.icon),
64810
+ status: east.none,
64811
+ trailing: east.some({ icon: "lock", label: m2.logicFixed(), tone: east.none }),
64812
+ draggable: true,
64813
+ filtered: false,
64814
+ placed: (card == null ? void 0 : card.placed) ?? false,
64815
+ media: east.none,
64816
+ avatar: east.none,
64817
+ byline: east.none,
64818
+ action: east.none,
64819
+ search: east.some(`${component2.name} ${component2.category} ${component2.tags.join(" ")}`),
64820
+ groups: /* @__PURE__ */ new Map([["category", component2.category]]),
64821
+ facets: /* @__PURE__ */ new Map([["category", [component2.category]], ["tags", component2.tags], ["collections", component2.collections]]),
64822
+ dims: /* @__PURE__ */ new Map()
64823
+ };
64824
+ }),
64825
+ groupOptions: [{ key: "category", label: m2.category() }],
64826
+ groupSummaries: /* @__PURE__ */ new Map(),
64827
+ dimOptions: [],
64828
+ defaultDimensions: [],
64829
+ filterOptions: [
64830
+ { key: "category", label: m2.category() },
64831
+ { key: "tags", label: m2.tags() },
64832
+ { key: "collections", label: m2.collections() }
64833
+ ],
64834
+ searchable: true,
64835
+ noun: east.some(m2.componentNoun()),
64836
+ addLabel: east.none,
64837
+ onAdd: east.none,
64838
+ onCardClick: east.some((key) => {
64839
+ onSelect(key);
64840
+ return null;
64841
+ }),
64842
+ slice: east.none,
64843
+ style: east.some({ height: east.some("fill"), maxHeight: east.none, virtualization: east.some(false), columns: east.none, mediaPlacement: east.none, mediaSize: east.none }),
64844
+ variant: east.none,
64845
+ layout: east.none,
64846
+ toolbar: true
64847
+ }), [ids.components, components2, cards, m2, onSelect]);
64848
+ const pagesLibrary = React.useMemo(() => ({
64849
+ id: ids.pages,
64850
+ hint: east.none,
64851
+ items: pages.map((page) => ({
64852
+ key: page.page,
64853
+ label: page.title,
64854
+ sublabel: east.some(page.meta),
64855
+ icon: east.some("file-lines"),
64856
+ status: east.none,
64857
+ trailing: east.some({
64858
+ icon: "circle",
64859
+ label: page.live ? m2.live() : m2.draft(),
64860
+ tone: east.some(page.live ? east.variant("success", null) : east.variant("neutral", null))
64861
+ }),
64862
+ draggable: false,
64863
+ filtered: false,
64864
+ placed: page.page === open,
64865
+ media: east.none,
64866
+ avatar: east.none,
64867
+ byline: east.none,
64868
+ action: east.none,
64869
+ search: east.some(page.title),
64870
+ groups: /* @__PURE__ */ new Map(),
64871
+ facets: /* @__PURE__ */ new Map(),
64872
+ dims: /* @__PURE__ */ new Map()
64873
+ })),
64874
+ groupOptions: [],
64875
+ groupSummaries: /* @__PURE__ */ new Map(),
64876
+ dimOptions: [],
64877
+ defaultDimensions: [],
64878
+ filterOptions: [],
64879
+ searchable: true,
64880
+ noun: east.some(m2.pageNoun()),
64881
+ addLabel: east.none,
64882
+ onAdd: east.none,
64883
+ onCardClick: east.some((key) => {
64884
+ onOpen(key);
64885
+ return null;
64886
+ }),
64887
+ slice: east.none,
64888
+ style: east.some({ height: east.some("fill"), maxHeight: east.none, virtualization: east.some(false), columns: east.none, mediaPlacement: east.none, mediaSize: east.none }),
64889
+ variant: east.none,
64890
+ layout: east.none,
64891
+ toolbar: true
64892
+ }), [ids.pages, pages, open, m2, onOpen]);
64893
+ return /* @__PURE__ */ jsxRuntime.jsx(
64894
+ eastUiComponents.DockPane,
64895
+ {
64896
+ storageKey: `${storageKey}.palette`,
64897
+ icon: "shapes",
64898
+ label: m2.components(),
64899
+ badge: words.number(components2.length),
64900
+ expandedSize: "264px",
64901
+ railSize: "44px",
64902
+ side: "start",
64903
+ surface: "shell",
64904
+ tabs: [
64905
+ { key: "components", label: m2.components(), body: /* @__PURE__ */ jsxRuntime.jsx(eastUiComponents.EastChakraLibrary, { value: componentsLibrary, storageKey: `${storageKey}.palette.components` }) },
64906
+ { key: "pages", label: m2.pages(), body: /* @__PURE__ */ jsxRuntime.jsx(eastUiComponents.EastChakraLibrary, { value: pagesLibrary, storageKey: `${storageKey}.palette.pages` }) }
64907
+ ]
64908
+ }
64909
+ );
64910
+ });
64911
+ const DEVICES = [
64912
+ { device: "desktop", icon: faDesktop, width: 1440 },
64913
+ { device: "tablet", icon: faTabletScreenButton, width: 1024 },
64914
+ { device: "mobile", icon: faMobileScreen, width: 390 }
64915
+ ];
64916
+ const StudioPublishPreview = React.memo(function StudioPublishPreview2({ value, page }) {
64917
+ const styles2 = react.useSlotRecipe({ key: "studioPublish" })();
64918
+ const m2 = useStudioMessages();
64919
+ const words = eastUiComponents.useFormatters();
64920
+ const [device, setDevice] = React.useState("desktop");
64921
+ const [phase, setPhase] = React.useState({ kind: "idle" });
64922
+ const latest = React.useRef(value);
64923
+ latest.current = value;
64924
+ const summary = value.summary;
64925
+ const standing = summary.standing.type;
64926
+ const live = summary.live.type === "some" ? summary.live.value : void 0;
64927
+ const liveVersion = live === void 0 ? "" : m2.version({ version: words.number(live) });
64928
+ const nextVersion = m2.version({ version: words.number(live === void 0 ? 1n : live + 1n) });
64929
+ const env = value.env.type === "some" ? value.env.value : void 0;
64930
+ const exit = value.onExit.type === "some" ? value.onExit.value : void 0;
64931
+ const busy = phase.kind === "applying" || phase.kind === "publishing";
64932
+ const width2 = DEVICES.find((d2) => d2.device === device).width;
64933
+ const publish = React.useCallback(async () => {
64934
+ setPhase({ kind: "publishing" });
64935
+ let reason;
64936
+ try {
64937
+ const refused = await latest.current.onPublish();
64938
+ reason = refused.type === "some" ? refused.value : void 0;
64939
+ } catch (err) {
64940
+ reason = err instanceof Error ? err.message : String(err);
64941
+ }
64942
+ setPhase(reason === void 0 ? { kind: "idle" } : { kind: "refused", reason });
64943
+ }, []);
64944
+ const ask = (then2) => {
64945
+ const id3 = Array.from(crypto.getRandomValues(new Uint8Array(8)), (b2) => b2.toString(16).padStart(2, "0")).join("");
64946
+ setPhase({ kind: "applying", id: id3, publish: then2 === "publish" });
64947
+ const onApply = value.onApply;
64948
+ queueMicrotask(() => {
64949
+ try {
64950
+ onApply(id3);
64951
+ } catch (err) {
64952
+ setPhase({ kind: "refused", reason: err instanceof Error ? err.message : String(err) });
64953
+ }
64954
+ });
64955
+ };
64956
+ const answer = value.apply;
64957
+ React.useEffect(() => {
64958
+ if (phase.kind !== "applying") return;
64959
+ if (answer.type === "applied" && answer.value === phase.id) {
64960
+ if (phase.publish) void publish();
64961
+ else setPhase({ kind: "idle" });
64962
+ } else if (answer.type === "refused" && answer.value.id === phase.id) {
64963
+ setPhase({ kind: "refused", reason: answer.value.reason });
64964
+ }
64965
+ }, [answer, phase, publish]);
64966
+ const changes = summary.changes;
64967
+ const changed = summary.changed;
64968
+ const count = changes.length;
64969
+ const head = standing === "ready" ? m2.readyToPublish() : standing === "current" ? m2.upToDate() : m2.templateNotPublished();
64970
+ const listHead = live === void 0 ? m2.changesFirst({ n: count, count: words.number(count) }) : count === 0 ? m2.noChangesSince({ version: liveVersion }) : m2.changesSince({ n: count, count: words.number(count), version: liveVersion });
64971
+ const tone = changed.length === 0 ? "change" : "warning";
64972
+ const audience = value.audience.type === "some" ? value.audience.value : void 0;
64973
+ const rollout = value.rollout.type === "some" ? value.rollout.value : void 0;
64974
+ return /* @__PURE__ */ jsxRuntime.jsxs(react.Box, { css: styles2.root, "data-studio-publish": "", children: [
64975
+ /* @__PURE__ */ jsxRuntime.jsxs(react.Box, { css: styles2.bar, "data-publish-bar": "", children: [
64976
+ /* @__PURE__ */ jsxRuntime.jsxs(react.Box, { as: "span", css: styles2.barLabel, children: [
64977
+ /* @__PURE__ */ jsxRuntime.jsx(react.Box, { as: "span", css: styles2.barDot, "aria-hidden": true }),
64978
+ m2.preview()
64979
+ ] }),
64980
+ /* @__PURE__ */ jsxRuntime.jsx(react.Box, { css: styles2.devices, role: "group", "aria-label": m2.devices(), "data-publish-devices": "", children: DEVICES.map(({ device: d2, icon: icon3 }) => /* @__PURE__ */ jsxRuntime.jsxs(
64981
+ react.chakra.button,
64982
+ {
64983
+ type: "button",
64984
+ css: styles2.device,
64985
+ "data-state": device === d2 ? "on" : "off",
64986
+ "aria-pressed": device === d2,
64987
+ "data-publish-device": d2,
64988
+ onClick: () => setDevice(d2),
64989
+ children: [
64990
+ /* @__PURE__ */ jsxRuntime.jsx(react.Box, { as: "span", css: styles2.deviceIcon, "aria-hidden": true, children: /* @__PURE__ */ jsxRuntime.jsx(FontAwesomeIcon, { icon: icon3 }) }),
64991
+ m2.device({ device: d2 })
64992
+ ]
64993
+ },
64994
+ d2
64995
+ )) }),
64996
+ env !== void 0 && /* @__PURE__ */ jsxRuntime.jsxs(react.Box, { as: "span", css: styles2.env, "data-publish-env": "", children: [
64997
+ m2.env(),
64998
+ " ·",
64999
+ /* @__PURE__ */ jsxRuntime.jsx(react.Box, { as: "span", css: styles2.envName, children: env }),
65000
+ /* @__PURE__ */ jsxRuntime.jsx(react.Box, { as: "span", css: styles2.envCaret, "aria-hidden": true, children: /* @__PURE__ */ jsxRuntime.jsx(FontAwesomeIcon, { icon: faChevronDown }) })
65001
+ ] }),
65002
+ /* @__PURE__ */ jsxRuntime.jsx(
65003
+ react.chakra.button,
65004
+ {
65005
+ type: "button",
65006
+ css: styles2.exit,
65007
+ disabled: exit === void 0,
65008
+ "data-publish-exit": "",
65009
+ onClick: () => {
65010
+ if (exit !== void 0) queueMicrotask(() => exit());
65011
+ },
65012
+ children: m2.exit()
65013
+ }
65014
+ )
65015
+ ] }),
65016
+ /* @__PURE__ */ jsxRuntime.jsxs(react.Box, { css: styles2.body, children: [
65017
+ /* @__PURE__ */ jsxRuntime.jsx(react.Box, { css: styles2.main, "data-publish-main": "", children: /* @__PURE__ */ jsxRuntime.jsxs(react.Box, { css: styles2.frame, style: { maxWidth: `${width2}px` }, "data-publish-frame": device, children: [
65018
+ /* @__PURE__ */ jsxRuntime.jsxs(react.Box, { css: styles2.head, children: [
65019
+ /* @__PURE__ */ jsxRuntime.jsx(react.Box, { as: "span", css: styles2.eyebrow, children: value.project }),
65020
+ /* @__PURE__ */ jsxRuntime.jsx(react.Box, { as: "h2", css: styles2.title, children: value.title })
65021
+ ] }),
65022
+ page
65023
+ ] }) }),
65024
+ /* @__PURE__ */ jsxRuntime.jsxs(react.Box, { as: "aside", css: styles2.aside, "aria-label": head, "data-publish-aside": "", children: [
65025
+ /* @__PURE__ */ jsxRuntime.jsxs(react.Box, { css: styles2.asideHead, children: [
65026
+ /* @__PURE__ */ jsxRuntime.jsx(react.Box, { as: "span", css: styles2.asideTitle, "data-publish-head": "", children: head }),
65027
+ /* @__PURE__ */ jsxRuntime.jsxs(react.Box, { as: "span", css: styles2.asideSub, "data-publish-versions": "", children: [
65028
+ value.title,
65029
+ " ·",
65030
+ " ",
65031
+ standing === "template" ? m2.templateKind() : standing === "current" ? `${liveVersion} ${m2.liveVersion()}` : live === void 0 ? /* @__PURE__ */ jsxRuntime.jsx(react.Box, { as: "span", css: styles2.asideVersion, children: nextVersion }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
65032
+ liveVersion,
65033
+ " → ",
65034
+ /* @__PURE__ */ jsxRuntime.jsx(react.Box, { as: "span", css: styles2.asideVersion, children: nextVersion })
65035
+ ] })
65036
+ ] })
65037
+ ] }),
65038
+ /* @__PURE__ */ jsxRuntime.jsxs(react.Box, { css: styles2.asideBody, children: [
65039
+ standing !== "template" && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
65040
+ /* @__PURE__ */ jsxRuntime.jsx(react.Box, { as: "span", css: styles2.listHead, "data-publish-count": "", children: listHead }),
65041
+ count > 0 && /* @__PURE__ */ jsxRuntime.jsx(react.Box, { as: "ul", css: styles2.list, "aria-label": listHead, "data-publish-changes": "", children: changes.map((row, i) => {
65042
+ const kind = row.change.type;
65043
+ return /* @__PURE__ */ jsxRuntime.jsxs(react.Box, { as: "li", css: styles2.change, "data-publish-change": kind, children: [
65044
+ /* @__PURE__ */ jsxRuntime.jsx(react.Box, { as: "span", css: styles2.sign, "data-sign": kind, "aria-hidden": true, children: kind === "added" ? "+" : kind === "removed" ? "−" : "±" }),
65045
+ /* @__PURE__ */ jsxRuntime.jsxs(react.Box, { css: styles2.changeText, children: [
65046
+ /* @__PURE__ */ jsxRuntime.jsxs(react.Box, { as: "span", css: styles2.changeLine, children: [
65047
+ m2.changeVerb({ change: kind }),
65048
+ " ",
65049
+ /* @__PURE__ */ jsxRuntime.jsx(react.Box, { as: "strong", css: styles2.changeName, children: row.name })
65050
+ ] }),
65051
+ /* @__PURE__ */ jsxRuntime.jsx(react.Box, { as: "span", css: styles2.changeDetail, children: row.change.value.detail })
65052
+ ] })
65053
+ ] }, `${row.change.value.cell}-${kind}-${i}`);
65054
+ }) }),
65055
+ standing === "ready" && live !== void 0 && /* @__PURE__ */ jsxRuntime.jsxs(
65056
+ react.Box,
65057
+ {
65058
+ css: styles2.banner,
65059
+ layerStyle: tone === "change" ? "banner.change" : "banner.guard",
65060
+ "data-tone": tone,
65061
+ role: tone === "warning" ? "alert" : "status",
65062
+ "data-publish-banner": tone,
65063
+ children: [
65064
+ /* @__PURE__ */ jsxRuntime.jsx(react.Box, { as: "span", css: styles2.bannerGlyph, "aria-hidden": true, children: tone === "change" ? "△" : "!" }),
65065
+ /* @__PURE__ */ jsxRuntime.jsx(react.Box, { as: "span", css: styles2.bannerText, children: tone === "change" ? m2.logicUnchanged() : m2.logicChangedIn({ version: liveVersion, components: changed }) })
65066
+ ]
65067
+ }
65068
+ )
65069
+ ] }),
65070
+ (audience !== void 0 || rollout !== void 0) && /* @__PURE__ */ jsxRuntime.jsxs(react.Box, { css: styles2.facts, "data-publish-facts": "", children: [
65071
+ audience !== void 0 && /* @__PURE__ */ jsxRuntime.jsxs(react.Box, { css: styles2.fact, children: [
65072
+ /* @__PURE__ */ jsxRuntime.jsx(react.Box, { as: "span", css: styles2.factLabel, children: m2.audience() }),
65073
+ /* @__PURE__ */ jsxRuntime.jsx(react.Box, { as: "span", css: styles2.factValue, children: audience })
65074
+ ] }),
65075
+ rollout !== void 0 && /* @__PURE__ */ jsxRuntime.jsxs(react.Box, { css: styles2.fact, children: [
65076
+ /* @__PURE__ */ jsxRuntime.jsx(react.Box, { as: "span", css: styles2.factLabel, children: m2.rollout() }),
65077
+ /* @__PURE__ */ jsxRuntime.jsx(react.Box, { as: "span", css: styles2.factValue, children: rollout })
65078
+ ] })
65079
+ ] }),
65080
+ phase.kind === "refused" && /* @__PURE__ */ jsxRuntime.jsx(react.Box, { as: "span", role: "alert", css: styles2.refusal, "data-publish-refused": "", children: phase.reason })
65081
+ ] }),
65082
+ /* @__PURE__ */ jsxRuntime.jsxs(react.Box, { css: styles2.foot, "data-publish-foot": "", children: [
65083
+ /* @__PURE__ */ jsxRuntime.jsx(
65084
+ react.Button,
65085
+ {
65086
+ type: "button",
65087
+ variant: "outline",
65088
+ size: "sm",
65089
+ "data-publish-save": "",
65090
+ disabled: !summary.unsaved || busy,
65091
+ loading: phase.kind === "applying" && !phase.publish,
65092
+ onClick: () => ask("save"),
65093
+ children: m2.saveAsDraft()
65094
+ }
65095
+ ),
65096
+ /* @__PURE__ */ jsxRuntime.jsx(
65097
+ react.Button,
65098
+ {
65099
+ type: "button",
65100
+ size: "sm",
65101
+ colorPalette: "brand",
65102
+ "data-publish-publish": "",
65103
+ disabled: standing !== "ready" || busy,
65104
+ loading: phase.kind === "applying" && phase.publish || phase.kind === "publishing",
65105
+ onClick: () => {
65106
+ if (summary.unsaved) ask("publish");
65107
+ else void publish();
65108
+ },
65109
+ children: m2.publishTo({ version: standing === "template" ? void 0 : nextVersion, env })
65110
+ }
65111
+ )
65112
+ ] })
65113
+ ] })
65114
+ ] })
65115
+ ] });
65116
+ });
65117
+ function NamePopover({
65118
+ open,
65119
+ onOpenChange,
65120
+ trigger,
65121
+ label,
65122
+ placeholder,
65123
+ initial: initial2,
65124
+ taken,
65125
+ missing,
65126
+ confirm,
65127
+ children: children2,
65128
+ onConfirm
65129
+ }) {
65130
+ const edit = react.useSlotRecipe({ key: "sliceEdit" })();
65131
+ const input = react.useRecipe({ key: "input" })({});
65132
+ const m2 = useStudioMessages();
65133
+ const id3 = React.useId();
65134
+ const [name, setName] = React.useState(initial2);
65135
+ const [refused, setRefused] = React.useState(void 0);
65136
+ const [busy, setBusy] = React.useState(false);
65137
+ const [wasOpen, setWasOpen] = React.useState(open);
65138
+ if (open !== wasOpen) {
65139
+ setWasOpen(open);
65140
+ if (open) {
65141
+ setName(initial2);
65142
+ setRefused(void 0);
65143
+ setBusy(false);
65144
+ }
65145
+ }
65146
+ const trimmed = name.trim();
65147
+ const isTaken = trimmed !== "" && taken.has(trimmed);
65148
+ const submit = async () => {
65149
+ if (trimmed === "" || isTaken || busy) return;
65150
+ setBusy(true);
65151
+ setRefused(void 0);
65152
+ try {
65153
+ const why = await onConfirm(trimmed);
65154
+ if (why === void 0) onOpenChange(false);
65155
+ else setRefused(why);
65156
+ } catch (err) {
65157
+ setRefused(err instanceof Error ? err.message : String(err));
65158
+ } finally {
65159
+ setBusy(false);
65160
+ }
65161
+ };
65162
+ return /* @__PURE__ */ jsxRuntime.jsx(
65163
+ eastUiComponents.SliceEditPopover,
65164
+ {
65165
+ open,
65166
+ onOpenChange,
65167
+ trigger,
65168
+ label,
65169
+ footActions: /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
65170
+ /* @__PURE__ */ jsxRuntime.jsx(react.Button, { type: "button", variant: "outline", size: "xs", disabled: busy, onClick: () => onOpenChange(false), children: m2.cancel() }),
65171
+ /* @__PURE__ */ jsxRuntime.jsx(
65172
+ react.Button,
65173
+ {
65174
+ type: "submit",
65175
+ form: `${id3}-form`,
65176
+ variant: "outline",
65177
+ size: "xs",
65178
+ loading: busy,
65179
+ disabled: trimmed === "" || isTaken,
65180
+ children: confirm
65181
+ }
65182
+ )
65183
+ ] }),
65184
+ children: /* @__PURE__ */ jsxRuntime.jsxs(
65185
+ react.chakra.form,
65186
+ {
65187
+ id: `${id3}-form`,
65188
+ display: "contents",
65189
+ noValidate: true,
65190
+ onSubmit: (e3) => {
65191
+ e3.preventDefault();
65192
+ void submit();
65193
+ },
65194
+ children: [
65195
+ /* @__PURE__ */ jsxRuntime.jsxs(react.Box, { display: "flex", flexDirection: "column", gap: "{spacing.1}", children: [
65196
+ /* @__PURE__ */ jsxRuntime.jsx(
65197
+ react.chakra.input,
65198
+ {
65199
+ css: input,
65200
+ value: name,
65201
+ placeholder,
65202
+ "aria-label": placeholder,
65203
+ autoComplete: "off",
65204
+ autoFocus: true,
65205
+ "aria-invalid": isTaken ? true : void 0,
65206
+ "aria-describedby": trimmed === "" || isTaken ? `${id3}-hint` : void 0,
65207
+ onChange: (e3) => setName(e3.target.value)
65208
+ }
65209
+ ),
65210
+ trimmed === "" && /* @__PURE__ */ jsxRuntime.jsx(react.Box, { as: "span", id: `${id3}-hint`, css: edit.hint, children: missing }),
65211
+ isTaken && /* @__PURE__ */ jsxRuntime.jsx(react.Box, { as: "span", id: `${id3}-hint`, css: edit.hintError, children: m2.nameTaken({ name: trimmed }) })
65212
+ ] }),
65213
+ children2,
65214
+ refused !== void 0 && /* @__PURE__ */ jsxRuntime.jsx(react.Box, { as: "span", role: "alert", css: edit.hintError, "data-refused": "", children: refused })
65215
+ ]
65216
+ }
65217
+ )
65218
+ }
65219
+ );
65220
+ }
65221
+ const StudioSaveTemplate = React.memo(function StudioSaveTemplate2({ value }) {
65222
+ const edit = react.useSlotRecipe({ key: "sliceEdit" })();
65223
+ const m2 = useStudioMessages();
65224
+ const [open, setOpen] = React.useState(false);
65225
+ const onSave = value.onSave;
65226
+ return /* @__PURE__ */ jsxRuntime.jsx(
65227
+ NamePopover,
65228
+ {
65229
+ open,
65230
+ onOpenChange: (next2) => setOpen(next2 && value.enabled),
65231
+ trigger: /* @__PURE__ */ jsxRuntime.jsx(
65232
+ react.Button,
65233
+ {
65234
+ variant: "outline",
65235
+ disabled: !value.enabled,
65236
+ "data-studio-save-template": "",
65237
+ ...value.enabled ? {} : { title: m2.templateOpen() },
65238
+ children: m2.saveAsTemplate()
65239
+ }
65240
+ ),
65241
+ label: /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
65242
+ m2.saveAsTemplate(),
65243
+ " · ",
65244
+ /* @__PURE__ */ jsxRuntime.jsx(react.Box, { as: "span", css: edit.clauseField, children: value.title })
65245
+ ] }),
65246
+ placeholder: m2.templateName(),
65247
+ initial: m2.templateNameFor({ page: value.title }),
65248
+ taken: value.taken,
65249
+ missing: m2.templateNameMissing(),
65250
+ confirm: m2.saveTemplate(),
65251
+ onConfirm: async (name) => {
65252
+ const refused = await onSave(name);
65253
+ return refused.type === "some" ? refused.value : void 0;
65254
+ }
65255
+ }
65256
+ );
65257
+ });
65258
+ function compileStudio() {
65259
+ return {
65260
+ /** Each listed component's palette card. */
65261
+ paletteCards: east.East.compile(internal$1.paletteCards, []),
65262
+ /** A project's pages, as the palette lists them. */
65263
+ palettePages: east.East.compile(internal$1.palettePages, []),
65264
+ /** Each listed component's tile on the canvas. */
65265
+ canvasTiles: east.East.compile(internal$1.canvasTiles, []),
65266
+ /** The selected placement, as the inspector shows it. */
65267
+ inspectorSelection: east.East.compile(internal$1.inspectorSelection, []),
65268
+ /** What the publish preview shows of the open entry. */
65269
+ publishSummary: east.East.compile(internal$1.publishSummary, []),
65270
+ /** What refused a publish. */
65271
+ publishRefusal: east.East.compile(internal$1.publishRefusal, []),
65272
+ /** The projects the record holds. */
65273
+ libraryProjects: east.East.compile(internal$1.libraryProjects, []),
65274
+ /** A project's pages, as the page library draws them. */
65275
+ libraryPages: east.East.compile(internal$1.libraryPages, []),
65276
+ /** A project's templates, as the page library draws them. */
65277
+ libraryTemplates: east.East.compile(internal$1.libraryTemplates, []),
65278
+ /** What refused a write under a new name. */
65279
+ nameWriteRefusal: east.East.compile(internal$1.nameWriteRefusal, []),
65280
+ /** The changes from one layout of a page to another. */
65281
+ changes: east.East.compile(internal$1.Studio.changes, []),
65282
+ /** The patch that publishes a page. */
65283
+ publish: east.East.compile(internal$1.Studio.publish, []),
65284
+ /** The patch that starts a page. */
65285
+ newPage: east.East.compile(internal$1.Studio.newPage, []),
65286
+ /** The patch that saves a page's draft as a template. */
65287
+ saveTemplate: east.East.compile(internal$1.Studio.saveTemplate, []),
65288
+ /** The canvas's Apply: a batch of placements, one patch through the record's patch write. */
65289
+ save: east.East.compileAsync(internal$1.saveCells, [])
65290
+ };
65291
+ }
65292
+ let compiled;
65293
+ function studioEast() {
65294
+ compiled ?? (compiled = compileStudio());
65295
+ return compiled;
65296
+ }
65297
+ const CellsType = east.ArrayType(internal$1.StudioCellType);
65298
+ const encodeCells = east.encodeBeast2For(CellsType);
65299
+ const decodeCells = east.decodeBeast2For(CellsType);
65300
+ const encodeCell = east.encodeBeast2For(internal$1.StudioCellType);
65301
+ const decodeBatch = east.decodeBeast2For(internal$2.Editing.Types.ChangeSet(internal$1.StudioCellType));
65302
+ const CELL_TYPE = east.toEastTypeValue(internal$1.StudioCellType);
65303
+ const CELL_DRAFT_TYPE = east.toEastTypeValue(internal$2.EditingDraftFieldType(internal$1.StudioCellType));
65304
+ const keyEqual = east.equalFor(internal$1.StudioKeyType);
65305
+ const printKey = east.printFor(internal$1.StudioKeyType);
65306
+ const NOTHING_SELECTED = { selected: east.none, request: east.none };
65307
+ const EastChakraStudioBuilder = React.memo(function EastChakraStudioBuilder2({ value, storageKey }) {
65308
+ const styles2 = react.useSlotRecipe({ key: "studioBuilder" })();
65309
+ const statusRecipe = react.useSlotRecipe({ key: "status" });
65310
+ const m2 = useStudioMessages();
65311
+ const words = eastUiComponents.useFormatters();
65312
+ const east$1 = studioEast();
65313
+ const { pages: handle, components: components2, project } = value;
65314
+ const id3 = value.id.type === "some" ? value.id.value : void 0;
65315
+ const keys = React.useMemo(() => internal$1.builderKeys(id3), [id3]);
65316
+ const read = React.useCallback(() => handle.read(), [handle]);
65317
+ const { result } = eastUiComponents.useTrackedEvaluation(read);
65318
+ const pages = result.ok ? result.value : void 0;
65319
+ const first2 = React.useMemo(() => {
65320
+ if (pages !== void 0) {
65321
+ for (const [key, entry2] of pages) {
65322
+ if (key.project === project && entry2.type === "page") return key;
65323
+ }
65324
+ }
65325
+ return { project, page: "" };
65326
+ }, [pages, project]);
65327
+ const [open, writeOpen] = useOpenPage(keys.page, first2);
65328
+ const openName = printKey(open);
65329
+ let entry;
65330
+ if (pages !== void 0) {
65331
+ for (const [key, found] of pages) {
65332
+ if (keyEqual(key, open)) {
65333
+ entry = found;
65334
+ break;
65335
+ }
65336
+ }
65337
+ }
65338
+ const [ui, setUi] = React.useState(NOTHING_SELECTED);
65339
+ const [applying2, setApplying] = React.useState(east.variant("idle", null));
65340
+ const [drafted, setDrafted] = React.useState(void 0);
65341
+ const [previewing, setPreviewing] = React.useState(false);
65342
+ const shown = React.useRef(openName);
65343
+ React.useEffect(() => {
65344
+ if (shown.current === openName) return;
65345
+ shown.current = openName;
65346
+ setUi(NOTHING_SELECTED);
65347
+ }, [openName]);
65348
+ const saved = React.useMemo(() => entry === void 0 ? [] : entry.type === "page" ? entry.value.draft.cells : entry.value.cells, [entry]);
65349
+ const cells = drafted !== void 0 && drafted.page === openName ? drafted.cells : saved;
65350
+ const liveCells = React.useMemo(() => entry !== void 0 && entry.type === "page" && entry.value.live.type === "some" ? east.some(entry.value.live.value.page.cells) : east.none, [entry]);
65351
+ const title = entry === void 0 ? "" : entry.type === "page" ? entry.value.draft.title : entry.value.title;
65352
+ const tiles = React.useMemo(() => east$1.canvasTiles(components2), [east$1, components2]);
65353
+ const componentOf = React.useRef(/* @__PURE__ */ new Map());
65354
+ const cellView = React.useCallback((cell) => {
65355
+ componentOf.current.set(cell.key, cell.component);
65356
+ const tile = tiles.get(cell.component);
65357
+ return {
65358
+ key: cell.key,
65359
+ row: cell.row,
65360
+ span: cell.span,
65361
+ height: cell.height,
65362
+ minHeight: east.none,
65363
+ align: cell.align,
65364
+ // A frameless component renders bare; one the surface does not
65365
+ // list is its placeholder, in a tile.
65366
+ frame: tile === void 0 ? true : tile.frame,
65367
+ label: cell.title.type === "some" ? cell.title : tile === void 0 ? east.none : east.some(tile.name),
65368
+ icon: tile === void 0 ? east.none : east.some(tile.icon),
65369
+ meta: tile === void 0 ? east.some(cell.component) : east.some(tile.meta)
65370
+ };
65371
+ }, [tiles]);
65372
+ const snapshot = React.useMemo(() => encodeCells([...saved]), [saved]);
65373
+ const editing = React.useMemo(() => ({
65374
+ sourceId: `studio.page:${openName}`,
65375
+ entryType: CELL_TYPE,
65376
+ idField: east.some("key"),
65377
+ draftType: CELL_DRAFT_TYPE,
65378
+ children: east.none,
65379
+ keyType: east.none,
65380
+ snapshot: east.some(snapshot),
65381
+ readEntry: (entryId) => {
65382
+ const cell = saved.find((c2) => c2.key === entryId);
65383
+ return cell === void 0 ? east.none : east.some(encodeCell(cell));
65384
+ },
65385
+ onPatch: east.none,
65386
+ // Apply: the batch, one patch on the page through the record's patch write.
65387
+ onApply: east.some(east.variant("async", (bytes) => east$1.save(handle, open, decodeBatch(bytes)))),
65388
+ mode: east.variant("batch", null),
65389
+ fields: { key: "key", row: "row", span: "span", height: east.some("height"), align: east.some("align") },
65390
+ derive: (bytes) => decodeCells(bytes).map(cellView),
65391
+ // A component dropped from the palette: a placement at its span,
65392
+ // storing its fingerprint; the canvas fits the span to the row.
65393
+ create: east.some((card, at) => {
65394
+ const component2 = components2.find((c2) => c2.key === card.key);
65395
+ if (component2 === void 0) throw new Error(`No component "${card.key}" is listed`);
65396
+ return encodeCell({
65397
+ key: at.key,
65398
+ row: at.row,
65399
+ span: component2.span,
65400
+ height: east.none,
65401
+ align: east.variant("top", null),
65402
+ title: east.none,
65403
+ component: component2.key,
65404
+ fingerprint: component2.fingerprint
65405
+ });
65406
+ }),
65407
+ ready: east.none,
65408
+ // The rows the canvas draws, for the palette's counts, the inspector and the preview.
65409
+ onDrafted: east.some((bytes) => {
65410
+ setDrafted({ page: openName, cells: decodeCells(bytes) });
65411
+ return null;
65412
+ })
65413
+ }), [openName, snapshot, saved, east$1, handle, open, cellView, components2]);
65414
+ const uiBind = React.useMemo(() => ({
65415
+ read: () => ui,
65416
+ write: (next2) => {
65417
+ setUi(next2);
65418
+ return null;
65419
+ },
65420
+ has: () => true
65421
+ }), [ui]);
65422
+ const applyBind = React.useMemo(() => ({
65423
+ read: () => applying2,
65424
+ write: (next2) => {
65425
+ setApplying(next2);
65426
+ return null;
65427
+ },
65428
+ has: () => true
65429
+ }), [applying2]);
65430
+ const canvas = React.useMemo(() => ({
65431
+ cells: saved.map(cellView),
65432
+ variant: east.none,
65433
+ width: east.some("1440px"),
65434
+ height: east.some("fill"),
65435
+ maxHeight: east.none,
65436
+ zoom: east.none,
65437
+ guides: true,
65438
+ editing: east.some(editing),
65439
+ ui: east.some(uiBind),
65440
+ view: east.none,
65441
+ apply: east.some(applyBind),
65442
+ id: east.none,
65443
+ sources: [keys.components],
65444
+ canDrop: east.none,
65445
+ widths: [
65446
+ { label: m2.device({ device: "desktop" }), icon: east.some("desktop"), width: "1440px" },
65447
+ { label: m2.device({ device: "tablet" }), icon: east.some("tablet-screen-button"), width: "1024px" }
65448
+ ],
65449
+ toolbar: { start: [], end: [] },
65450
+ panes: { start: east.none, end: east.none },
65451
+ surface: east.some(east.variant("shell", null))
65452
+ }), [saved, cellView, editing, uiBind, applyBind, keys.components, m2]);
65453
+ const listedByKey = React.useMemo(() => {
65454
+ const byKey = /* @__PURE__ */ new Map();
65455
+ for (const component2 of components2) {
65456
+ const same2 = byKey.get(component2.key);
65457
+ if (same2 === void 0) byKey.set(component2.key, [component2]);
65458
+ else same2.push(component2);
65459
+ }
65460
+ return byKey;
65461
+ }, [components2]);
65462
+ const renderContent = React.useCallback((cell) => {
65463
+ const component2 = componentOf.current.get(cell.key) ?? "";
65464
+ return /* @__PURE__ */ jsxRuntime.jsx(StudioPlacement, { component: component2, listed: listedByKey.get(component2) ?? [], storageKey: `${storageKey}.canvas.${cell.key}` });
65465
+ }, [listedByKey, storageKey]);
65466
+ const status = entry === void 0 ? void 0 : entry.type === "template" ? { label: m2.statusTemplate(), tone: "neutral", ring: false } : entry.value.live.type === "none" ? { label: m2.statusDraft(), tone: "neutral", ring: true } : east$1.changes(entry.value.live.value.page, entry.value.draft).length === 0 ? { label: m2.statusLive(), tone: "success", ring: false } : { label: m2.statusLiveEdited(), tone: "warning", ring: false };
65467
+ const statusStyles = status === void 0 ? void 0 : statusRecipe({ status: status.tone, size: "md", ring: status.ring });
65468
+ const taken = React.useMemo(() => {
65469
+ const names = /* @__PURE__ */ new Set();
65470
+ if (pages !== void 0) {
65471
+ for (const [key] of pages) {
65472
+ if (key.project === open.project) names.add(key.page);
65473
+ }
65474
+ }
65475
+ return names;
65476
+ }, [pages, open.project]);
65477
+ const saveTemplate = React.useMemo(() => ({
65478
+ title,
65479
+ enabled: entry !== void 0 && entry.type === "page",
65480
+ taken,
65481
+ // The open page, as last saved, as a template under a name — one commit.
65482
+ onSave: async (name) => {
65483
+ const now2 = handle.read();
65484
+ const patch = east$1.saveTemplate(now2, open, { project: open.project, page: name }, name);
65485
+ const outcome = await handle.commit.patch("", patch);
65486
+ return east$1.nameWriteRefusal(outcome, name);
65487
+ }
65488
+ }), [title, entry, taken, handle, east$1, open]);
65489
+ const toolbar = {
65490
+ start: [status !== void 0 && statusStyles !== void 0 && {
65491
+ key: "status",
65492
+ side: "start",
65493
+ version: status.label,
65494
+ forms: [
65495
+ /* @__PURE__ */ jsxRuntime.jsxs(react.HStack, { css: statusStyles.root, "data-studio-status": status.tone, children: [
65496
+ /* @__PURE__ */ jsxRuntime.jsx(react.Box, { as: "span", css: statusStyles.indicator }),
65497
+ /* @__PURE__ */ jsxRuntime.jsx(react.Box, { css: statusStyles.label, children: status.label })
65498
+ ] })
65499
+ ]
65500
+ }],
65501
+ end: [
65502
+ { key: "save-template", side: "end", forms: [/* @__PURE__ */ jsxRuntime.jsx(StudioSaveTemplate, { value: saveTemplate })] },
65503
+ {
65504
+ key: "preview",
65505
+ side: "end",
65506
+ forms: [/* @__PURE__ */ jsxRuntime.jsx(react.Button, { variant: "outline", "data-studio-preview": "", onClick: () => setPreviewing(true), children: m2.preview() })]
65507
+ },
65508
+ {
65509
+ key: "publish",
65510
+ side: "end",
65511
+ forms: [/* @__PURE__ */ jsxRuntime.jsx(react.Button, { variant: "outline", "data-studio-open-publish": "", onClick: () => setPreviewing(true), children: m2.publish() })]
65512
+ }
65513
+ ]
65514
+ };
65515
+ const listed = React.useMemo(() => components2.filter((c2) => !c2.deprecated), [components2]);
65516
+ const cards = React.useMemo(() => east$1.paletteCards(listed, [...cells], ui.selected), [east$1, listed, cells, ui.selected]);
65517
+ const projectPages = React.useMemo(() => pages === void 0 ? [] : east$1.palettePages(pages, project), [east$1, pages, project]);
65518
+ const selectFirst = React.useCallback((component2) => {
65519
+ const placement = cells.find((c2) => c2.component === component2);
65520
+ if (placement !== void 0) setUi({ selected: east.some(placement.key), request: east.none });
65521
+ }, [cells]);
65522
+ const openPage = React.useCallback((page) => {
65523
+ writeOpen({ project, page });
65524
+ setUi(NOTHING_SELECTED);
65525
+ }, [writeOpen, project]);
65526
+ const paletteIds = React.useMemo(() => ({ components: keys.components, pages: keys.pages }), [keys.components, keys.pages]);
65527
+ const selection2 = React.useMemo(
65528
+ () => east$1.inspectorSelection(components2, [...cells], liveCells, ui.selected),
65529
+ [east$1, components2, cells, liveCells, ui.selected]
65530
+ );
65531
+ const onRequest = React.useCallback((request) => {
65532
+ setUi({ selected: east.some(request.key), request: east.some(request) });
65533
+ return null;
65534
+ }, []);
65535
+ const inspector = React.useMemo(() => ({ selection: selection2, onRequest }), [selection2, onRequest]);
65536
+ const selected2 = selection2.type === "some" ? selection2.value : void 0;
65537
+ const summary = React.useMemo(
65538
+ () => entry === void 0 ? void 0 : east$1.publishSummary(components2, entry.type === "page" ? entry.value.live : east.none, { title, cells: [...cells] }, [...saved], entry.type === "template"),
65539
+ [east$1, components2, entry, title, cells, saved]
65540
+ );
65541
+ const preview = React.useMemo(() => summary === void 0 ? void 0 : {
65542
+ project: open.project,
65543
+ title,
65544
+ summary,
65545
+ env: value.env,
65546
+ audience: value.audience,
65547
+ rollout: value.rollout,
65548
+ apply: applying2,
65549
+ // The canvas applies its drafts, and answers under the id.
65550
+ onApply: (ask) => {
65551
+ setApplying(east.variant("asked", ask));
65552
+ return null;
65553
+ },
65554
+ // The publish, from the record as it stands when it commits — what an
65555
+ // Apply just before it left.
65556
+ onPublish: async () => {
65557
+ const now2 = handle.read();
65558
+ const patch = east$1.publish(now2, open, components2);
65559
+ const outcome = await handle.commit.patch("", patch);
65560
+ return east$1.publishRefusal(outcome);
65561
+ },
65562
+ onExit: east.some(() => {
65563
+ setPreviewing(false);
65564
+ return null;
65565
+ })
65566
+ }, [summary, open, title, value.env, value.audience, value.rollout, applying2, handle, east$1, components2]);
65567
+ if (!result.ok) {
65568
+ const message = result.error instanceof Error ? result.error.message : String(result.error);
65569
+ return /* @__PURE__ */ jsxRuntime.jsx(eastUiComponents.BannerView, { status: "error", title: message });
65570
+ }
65571
+ if (entry === void 0) {
65572
+ return /* @__PURE__ */ jsxRuntime.jsx(
65573
+ eastUiComponents.EmptyStateView,
65574
+ {
65575
+ icon: { prefix: "fas", name: "file-circle-question" },
65576
+ title: m2.noPageOpen(),
65577
+ description: m2.noPageOpenHint({ project, page: open.page })
65578
+ }
65579
+ );
65580
+ }
65581
+ return /* @__PURE__ */ jsxRuntime.jsxs(react.Box, { css: styles2.root, "data-studio-builder": "", children: [
65582
+ /* @__PURE__ */ jsxRuntime.jsx(react.Box, { css: styles2.canvas, hidden: previewing, "data-studio-canvas": "", children: /* @__PURE__ */ jsxRuntime.jsx(
65583
+ eastUiComponents.SnapGridEditor,
65584
+ {
65585
+ value: canvas,
65586
+ storageKey: `${storageKey}.canvas`,
65587
+ toolbar,
65588
+ renderContent,
65589
+ panes: {
65590
+ start: /* @__PURE__ */ jsxRuntime.jsx(
65591
+ StudioPalette,
65592
+ {
65593
+ components: listed,
65594
+ cards,
65595
+ pages: projectPages,
65596
+ open: open.project === project ? open.page : "",
65597
+ ids: paletteIds,
65598
+ onSelect: selectFirst,
65599
+ onOpen: openPage,
65600
+ storageKey
65601
+ }
65602
+ ),
65603
+ end: /* @__PURE__ */ jsxRuntime.jsx(
65604
+ eastUiComponents.DockPane,
65605
+ {
65606
+ storageKey: `${storageKey}.inspector`,
65607
+ icon: "sliders",
65608
+ label: m2.inspector(),
65609
+ badge: selected2 === void 0 ? "" : m2.spanBadge({ span: words.number(Number(selected2.layout.span)) }),
65610
+ active: selected2 !== void 0,
65611
+ detail: selected2 === void 0 ? m2.nothingSelected() : selected2.name,
65612
+ expandedSize: "300px",
65613
+ railSize: "44px",
65614
+ side: "end",
65615
+ surface: "shell",
65616
+ body: /* @__PURE__ */ jsxRuntime.jsx(StudioInspector, { value: inspector })
65617
+ }
65618
+ )
65619
+ }
65620
+ }
65621
+ ) }),
65622
+ previewing && preview !== void 0 && /* @__PURE__ */ jsxRuntime.jsx(
65623
+ StudioPublishPreview,
65624
+ {
65625
+ value: preview,
65626
+ page: /* @__PURE__ */ jsxRuntime.jsx(StudioLayout, { cells, components: components2, storageKey: `${storageKey}.preview` })
65627
+ }
65628
+ )
65629
+ ] });
65630
+ });
65631
+ eastUiComponents.implementUIComponent(internal$1.StudioBuilderComponent, EastChakraStudioBuilder);
65632
+ const RANK = { newPage: 0, sort: 1, newPageIcon: 2, searchMid: 3, searchNarrow: 4 };
65633
+ const SORTS = [
65634
+ { key: "az", icon: faArrowDownAZ, name: (m2) => m2.nameAz() },
65635
+ { key: "za", icon: faArrowDownZA, name: (m2) => m2.nameZa() }
65636
+ ];
65637
+ const BLANK = "\0blank";
65638
+ function SortMenu({ sort: sort2, onPick, compact, trigger, caret: caret2, check }) {
65639
+ const m2 = useStudioMessages();
65640
+ const current = SORTS.find((s2) => s2.key === sort2) ?? SORTS[0];
65641
+ const words = m2.sortByName();
65642
+ return /* @__PURE__ */ jsxRuntime.jsxs(react.Menu.Root, { positioning: { placement: "bottom-end" }, children: [
65643
+ /* @__PURE__ */ jsxRuntime.jsx(react.Menu.Trigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(
65644
+ react.chakra.button,
65645
+ {
65646
+ type: "button",
65647
+ css: trigger,
65648
+ "data-page-library-sort": "",
65649
+ ...compact ? { "aria-label": words, title: words } : {},
65650
+ children: compact ? /* @__PURE__ */ jsxRuntime.jsx(FontAwesomeIcon, { icon: current.icon }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
65651
+ words,
65652
+ /* @__PURE__ */ jsxRuntime.jsx(react.Box, { as: "span", css: caret2, "aria-hidden": true, children: /* @__PURE__ */ jsxRuntime.jsx(FontAwesomeIcon, { icon: faCaretDown }) })
65653
+ ] })
65654
+ }
65655
+ ) }),
65656
+ /* @__PURE__ */ jsxRuntime.jsx(react.Portal, { children: /* @__PURE__ */ jsxRuntime.jsx(react.Menu.Positioner, { children: /* @__PURE__ */ jsxRuntime.jsx(react.Menu.Content, { children: /* @__PURE__ */ jsxRuntime.jsx(react.Menu.RadioItemGroup, { value: sort2, onValueChange: (d2) => {
65657
+ const picked = SORTS.find((s2) => s2.key === d2.value);
65658
+ if (picked !== void 0 && picked.key !== sort2) onPick(picked.key);
65659
+ }, children: SORTS.map((s2) => /* @__PURE__ */ jsxRuntime.jsxs(react.Menu.RadioItem, { value: s2.key, children: [
65660
+ /* @__PURE__ */ jsxRuntime.jsx(react.Box, { as: "span", css: check, children: s2.key === sort2 && /* @__PURE__ */ jsxRuntime.jsx(FontAwesomeIcon, { icon: faCheck }) }),
65661
+ s2.name(m2)
65662
+ ] }, s2.key)) }) }) }) })
65663
+ ] });
65664
+ }
65665
+ const EastChakraStudioLibrary = React.memo(function EastChakraStudioLibrary2({ value, storageKey }) {
65666
+ const styles2 = react.useSlotRecipe({ key: "studioLibrary" })();
65667
+ const library2 = react.useSlotRecipe({ key: "library" })();
65668
+ const edit = react.useSlotRecipe({ key: "sliceEdit" })();
65669
+ const status = react.useSlotRecipe({ key: "status" });
65670
+ const liveDot = status({ status: "success" });
65671
+ const draftDot = status({ status: "neutral", ring: true });
65672
+ const button = react.useRecipe({ key: "button" });
65673
+ const m2 = useStudioMessages();
65674
+ const words = eastUiComponents.useFormatters();
65675
+ const id3 = React.useId();
65676
+ const east$1 = studioEast();
65677
+ const { pages: handle, components: components2 } = value;
65678
+ const home = value.project;
65679
+ const keys = React.useMemo(() => internal$1.builderKeys(value.id.type === "some" ? value.id.value : void 0), [value.id]);
65680
+ const tellHost = value.onOpen.type === "some" ? value.onOpen.value : void 0;
65681
+ const read = React.useCallback(() => handle.read(), [handle]);
65682
+ const { result } = eastUiComponents.useTrackedEvaluation(read);
65683
+ const records = result.ok ? result.value : void 0;
65684
+ const [project, setProject] = React.useState(home);
65685
+ const [text, setText] = React.useState("");
65686
+ const [sort2, setSort] = React.useState("az");
65687
+ const [layout4, setLayout] = React.useState("grid");
65688
+ const [popover, setPopover] = React.useState(void 0);
65689
+ const needle = text.toLowerCase();
65690
+ const first2 = React.useMemo(() => {
65691
+ if (records !== void 0) {
65692
+ for (const [key, entry] of records) {
65693
+ if (key.project === home && entry.type === "page") return key;
65694
+ }
65695
+ }
65696
+ return { project: home, page: "" };
65697
+ }, [records, home]);
65698
+ const [open, writeOpen] = useOpenPage(keys.page, first2);
65699
+ const za = sort2 === "za";
65700
+ const everyPage = React.useMemo(() => records === void 0 ? [] : east$1.libraryPages(records, project), [east$1, records, project]);
65701
+ const everyTemplate = React.useMemo(
65702
+ () => records === void 0 ? [] : east$1.libraryTemplates(records, project, components2),
65703
+ [east$1, records, project, components2]
65704
+ );
65705
+ const pageRows2 = React.useMemo(() => {
65706
+ const matching2 = everyPage.filter((p2) => p2.title.toLowerCase().includes(needle));
65707
+ return za ? matching2.reverse() : matching2;
65708
+ }, [everyPage, needle, za]);
65709
+ const paneRows = React.useMemo(() => {
65710
+ const byName = records === void 0 ? [] : east$1.palettePages(records, project);
65711
+ return za ? [...byName].reverse() : byName;
65712
+ }, [east$1, records, project, za]);
65713
+ const templateRows = React.useMemo(() => {
65714
+ const matching2 = everyTemplate.filter((t4) => t4.title.toLowerCase().includes(needle));
65715
+ const ordered = za ? matching2.reverse() : matching2;
65716
+ const blank = { name: "", title: m2.blankGrid(), summary: m2.blankSummary(), cells: [] };
65717
+ return m2.blankGrid().toLowerCase().includes(needle) ? [blank, ...ordered] : ordered;
65718
+ }, [everyTemplate, needle, za, m2]);
65719
+ const projects = React.useMemo(() => records === void 0 ? [home] : east$1.libraryProjects(records, home), [east$1, records, home]);
65720
+ const taken = React.useMemo(() => {
65721
+ const names = /* @__PURE__ */ new Set();
65722
+ if (records !== void 0) {
65723
+ for (const [key] of records) {
65724
+ if (key.project === project) names.add(key.page);
65725
+ }
65726
+ }
65727
+ return names;
65728
+ }, [records, project]);
65729
+ const openPage = React.useCallback((name) => {
65730
+ const key = { project, page: name };
65731
+ writeOpen(key);
65732
+ if (tellHost !== void 0) queueMicrotask(() => tellHost(key));
65733
+ }, [project, writeOpen, tellHost]);
65734
+ const startFrom = React.useCallback((name) => setPopover(name), []);
65735
+ const startBlank = React.useCallback(() => setPopover(""), []);
65736
+ const wireframes = React.useMemo(() => {
65737
+ const out = /* @__PURE__ */ new Map();
65738
+ const layouts = [
65739
+ ...templateRows.map((t4) => [`template:${t4.name}`, t4.cells]),
65740
+ ...pageRows2.map((p2) => [`page:${p2.page}`, p2.cells])
65741
+ ];
65742
+ for (const [card, cells] of layouts) {
65743
+ out.set(card, cells.map((c2) => ({
65744
+ key: c2.key,
65745
+ row: c2.row,
65746
+ span: c2.span,
65747
+ height: east.some(c2.height.type === "some" ? c2.height.value / 12n : 12n),
65748
+ align: c2.align,
65749
+ frame: true
65750
+ })));
65751
+ }
65752
+ return out;
65753
+ }, [templateRows, pageRows2]);
65754
+ const templateMedia = React.useCallback((item) => /* @__PURE__ */ jsxRuntime.jsx(eastUiComponents.SnapGridTiles, { wireframe: true, cells: wireframes.get(`template:${item.key}`) ?? [], content: () => null }), [wireframes]);
65755
+ const pageMedia = React.useCallback((item) => /* @__PURE__ */ jsxRuntime.jsx(eastUiComponents.SnapGridTiles, { wireframe: true, cells: wireframes.get(`page:${item.key}`) ?? [], content: () => null }), [wireframes]);
65756
+ const templatesGallery = React.useMemo(() => ({
65757
+ id: `${storageKey}.templates`,
65758
+ hint: east.none,
65759
+ items: templateRows.map((t4) => ({
65760
+ key: t4.name,
65761
+ label: t4.title,
65762
+ sublabel: east.some(t4.summary),
65763
+ icon: east.none,
65764
+ status: east.none,
65765
+ trailing: east.none,
65766
+ draggable: false,
65767
+ filtered: false,
65768
+ placed: false,
65769
+ media: east.none,
65770
+ avatar: east.none,
65771
+ byline: east.none,
65772
+ action: east.none,
65773
+ search: east.none,
65774
+ groups: /* @__PURE__ */ new Map(),
65775
+ facets: /* @__PURE__ */ new Map(),
65776
+ dims: /* @__PURE__ */ new Map()
65777
+ })),
65778
+ groupOptions: [],
65779
+ groupSummaries: /* @__PURE__ */ new Map(),
65780
+ dimOptions: [],
65781
+ defaultDimensions: [],
65782
+ filterOptions: [],
65783
+ searchable: false,
65784
+ noun: east.none,
65785
+ addLabel: east.none,
65786
+ onAdd: east.none,
65787
+ onCardClick: east.some((name) => {
65788
+ startFrom(name);
65789
+ return null;
65790
+ }),
65791
+ slice: east.none,
65792
+ style: east.some({ height: east.none, maxHeight: east.none, virtualization: east.none, columns: east.some(4n), mediaPlacement: east.none, mediaSize: east.some("80px") }),
65793
+ variant: east.some(east.variant("gallery", null)),
65794
+ layout: east.none,
65795
+ toolbar: false
65796
+ }), [storageKey, templateRows, startFrom]);
65797
+ const pagesGallery = React.useMemo(() => ({
65798
+ id: `${storageKey}.pages`,
65799
+ hint: east.none,
65800
+ items: pageRows2.map((p2) => ({
65801
+ key: p2.page,
65802
+ label: p2.title,
65803
+ sublabel: east.some(m2.placements({ n: p2.cells.length, count: words.number(p2.cells.length) })),
65804
+ icon: east.none,
65805
+ status: east.some(p2.live ? { label: m2.live(), tone: east.variant("success", null), ring: false } : { label: m2.draft(), tone: east.variant("neutral", null), ring: true }),
65806
+ trailing: east.none,
65807
+ draggable: false,
65808
+ filtered: false,
65809
+ placed: false,
65810
+ media: east.none,
65811
+ avatar: east.none,
65812
+ byline: east.none,
65813
+ action: east.some(m2.openInBuilder()),
65814
+ search: east.none,
65815
+ groups: /* @__PURE__ */ new Map(),
65816
+ facets: /* @__PURE__ */ new Map(),
65817
+ dims: /* @__PURE__ */ new Map()
65818
+ })),
65819
+ groupOptions: [],
65820
+ groupSummaries: /* @__PURE__ */ new Map(),
65821
+ dimOptions: [],
65822
+ defaultDimensions: [],
65823
+ filterOptions: [],
65824
+ searchable: false,
65825
+ noun: east.none,
65826
+ addLabel: east.some(m2.newPageFromTemplate()),
65827
+ onAdd: east.some(() => {
65828
+ startBlank();
65829
+ return null;
65830
+ }),
65831
+ onCardClick: east.some((name) => {
65832
+ openPage(name);
65833
+ return null;
65834
+ }),
65835
+ slice: east.none,
65836
+ style: east.some({ height: east.none, maxHeight: east.none, virtualization: east.none, columns: east.some(2n), mediaPlacement: east.some(east.variant("start", null)), mediaSize: east.some("156px") }),
65837
+ variant: east.some(east.variant("gallery", null)),
65838
+ layout: east.some(layout4 === "list" ? east.variant("list", null) : east.variant("grid", null)),
65839
+ toolbar: false
65840
+ }), [storageKey, pageRows2, m2, words, startBlank, openPage, layout4]);
65841
+ const from2 = popover !== void 0 && popover !== "" ? popover : BLANK;
65842
+ const [template, setTemplate] = React.useState(from2);
65843
+ const [openedFrom, setOpenedFrom] = React.useState(popover);
65844
+ if (popover !== openedFrom) {
65845
+ setOpenedFrom(popover);
65846
+ if (popover !== void 0) setTemplate(from2);
65847
+ }
65848
+ const picker = React.useMemo(() => react.createListCollection({
65849
+ items: [{ value: BLANK, label: m2.blankGrid() }, ...everyTemplate.map((t4) => ({ value: t4.name, label: t4.title }))]
65850
+ }), [everyTemplate, m2]);
65851
+ const create2 = async (name) => {
65852
+ const now2 = handle.read();
65853
+ const key = { project, page: name };
65854
+ const patch = east$1.newPage(now2, key, name, template === BLANK ? east.none : east.some({ project, page: template }));
65855
+ const outcome = await handle.commit.patch("", patch);
65856
+ const refused = east$1.nameWriteRefusal(outcome, name);
65857
+ return refused.type === "some" ? refused.value : void 0;
65858
+ };
65859
+ const np = everyPage.length;
65860
+ const nt = everyTemplate.length + 1;
65861
+ const shown = pageRows2.length;
65862
+ const current = open.project === project ? open.page : "";
65863
+ const searchBox = (size3) => /* @__PURE__ */ jsxRuntime.jsxs(react.Box, { css: library2.searchBox, "data-size": size3, children: [
65864
+ /* @__PURE__ */ jsxRuntime.jsx(react.Box, { as: "span", css: library2.searchIcon, "aria-hidden": true, children: /* @__PURE__ */ jsxRuntime.jsx(FontAwesomeIcon, { icon: faMagnifyingGlass }) }),
65865
+ /* @__PURE__ */ jsxRuntime.jsx(
65866
+ react.chakra.input,
65867
+ {
65868
+ css: library2.searchInput,
65869
+ placeholder: m2.searchLibrary({ pages: words.number(np), templates: words.number(nt), np, nt }),
65870
+ "aria-label": m2.searchLabel(),
65871
+ value: text,
65872
+ "data-page-library-search": "",
65873
+ onChange: (e3) => setText(e3.target.value),
65874
+ onKeyDown: (e3) => {
65875
+ if (e3.key === "Escape" && text !== "") {
65876
+ e3.preventDefault();
65877
+ setText("");
65878
+ }
65879
+ }
65880
+ }
65881
+ ),
65882
+ text !== "" && /* @__PURE__ */ jsxRuntime.jsx(react.chakra.button, { type: "button", css: library2.searchClear, "aria-label": m2.clearSearch(), onClick: () => setText(""), children: /* @__PURE__ */ jsxRuntime.jsx(FontAwesomeIcon, { icon: faXmark }) })
65883
+ ] });
65884
+ const sortMenu = (compact) => /* @__PURE__ */ jsxRuntime.jsx(
65885
+ SortMenu,
65886
+ {
65887
+ sort: sort2,
65888
+ compact,
65889
+ trigger: button({ variant: "outline", size: "sm" }),
65890
+ caret: styles2.caret,
65891
+ check: library2.menuCheck,
65892
+ onPick: setSort
65893
+ }
65894
+ );
65895
+ const newPage = (form) => /* @__PURE__ */ jsxRuntime.jsx(
65896
+ NamePopover,
65897
+ {
65898
+ open: popover !== void 0,
65899
+ onOpenChange: (next2) => setPopover(next2 ? "" : void 0),
65900
+ trigger: /* @__PURE__ */ jsxRuntime.jsxs(
65901
+ react.chakra.button,
65902
+ {
65903
+ type: "button",
65904
+ css: button({ variant: "solid", size: "sm" }),
65905
+ colorPalette: "brand",
65906
+ "data-page-library-new": "",
65907
+ ...form !== "full" ? { title: m2.newPageIn({ project }) } : {},
65908
+ ...form === "icon" ? { "aria-label": m2.newPageIn({ project }) } : {},
65909
+ children: [
65910
+ /* @__PURE__ */ jsxRuntime.jsx(react.Box, { as: "span", css: styles2.buttonIcon, "aria-hidden": true, children: /* @__PURE__ */ jsxRuntime.jsx(FontAwesomeIcon, { icon: faPlus }) }),
65911
+ form === "full" ? m2.newPageIn({ project }) : form === "short" ? m2.newPage() : null
65912
+ ]
65913
+ }
65914
+ ),
65915
+ label: /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
65916
+ m2.newPage(),
65917
+ " · ",
65918
+ /* @__PURE__ */ jsxRuntime.jsx(react.Box, { as: "span", css: edit.clauseField, children: project })
65919
+ ] }),
65920
+ placeholder: m2.pageName(),
65921
+ initial: "",
65922
+ taken,
65923
+ missing: m2.pageNameMissing(),
65924
+ confirm: m2.createPage(),
65925
+ onConfirm: create2,
65926
+ children: /* @__PURE__ */ jsxRuntime.jsxs(react.Select.Root, { collection: picker, value: [template], onValueChange: (d2) => setTemplate(d2.value[0] ?? BLANK), children: [
65927
+ /* @__PURE__ */ jsxRuntime.jsx(react.Select.HiddenSelect, {}),
65928
+ /* @__PURE__ */ jsxRuntime.jsx(react.Select.Label, { children: m2.template() }),
65929
+ /* @__PURE__ */ jsxRuntime.jsxs(react.Select.Control, { children: [
65930
+ /* @__PURE__ */ jsxRuntime.jsx(react.Select.Trigger, { "data-page-library-template": "", children: /* @__PURE__ */ jsxRuntime.jsx(react.Select.ValueText, {}) }),
65931
+ /* @__PURE__ */ jsxRuntime.jsx(react.Select.IndicatorGroup, { children: /* @__PURE__ */ jsxRuntime.jsx(react.Select.Indicator, {}) })
65932
+ ] }),
65933
+ /* @__PURE__ */ jsxRuntime.jsx(react.Portal, { children: /* @__PURE__ */ jsxRuntime.jsx(react.Select.Positioner, { children: /* @__PURE__ */ jsxRuntime.jsx(react.Select.Content, { children: picker.items.map((item) => /* @__PURE__ */ jsxRuntime.jsxs(react.Select.Item, { item, children: [
65934
+ item.label,
65935
+ /* @__PURE__ */ jsxRuntime.jsx(react.Select.ItemIndicator, {})
65936
+ ] }, item.value)) }) }) })
65937
+ ] })
65938
+ }
65939
+ );
65940
+ const toolbarItems = [
65941
+ {
65942
+ key: "search",
65943
+ forms: [searchBox("wide"), searchBox("mid"), searchBox("narrow")],
65944
+ rank: [RANK.searchMid, RANK.searchNarrow]
65945
+ },
65946
+ { key: "sort", side: "end", forms: [sortMenu(false), sortMenu(true)], rank: RANK.sort, version: sort2 },
65947
+ {
65948
+ key: "layout",
65949
+ side: "end",
65950
+ forms: [/* @__PURE__ */ jsxRuntime.jsx(eastUiComponents.LibraryLayoutSwitch, { layout: layout4, onPick: setLayout })]
65951
+ },
65952
+ { key: "rule", side: "end", forms: [/* @__PURE__ */ jsxRuntime.jsx(react.Box, { as: "span", css: styles2.divider, "aria-hidden": true })] },
65953
+ {
65954
+ key: "new",
65955
+ side: "end",
65956
+ forms: [newPage("full"), newPage("short"), newPage("icon")],
65957
+ rank: [RANK.newPage, RANK.newPageIcon],
65958
+ version: project
65959
+ }
65960
+ ];
65961
+ if (!result.ok) {
65962
+ const message = result.error instanceof Error ? result.error.message : String(result.error);
65963
+ return /* @__PURE__ */ jsxRuntime.jsx(eastUiComponents.BannerView, { status: "error", title: message });
65964
+ }
65965
+ return /* @__PURE__ */ jsxRuntime.jsxs(react.Box, { css: styles2.root, "data-studio-page-library": "", children: [
65966
+ /* @__PURE__ */ jsxRuntime.jsx(react.Box, { css: styles2.toolbar, "data-slot": "toolbar", children: /* @__PURE__ */ jsxRuntime.jsx(eastUiComponents.Toolbar, { items: toolbarItems }) }),
65967
+ /* @__PURE__ */ jsxRuntime.jsxs(react.Box, { css: styles2.body, children: [
65968
+ /* @__PURE__ */ jsxRuntime.jsxs(react.Box, { css: styles2.pane, "data-page-library-pane": "", children: [
65969
+ /* @__PURE__ */ jsxRuntime.jsxs(react.Box, { css: styles2.paneSection, role: "group", "aria-labelledby": `${id3}-projects`, children: [
65970
+ /* @__PURE__ */ jsxRuntime.jsx(react.Box, { css: styles2.paneHead, children: /* @__PURE__ */ jsxRuntime.jsx(react.Box, { as: "span", id: `${id3}-projects`, css: styles2.paneCaption, children: m2.projects() }) }),
65971
+ projects.map((p2) => {
65972
+ const active = p2 === project;
65973
+ return /* @__PURE__ */ jsxRuntime.jsxs(
65974
+ react.chakra.button,
65975
+ {
65976
+ type: "button",
65977
+ css: styles2.paneRow,
65978
+ "data-page-library-project": p2,
65979
+ ...active ? { "data-active": "", "aria-current": "true" } : {},
65980
+ onClick: () => {
65981
+ if (!active) setProject(p2);
65982
+ },
65983
+ children: [
65984
+ /* @__PURE__ */ jsxRuntime.jsx(react.Box, { as: "span", css: styles2.paneIcon, "aria-hidden": true, children: /* @__PURE__ */ jsxRuntime.jsx(FontAwesomeIcon, { icon: active ? faFolderOpen : faFolder }) }),
65985
+ /* @__PURE__ */ jsxRuntime.jsx(react.Box, { as: "span", css: styles2.paneTitle, children: p2 })
65986
+ ]
65987
+ },
65988
+ p2
65989
+ );
65990
+ })
65991
+ ] }),
65992
+ /* @__PURE__ */ jsxRuntime.jsx(react.Box, { css: styles2.paneRule, "aria-hidden": true }),
65993
+ /* @__PURE__ */ jsxRuntime.jsxs(react.Box, { css: styles2.paneSection, role: "group", "aria-labelledby": `${id3}-pages`, children: [
65994
+ /* @__PURE__ */ jsxRuntime.jsxs(react.Box, { css: styles2.paneHead, children: [
65995
+ /* @__PURE__ */ jsxRuntime.jsx(react.Box, { as: "span", id: `${id3}-pages`, css: styles2.paneCaption, children: m2.pages() }),
65996
+ /* @__PURE__ */ jsxRuntime.jsx(react.Box, { as: "span", css: styles2.paneCount, children: words.number(np) })
65997
+ ] }),
65998
+ paneRows.map((p2) => {
65999
+ const dot = p2.live ? liveDot : draftDot;
66000
+ const state = p2.live ? m2.live() : m2.draft();
66001
+ return /* @__PURE__ */ jsxRuntime.jsxs(
66002
+ react.chakra.button,
66003
+ {
66004
+ type: "button",
66005
+ css: styles2.paneRow,
66006
+ "data-page": "",
66007
+ "data-page-library-page": p2.page,
66008
+ ...p2.page === current ? { "data-current": "", "aria-current": "page" } : {},
66009
+ onClick: () => openPage(p2.page),
66010
+ children: [
66011
+ /* @__PURE__ */ jsxRuntime.jsx(react.Box, { as: "span", css: styles2.paneTitle, children: p2.title }),
66012
+ /* @__PURE__ */ jsxRuntime.jsx(react.Box, { as: "span", css: dot.root, role: "img", "aria-label": state, title: state, children: /* @__PURE__ */ jsxRuntime.jsx(react.Box, { as: "span", css: dot.indicator }) })
66013
+ ]
66014
+ },
66015
+ p2.page
66016
+ );
66017
+ })
66018
+ ] }),
66019
+ /* @__PURE__ */ jsxRuntime.jsxs(react.Box, { css: styles2.legend, "data-page-library-legend": "", children: [
66020
+ /* @__PURE__ */ jsxRuntime.jsxs(react.Box, { as: "span", css: liveDot.root, children: [
66021
+ /* @__PURE__ */ jsxRuntime.jsx(react.Box, { as: "span", css: liveDot.indicator }),
66022
+ /* @__PURE__ */ jsxRuntime.jsx(react.Box, { as: "span", css: liveDot.label, children: m2.live() })
66023
+ ] }),
66024
+ /* @__PURE__ */ jsxRuntime.jsxs(react.Box, { as: "span", css: draftDot.root, children: [
66025
+ /* @__PURE__ */ jsxRuntime.jsx(react.Box, { as: "span", css: draftDot.indicator }),
66026
+ /* @__PURE__ */ jsxRuntime.jsx(react.Box, { as: "span", css: draftDot.label, children: m2.draft() })
66027
+ ] })
66028
+ ] })
66029
+ ] }),
66030
+ /* @__PURE__ */ jsxRuntime.jsxs(react.Box, { css: styles2.main, children: [
66031
+ /* @__PURE__ */ jsxRuntime.jsxs(react.Box, { as: "section", css: styles2.section, "data-section": "templates", "aria-labelledby": `${id3}-templates`, children: [
66032
+ /* @__PURE__ */ jsxRuntime.jsxs(react.Box, { css: styles2.sectionHead, children: [
66033
+ /* @__PURE__ */ jsxRuntime.jsx(react.Box, { as: "h3", id: `${id3}-templates`, css: styles2.sectionTitle, children: m2.templates() }),
66034
+ /* @__PURE__ */ jsxRuntime.jsx(react.Box, { as: "span", css: styles2.sectionSub, children: m2.cloneToStart() })
66035
+ ] }),
66036
+ /* @__PURE__ */ jsxRuntime.jsx(eastUiComponents.EastChakraLibrary, { value: templatesGallery, storageKey: `${storageKey}.templates`, renderMedia: templateMedia })
66037
+ ] }),
66038
+ /* @__PURE__ */ jsxRuntime.jsxs(react.Box, { as: "section", css: styles2.section, "data-section": "pages", "aria-labelledby": `${id3}-rows`, children: [
66039
+ /* @__PURE__ */ jsxRuntime.jsxs(react.Box, { css: styles2.sectionHead, children: [
66040
+ /* @__PURE__ */ jsxRuntime.jsx(react.Box, { as: "h3", id: `${id3}-rows`, css: styles2.sectionTitle, children: m2.pages() }),
66041
+ /* @__PURE__ */ jsxRuntime.jsx(react.Box, { as: "span", css: styles2.sectionSub, "data-page-library-shown": "", children: m2.pagesIn({ shown: words.number(shown), total: words.number(np), project, narrowed: shown !== np }) })
66042
+ ] }),
66043
+ /* @__PURE__ */ jsxRuntime.jsx(eastUiComponents.EastChakraLibrary, { value: pagesGallery, storageKey: `${storageKey}.pages`, renderMedia: pageMedia })
66044
+ ] })
66045
+ ] })
66046
+ ] })
66047
+ ] });
66048
+ });
66049
+ eastUiComponents.implementUIComponent(internal$1.StudioLibraryComponent, EastChakraStudioLibrary);
64201
66050
  function formatApiError(error3) {
64202
66051
  if (error3 instanceof e3ApiClient.ApiError && error3.details != null) {
64203
66052
  const details = error3.details;
@@ -66119,6 +67968,9 @@ exports.EastChakraDecisionQueue = EastChakraDecisionQueue;
66119
67968
  exports.EastChakraDiff = EastChakraDiff;
66120
67969
  exports.EastChakraExperiment = EastChakraExperiment;
66121
67970
  exports.EastChakraOntology = EastChakraOntology;
67971
+ exports.EastChakraStudioBuilder = EastChakraStudioBuilder;
67972
+ exports.EastChakraStudioLibrary = EastChakraStudioLibrary;
67973
+ exports.EastChakraStudioPage = EastChakraStudioPage;
66122
67974
  exports.EastValueViewer = EastValueViewer;
66123
67975
  exports.ErrorBoundary = ErrorBoundary;
66124
67976
  exports.FuncPlatform = FuncPlatform;
@@ -66135,6 +67987,7 @@ exports.RecordPlatform = RecordPlatform;
66135
67987
  exports.RecordRuntime = RecordRuntime;
66136
67988
  exports.StagedStore = StagedStore;
66137
67989
  exports.StatusDisplay = StatusDisplay;
67990
+ exports.StudioMessagesProvider = StudioMessagesProvider;
66138
67991
  exports.TaskPreview = TaskPreview;
66139
67992
  exports.UITaskPreview = UITaskPreview;
66140
67993
  exports.VirtualizedLogViewer = VirtualizedLogViewer;
@@ -66186,6 +68039,7 @@ exports.preloadReactiveDatasetList = preloadReactiveDatasetList;
66186
68039
  exports.realClock = realClock;
66187
68040
  exports.recordChannelKey = recordChannelKey;
66188
68041
  exports.signatureOfFuncHandleType = signatureOfFuncHandleType;
68042
+ exports.studioMessages = studioMessages;
66189
68043
  exports.trackDatasetPath = trackDatasetPath;
66190
68044
  exports.useDataflowCancel = useDataflowCancel;
66191
68045
  exports.useDataflowExecute = useDataflowExecute;
@@ -66225,6 +68079,7 @@ exports.useRepoGcStatus = useRepoGcStatus;
66225
68079
  exports.useRepoList = useRepoList;
66226
68080
  exports.useRepoRemove = useRepoRemove;
66227
68081
  exports.useRepoStatus = useRepoStatus;
68082
+ exports.useStudioMessages = useStudioMessages;
66228
68083
  exports.useTaskDetails = useTaskDetails;
66229
68084
  exports.useTaskExecutionList = useTaskExecutionList;
66230
68085
  exports.useTaskGet = useTaskGet;