@almadar/ui 4.23.0 → 4.25.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.
@@ -37837,7 +37837,8 @@ function renderPatternChildren(children, onDismiss, parentId = "root", parentPat
37837
37837
  if (!child || typeof child !== "object") return null;
37838
37838
  const childId = `${parentId}-${index}`;
37839
37839
  const childPath = parentPath === "root" ? `root.children.${index}` : `${parentPath}.children.${index}`;
37840
- const { type: _childType, props: nestedProps, _id: _childNodeId, children: _childChildren, ...flatProps } = child;
37840
+ const childAsRecord = child;
37841
+ const { type: _childType, props: nestedProps, _id: _childNodeId, children: _childChildren, ...flatProps } = childAsRecord;
37841
37842
  const resolvedProps = nestedProps !== void 0 ? nestedProps : flatProps;
37842
37843
  if (_childChildren !== void 0 && nestedProps === void 0) {
37843
37844
  resolvedProps.children = _childChildren;
@@ -37865,7 +37866,46 @@ function renderPatternChildren(children, onDismiss, parentId = "root", parentPat
37865
37866
  });
37866
37867
  }
37867
37868
  function isPatternConfig(value) {
37868
- return value !== null && typeof value === "object" && !Array.isArray(value) && "type" in value && typeof value.type === "string";
37869
+ if (value === null || value === void 0) return false;
37870
+ if (typeof value !== "object") return false;
37871
+ if (Array.isArray(value)) return false;
37872
+ if (React113__default.isValidElement(value)) return false;
37873
+ if (value instanceof Date) return false;
37874
+ if (typeof value === "function") return false;
37875
+ const record = value;
37876
+ return "type" in record && typeof record.type === "string";
37877
+ }
37878
+ function isPlainConfigObject(value) {
37879
+ if (React113__default.isValidElement(value)) return false;
37880
+ if (value instanceof Date) return false;
37881
+ const proto = Object.getPrototypeOf(value);
37882
+ return proto === Object.prototype || proto === null;
37883
+ }
37884
+ function substituteTraitRefsDeep(value, pathKey) {
37885
+ if (typeof value === "string") {
37886
+ const match = TRAIT_BINDING_RE.exec(value);
37887
+ if (match) {
37888
+ const traitName = match[1];
37889
+ return /* @__PURE__ */ jsx(TraitFrame, { traitName }, `${pathKey}:${traitName}`);
37890
+ }
37891
+ return value;
37892
+ }
37893
+ if (typeof value === "number" || typeof value === "boolean" || value === null || value === void 0 || typeof value === "function") {
37894
+ return value;
37895
+ }
37896
+ if (Array.isArray(value)) {
37897
+ return value.map(
37898
+ (item, i) => substituteTraitRefsDeep(item, `${pathKey}[${i}]`)
37899
+ );
37900
+ }
37901
+ if (typeof value === "object" && isPlainConfigObject(value)) {
37902
+ const out = {};
37903
+ for (const [k, v] of Object.entries(value)) {
37904
+ out[k] = substituteTraitRefsDeep(v, `${pathKey}.${k}`);
37905
+ }
37906
+ return out;
37907
+ }
37908
+ return value;
37869
37909
  }
