@ethisyscore/plugin-ui 1.47.0 → 1.49.0

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.
@@ -72,7 +72,7 @@ function surfacePathFor(opts) {
72
72
  }
73
73
  var CONTEXT_KEY = /* @__PURE__ */ Symbol.for("ethisyscore.plugin-ui.hostSidebarActionsContext");
74
74
  var SINK_KEY = /* @__PURE__ */ Symbol.for("ethisyscore.plugin-ui.hostChromeDiagnosticSink");
75
- var HOST_CHROME_CONTRACT_VERSION = "2.0.0";
75
+ var HOST_CHROME_CONTRACT_VERSION = "2.1.0";
76
76
  var _g = globalThis;
77
77
  var HostSidebarActionsContext = _g[CONTEXT_KEY] ?? (_g[CONTEXT_KEY] = createContext(null));
78
78
  var _gs = globalThis;
@@ -549,8 +549,17 @@ function toDescriptor(a) {
549
549
  const { onSelect: _drop, ...rest } = a;
550
550
  return rest;
551
551
  }
552
+ if (a.kind === "group") {
553
+ const { children, ...rest } = a;
554
+ return { ...rest, children: children.map(toDescriptor) };
555
+ }
552
556
  return a;
553
557
  }
558
+ function collectDispatchHandlers(actions) {
559
+ return actions.flatMap(
560
+ (a) => a.kind === "dispatch" && a.onSelect ? [[a.id, a.onSelect]] : a.kind === "group" ? collectDispatchHandlers(a.children) : []
561
+ );
562
+ }
554
563
  function toContribution(input) {
555
564
  if (input.mode === SIDEBAR_MODE.none) {
556
565
  return { mode: SIDEBAR_MODE.none };
@@ -577,7 +586,7 @@ function contributionKey(input) {
577
586
  if (input.mode === SIDEBAR_MODE.none) {
578
587
  return JSON.stringify([SIDEBAR_MODE.none]);
579
588
  }
580
- const actionTuples = input.actions.map((a) => [
589
+ const actionTuple = (a) => [
581
590
  a.id,
582
591
  a.label,
583
592
  a.icon ?? "",
@@ -587,8 +596,11 @@ function contributionKey(input) {
587
596
  a.active ? 1 : 0,
588
597
  a.requiredPermission ?? "",
589
598
  a.kind,
590
- a.kind === "navigate" ? a.href : ""
591
- ]);
599
+ a.kind === "navigate" ? a.href : "",
600
+ // Group children fold into the key so a change to any collapsed leaf forces a republish.
601
+ a.kind === "group" ? a.children.map(actionTuple) : ""
602
+ ];
603
+ const actionTuples = input.actions.map(actionTuple);
592
604
  if (input.mode === SIDEBAR_MODE.actions) {
593
605
  return JSON.stringify([SIDEBAR_MODE.actions, input.entityToken, actionTuples]);
594
606
  }
@@ -621,11 +633,7 @@ function useHostSidebarActions(input) {
621
633
  const compatible = api && isHostChromeCompatible(api.capabilities?.contractVersion) ? api : null;
622
634
  const actions = input.mode === SIDEBAR_MODE.none ? [] : input.actions;
623
635
  const handlers = useRef(/* @__PURE__ */ new Map());
624
- handlers.current = new Map(
625
- actions.flatMap(
626
- (a) => a.kind === "dispatch" && a.onSelect ? [[a.id, a.onSelect]] : []
627
- )
628
- );
636
+ handlers.current = new Map(collectDispatchHandlers(actions));
629
637
  useEffect(() => {
630
638
  if (!compatible) {
631
639
  reportNoHost(pageId);
@@ -675,37 +683,46 @@ function slugRelative(href, basePath) {
675
683
  function isConfinable(slugRelativeHref) {
676
684
  return slugRelativeHref.length > 0 && !slugRelativeHref.startsWith("/") && !/^[a-zA-Z][a-zA-Z0-9+.-]*:/.test(slugRelativeHref) && !slugRelativeHref.includes("#");
677
685
  }
678
- function flattenLeaves(items) {
679
- const out = [];
680
- for (const item of items) {
681
- if (item.children?.length) out.push(...flattenLeaves(item.children));
682
- else out.push(item);
683
- }
684
- return out;
685
- }
686
686
  function toHostActions(actions, opts) {
687
+ const seen = /* @__PURE__ */ new Set();
687
688
  const out = [];
688
- for (const item of flattenLeaves(actions)) {
689
- const mapped = toHostAction(item, opts);
689
+ for (const item of actions) {
690
+ const mapped = toHostAction(item, opts, seen);
690
691
  if (mapped) out.push(mapped);
691
692
  }
692
- const seen = /* @__PURE__ */ new Set();
693
- return out.filter((a) => seen.has(a.id) ? false : (seen.add(a.id), true));
693
+ return out;
694
694
  }
695
- function toHostAction(item, opts) {
695
+ function toHostAction(item, opts, seen) {
696
+ if (seen.has(item.id)) return null;
696
697
  const slot = item.slot === "primary" ? "primary" : item.slot === "sidebar-only" ? "sidebar-only" : "overflow";
697
698
  const variant = item.variant === "danger" ? "danger" : void 0;
698
699
  const shared = { id: item.id, label: item.label, icon: item.icon, slot, variant, disabled: item.disabled };
700
+ if (item.children?.length) {
701
+ seen.add(item.id);
702
+ const children = [];
703
+ for (const child of item.children) {
704
+ const mapped = toHostAction(child, opts, seen);
705
+ if (mapped) children.push(mapped);
706
+ }
707
+ if (children.length === 0) {
708
+ seen.delete(item.id);
709
+ return null;
710
+ }
711
+ return { ...shared, kind: "group", children };
712
+ }
699
713
  if (item.href) {
700
714
  const href = slugRelative(item.href, opts.basePath);
701
715
  if (!isConfinable(href)) return null;
716
+ seen.add(item.id);
702
717
  return { ...shared, kind: "navigate", href };
703
718
  }
704
719
  if (item.actionId) {
705
720
  const actionId = item.actionId;
721
+ seen.add(item.id);
706
722
  return { ...shared, kind: "dispatch", onSelect: () => opts.onDispatch(actionId) };
707
723
  }
708
724
  if (item.onClick) {
725
+ seen.add(item.id);
709
726
  return { ...shared, kind: "dispatch", onSelect: item.onClick };
710
727
  }
711
728
  return null;