37870
37910
  function renderPatternProps(props, onDismiss) {
37871
37911
  const rendered = {};
@@ -37873,17 +37913,19 @@ function renderPatternProps(props, onDismiss) {
37873
37913
  if (key === "children") {
37874
37914
  rendered[key] = value;
37875
37915
  } else if (isPatternConfig(value)) {
37916
+ const nestedProps = {};
37917
+ for (const [k, v] of Object.entries(value)) {
37918
+ if (k !== "type") nestedProps[k] = v;
37919
+ }
37876
37920
  const childContent = {
37877
37921
  id: `prop-${key}`,
37878
37922
  pattern: value.type,
37879
- props: Object.fromEntries(
37880
- Object.entries(value).filter(([k]) => k !== "type")
37881
- ),
37923
+ props: nestedProps,
37882
37924
  priority: 0
37883
37925
  };
37884
37926
  rendered[key] = /* @__PURE__ */ jsx(SlotContentRenderer, { content: childContent, onDismiss });
37885
37927
  } else {
37886
- rendered[key] = value;
37928
+ rendered[key] = substituteTraitRefsDeep(value, `prop:${key}`);
37887
37929
  }
37888
37930
  }
37889
37931
  return rendered;
@@ -38226,7 +38268,7 @@ function resolveLambdaBindings(body, argName, arg) {
38226
38268
  let cur = arg;
38227
38269
  for (const seg of path.split(".")) {
38228
38270
  if (cur === null || cur === void 0) return void 0;
38229
- if (typeof cur !== "object") return void 0;
38271
+ if (typeof cur !== "object" || Array.isArray(cur)) return void 0;
38230
38272
  cur = cur[seg];
38231
38273
  }
38232
38274
  return cur;
@@ -38242,7 +38284,7 @@ function resolveLambdaBindings(body, argName, arg) {
38242
38284
  if (Array.isArray(body)) {
38243
38285
  return body.map((b) => resolveLambdaBindings(b, argName, arg));
38244
38286
  }
38245
- if (body !== null && typeof body === "object") {
38287
+ if (body !== null && typeof body === "object" && !React113__default.isValidElement(body) && !(body instanceof Date) && typeof body !== "function") {
38246
38288
  const out = {};
38247
38289
  for (const [k, v] of Object.entries(body)) {
38248
38290
  out[k] = resolveLambdaBindings(v, argName, arg);
@@ -38261,7 +38303,7 @@ function getSlotContentRenderer2() {
38261
38303
  function makeLambdaFn(argName, lambdaBody, callerKey) {
38262
38304
  return (item, index) => {
38263
38305
  const resolvedBody = resolveLambdaBindings(lambdaBody, argName, item);
38264
- if (resolvedBody === null || typeof resolvedBody !== "object" || Array.isArray(resolvedBody)) {
38306
+ if (resolvedBody === null || typeof resolvedBody !== "object" || Array.isArray(resolvedBody) || typeof resolvedBody === "function" || React113__default.isValidElement(resolvedBody) || resolvedBody instanceof Date) {
38265
38307
  return null;
38266
38308
  }
38267
38309
  const record = resolvedBody;
@@ -38269,12 +38311,14 @@ function makeLambdaFn(argName, lambdaBody, callerKey) {
38269
38311
  return null;
38270
38312
  }
38271
38313
  const SlotContentRenderer2 = getSlotContentRenderer2();
38314
+ const childProps = {};
38315
+ for (const [k, v] of Object.entries(record)) {
38316
+ if (k !== "type") childProps[k] = v;
38317
+ }
38272
38318
  const childContent = {
38273
38319
  id: `lambda-${callerKey}-${index}`,
38274
38320
  pattern: record.type,
38275
- props: Object.fromEntries(
38276
- Object.entries(record).filter(([k]) => k !== "type")
38277
- ),
38321
+ props: childProps,
38278
38322
  priority: 0
38279
38323
  };
38280
38324
  return React113__default.createElement(SlotContentRenderer2, { content: childContent });
@@ -38287,15 +38331,16 @@ function convertNode(node, callerKey) {
38287
38331
  const [, argName, body] = node;
38288
38332
  return makeLambdaFn(argName, body, callerKey);
38289
38333
  }
38334
+ const arr = node;
38290
38335
  let anyChanged = false;
38291
- const mapped = node.map((item, i) => {
38336
+ const mapped = arr.map((item, i) => {
38292
38337
  const next = convertNode(item, `${callerKey}[${i}]`);
38293
38338
  if (next !== item) anyChanged = true;
38294
38339
  return next;
38295
38340
  });
38296
38341
  return anyChanged ? mapped : node;
38297
38342
  }
38298
- if (typeof node === "object") {
38343
+ if (typeof node === "object" && !React113__default.isValidElement(node) && !(node instanceof Date)) {
38299
38344
  return convertObjectProps(node);
38300
38345
  }
38301
38346
  return node;
@@ -39486,6 +39531,7 @@ function prepareSchemaForPreview(input) {
39486
39531
  // runtime/OrbPreview.tsx
39487
39532
  init_logger();
39488
39533
  var xOrbitalLog2 = createLogger("almadar:runtime:cross-orbital");
39534
+ var navLog = createLogger("almadar:runtime:navigation");
39489
39535
  function normalizeChild(child) {
39490
39536
  if (typeof child === "string") return child;
39491
39537
  if (child === null || typeof child !== "object" || Array.isArray(child)) {
@@ -39561,6 +39607,19 @@ function TraitInitializer({ traits: traits2, orbitalNames, onNavigate, onLocalFa
39561
39607
  }, [bridge.connected, bridge.sendEvent, orbitalNames, uiSlots, onNavigate, embeddedTraits]);
39562
39608
  const opts = orbitalNames ? { onEventProcessed, navigate: onNavigate, traitConfigsByName, orbitalsByTrait, embeddedTraits } : { navigate: onNavigate, persistence, traitConfigsByName, orbitalsByTrait, embeddedTraits };
39563
39609
  const { sendEvent } = useTraitStateMachine(traits2, uiSlots, opts);
39610
+ const prevTraitNamesRef = useRef("");
39611
+ useEffect(() => {
39612
+ const traitNames = traits2.map((b) => b.trait?.name ?? "").filter(Boolean).sort().join(",");
39613
+ if (prevTraitNamesRef.current && prevTraitNamesRef.current !== traitNames) {
39614
+ navLog.info("page:trait-set-changed", {
39615
+ from: prevTraitNamesRef.current,
39616
+ to: traitNames,
39617
+ action: "clearAll-slots"
39618
+ });
39619
+ uiSlots.clearAll();
39620
+ }
39621
+ prevTraitNamesRef.current = traitNames;
39622
+ }, [traits2, uiSlots]);
39564
39623
  const initSentRef = useRef(false);
39565
39624
  useEffect(() => {
39566
39625
  if (!orbitalNames?.length) {
@@ -39575,6 +39634,10 @@ function TraitInitializer({ traits: traits2, orbitalNames, onNavigate, onLocalFa
39575
39634
  }, 5e3);
39576
39635
  return () => clearTimeout(fallback);
39577
39636
  }, [traits2, orbitalNames, sendEvent, onLocalFallback]);
39637
+ const orbitalsKey = (orbitalNames ?? []).slice().sort().join(",");
39638
+ useEffect(() => {
39639
+ initSentRef.current = false;
39640
+ }, [orbitalsKey]);
39578
39641
  useEffect(() => {
39579
39642
  if (!bridge.connected || !orbitalNames?.length || initSentRef.current) return;
39580
39643
  initSentRef.current = true;
@@ -39815,8 +39878,19 @@ function OrbPreview({
39815
39878
  }, [initialPageName, currentPage]);
39816
39879
  const handleNavigate = useCallback((path) => {
39817
39880
  const match = pages.find(({ page }) => page.path === path);
39881
+ navLog.info("handleNavigate", {
39882
+ path,
39883
+ matched: match?.page.name ?? null,
39884
+ availablePaths: pages.map((p2) => p2.page.path)
39885
+ });
39818
39886
  if (match) {
39819
39887
  setCurrentPage(match.page.name);
39888
+ if (typeof window !== "undefined") {
39889
+ const url = new URL(window.location.href);
39890
+ url.searchParams.set("page", path);
39891
+ window.history.pushState({}, "", url.toString());
39892
+ window.dispatchEvent(new PopStateEvent("popstate"));
39893
+ }
39820
39894
  }
39821
39895
  }, [pages]);
39822
39896
  if (!parseResult.ok) {
@@ -39828,18 +39902,30 @@ function OrbPreview({
39828
39902
  const containerRef = useRef(null);
39829
39903
  useEffect(() => {
39830
39904
  const el = containerRef.current;
39831
- if (!el || pages.length <= 1) return;
39905
+ if (!el) return;
39906
+ if (pages.length <= 1) {
39907
+ navLog.info("interceptor:skipped", { reason: "single-page schema", pageCount: pages.length });
39908
+ return;
39909
+ }
39832
39910
  const handler = (e) => {
39833
39911
  const anchor = e.target.closest("a");
39834
39912
  if (!anchor) return;
39835
39913
  const href = anchor.getAttribute("href") ?? anchor.getAttribute("to") ?? "";
39836
- if (!href || href.startsWith("http") || href.startsWith("mailto:") || href.startsWith("#")) return;
39914
+ navLog.info("click:intercepted", {
39915
+ href,
39916
+ anchorText: anchor.textContent?.trim().slice(0, 40)
39917
+ });
39918
+ if (!href || href.startsWith("http") || href.startsWith("mailto:") || href.startsWith("#")) {
39919
+ navLog.info("click:skipped", { href, reason: "external/empty/hash" });
39920
+ return;
39921
+ }
39837
39922
  e.preventDefault();
39838
39923
  e.stopPropagation();
39839
39924
  e.stopImmediatePropagation();
39840
39925
  handleNavigate(href);
39841
39926
  };
39842
39927
  el.addEventListener("click", handler, true);
39928
+ navLog.info("interceptor:installed", { pageCount: pages.length, paths: pages.map((p2) => p2.page.path) });
39843
39929
  return () => el.removeEventListener("click", handler, true);
39844
39930
  }, [pages, handleNavigate]);
39845
39931
  return /* @__PURE__ */ jsxs(
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@almadar/ui",
3
- "version": "4.23.0",
3
+ "version": "4.25.0",
4
4
  "description": "React UI components, hooks, and providers for Almadar",
5
5
  "type": "module",
6
6
  "main": "./dist/components/index.js",
@@ -118,7 +118,7 @@
118
118
  "access": "public"
119
119
  },
120
120
  "dependencies": {
121
- "@almadar/core": "^7.10.0",
121
+ "@almadar/core": ">=7.12.0",
122
122
  "@almadar/evaluator": ">=2.9.2",
123
123
  "@almadar/patterns": "^2.20.2",
124
124
  "@almadar/runtime": "^6.0.0",