@almadar/ui 4.6.6 → 4.6.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,5 @@
1
1
  import * as React115 from 'react';
2
- import React115__default, { createContext, useContext, useRef, useEffect, useCallback, useMemo, Suspense, useState, useLayoutEffect, lazy, useId } from 'react';
2
+ import React115__default, { createContext, useContext, useRef, useEffect, useCallback, useMemo, useState, Suspense, useLayoutEffect, lazy, useId } from 'react';
3
3
  import { EventBusContext, OrbitalProvider, VerificationProvider } from '@almadar/ui/providers';
4
4
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
5
5
  import { clsx } from 'clsx';
@@ -1048,6 +1048,109 @@ var init_verificationRegistry = __esm({
1048
1048
  exposeOnWindow();
1049
1049
  }
1050
1050
  });
1051
+ function refId(obj) {
1052
+ if (obj === null || obj === void 0 || typeof obj !== "object") return null;
1053
+ const existing = refIds.get(obj);
1054
+ if (existing !== void 0) return existing;
1055
+ const id = nextRefId++;
1056
+ refIds.set(obj, id);
1057
+ return id;
1058
+ }
1059
+ function slotEntriesInOrder(slot) {
1060
+ if (!slot) return [];
1061
+ const out = [];
1062
+ for (const [sourceKey, entry] of Object.entries(slot)) {
1063
+ if (entry.patterns.length > 0) {
1064
+ out.push({ sourceKey, entry });
1065
+ }
1066
+ }
1067
+ return out;
1068
+ }
1069
+ function SlotsProvider({ children }) {
1070
+ const [slots, setSlots] = useState({});
1071
+ const setSlotPatterns = useCallback((slot, patterns, source) => {
1072
+ const sourceKey = source?.trait ?? DEFAULT_SOURCE_KEY;
1073
+ const entityProp = patterns[0]?.pattern && typeof patterns[0].pattern === "object" ? patterns[0].pattern.entity : void 0;
1074
+ slotLog.debug("setSlotPatterns", {
1075
+ slot,
1076
+ sourceKey,
1077
+ patternCount: patterns.length,
1078
+ firstPatternType: patterns[0]?.pattern && typeof patterns[0].pattern === "object" ? patterns[0].pattern.type : void 0,
1079
+ entityRefId: refId(entityProp)
1080
+ });
1081
+ setSlots((prev) => {
1082
+ const prevSlot = prev[slot] ?? {};
1083
+ return {
1084
+ ...prev,
1085
+ [slot]: {
1086
+ ...prevSlot,
1087
+ [sourceKey]: { patterns, source }
1088
+ }
1089
+ };
1090
+ });
1091
+ }, []);
1092
+ const clearSlot = useCallback((slot) => {
1093
+ setSlots((prev) => {
1094
+ const existing = prev[slot];
1095
+ if (existing && Object.keys(existing).length === 0) {
1096
+ return prev;
1097
+ }
1098
+ return { ...prev, [slot]: {} };
1099
+ });
1100
+ }, []);
1101
+ const clearSlotForSource = useCallback((slot, sourceTrait) => {
1102
+ setSlots((prev) => {
1103
+ const existing = prev[slot];
1104
+ if (!existing || !(sourceTrait in existing)) return prev;
1105
+ const next = { ...existing };
1106
+ delete next[sourceTrait];
1107
+ return { ...prev, [slot]: next };
1108
+ });
1109
+ }, []);
1110
+ const clearAllSlots = useCallback(() => {
1111
+ setSlots({});
1112
+ }, []);
1113
+ const actionsRef = useRef({
1114
+ setSlotPatterns,
1115
+ clearSlot,
1116
+ clearSlotForSource,
1117
+ clearAllSlots
1118
+ });
1119
+ actionsRef.current = { setSlotPatterns, clearSlot, clearSlotForSource, clearAllSlots };
1120
+ const [stableActions] = useState(() => ({
1121
+ setSlotPatterns: (...args) => actionsRef.current.setSlotPatterns(...args),
1122
+ clearSlot: (...args) => actionsRef.current.clearSlot(...args),
1123
+ clearSlotForSource: (...args) => actionsRef.current.clearSlotForSource(...args),
1124
+ clearAllSlots: () => actionsRef.current.clearAllSlots()
1125
+ }));
1126
+ return /* @__PURE__ */ jsx(SlotsActionsContext.Provider, { value: stableActions, children: /* @__PURE__ */ jsx(SlotsStateContext.Provider, { value: slots, children }) });
1127
+ }
1128
+ function useSlots() {
1129
+ return useContext(SlotsStateContext);
1130
+ }
1131
+ function useSlotContent(slotName) {
1132
+ const slots = useContext(SlotsStateContext);
1133
+ return slots[slotName] || null;
1134
+ }
1135
+ function useSlotsActions() {
1136
+ const actions = useContext(SlotsActionsContext);
1137
+ if (!actions) {
1138
+ throw new Error("useSlotsActions must be used within a SlotsProvider");
1139
+ }
1140
+ return actions;
1141
+ }
1142
+ var slotLog, refIds, nextRefId, DEFAULT_SOURCE_KEY, SlotsStateContext, SlotsActionsContext;
1143
+ var init_SlotsContext = __esm({
1144
+ "runtime/ui/SlotsContext.tsx"() {
1145
+ init_logger();
1146
+ slotLog = createLogger("almadar:ui:slot-render");
1147
+ refIds = /* @__PURE__ */ new WeakMap();
1148
+ nextRefId = 1;
1149
+ DEFAULT_SOURCE_KEY = "__default__";
1150
+ SlotsStateContext = createContext({});
1151
+ SlotsActionsContext = createContext(null);
1152
+ }
1153
+ });
1051
1154
  function cn(...inputs) {
1052
1155
  return twMerge(clsx(inputs));
1053
1156
  }
@@ -19762,20 +19865,21 @@ var init_InputGroup = __esm({
19762
19865
 
19763
19866
  // lib/debug.ts
19764
19867
  function isDebugEnabled() {
19765
- return DEBUG_ENABLED;
19868
+ if (DEBUG_ENABLED) return true;
19869
+ return typeof window !== "undefined" && window.__ALMADAR_DEBUG_VERIFY__ === true;
19766
19870
  }
19767
19871
  function debug(...args) {
19768
- if (DEBUG_ENABLED) {
19872
+ if (isDebugEnabled()) {
19769
19873
  console.log("[DEBUG]", ...args);
19770
19874
  }
19771
19875
  }
19772
19876
  function debugGroup(label) {
19773
- if (DEBUG_ENABLED) {
19877
+ if (isDebugEnabled()) {
19774
19878
  console.group(`[DEBUG] ${label}`);
19775
19879
  }
19776
19880
  }
19777
19881
  function debugGroupEnd() {
19778
- if (DEBUG_ENABLED) {
19882
+ if (isDebugEnabled()) {
19779
19883
  console.groupEnd();
19780
19884
  }
19781
19885
  }
@@ -28288,7 +28392,14 @@ var init_Form = __esm({
28288
28392
  // Schema-based props
28289
28393
  entity,
28290
28394
  fields,
28291
- initialData = {},
28395
+ // No `= {}` default: a fresh `{}` evaluated inline on every render
28396
+ // would change the prop reference every tick and bust the useMemo
28397
+ // cache below (`[entity, initialData]` deps), reigniting the
28398
+ // setFormData useEffect on every keystroke and producing an
28399
+ // infinite re-render loop with stuck form inputs. The memo and
28400
+ // submit handler both handle `undefined` already via the
28401
+ // `typeof initialData === 'object'` guard.
28402
+ initialData,
28292
28403
  isLoading = false,
28293
28404
  error,
28294
28405
  submitLabel,
@@ -28315,9 +28426,11 @@ var init_Form = __esm({
28315
28426
  const isSchemaEntity = isOrbitalEntitySchema(entity);
28316
28427
  const resolvedEntity = isSchemaEntity ? entity : void 0;
28317
28428
  const entityName = typeof entity === "string" ? entity : resolvedEntity?.name;
28318
- const entityRowAsInitial = isPlainEntityRow(entity) ? entity : void 0;
28319
- const callerInitial = initialData !== null && typeof initialData === "object" && !Array.isArray(initialData) ? initialData : {};
28320
- const normalizedInitialData = entityRowAsInitial !== void 0 ? { ...entityRowAsInitial, ...callerInitial } : callerInitial;
28429
+ const normalizedInitialData = React115__default.useMemo(() => {
28430
+ const entityRowAsInitial = isPlainEntityRow(entity) ? entity : void 0;
28431
+ const callerInitial = initialData !== null && typeof initialData === "object" && !Array.isArray(initialData) ? initialData : {};
28432
+ return entityRowAsInitial !== void 0 ? { ...entityRowAsInitial, ...callerInitial } : callerInitial;
28433
+ }, [entity, initialData]);
28321
28434
  const entityDerivedFields = React115__default.useMemo(() => {
28322
28435
  if (fields && fields.length > 0) return void 0;
28323
28436
  if (!resolvedEntity) return void 0;
@@ -28343,6 +28456,19 @@ var init_Form = __esm({
28343
28456
  const [collapsedSections, setCollapsedSections] = React115__default.useState(
28344
28457
  /* @__PURE__ */ new Set()
28345
28458
  );
28459
+ const formMode = props.mode;
28460
+ const mountedRef = React115__default.useRef(false);
28461
+ if (!mountedRef.current) {
28462
+ mountedRef.current = true;
28463
+ debug("forms", "mount", {
28464
+ mode: formMode,
28465
+ submitEvent,
28466
+ cancelEvent,
28467
+ fieldNames: (fields ?? []).map((f3) => f3.name ?? f3.field).filter(Boolean),
28468
+ initialDataKeys: Object.keys(normalizedInitialData),
28469
+ initialData: normalizedInitialData
28470
+ });
28471
+ }
28346
28472
  const shouldShowCancel = showCancel ?? (fields && fields.length > 0);
28347
28473
  const evalContext = React115__default.useMemo(
28348
28474
  () => ({
@@ -28354,6 +28480,12 @@ var init_Form = __esm({
28354
28480
  [formData, externalContext]
28355
28481
  );
28356
28482
  React115__default.useEffect(() => {
28483
+ debug("forms", "initialData-sync", {
28484
+ mode: formMode,
28485
+ normalizedInitialData,
28486
+ prevFormData: formData,
28487
+ willSet: Object.keys(normalizedInitialData).length > 0
28488
+ });
28357
28489
  if (Object.keys(normalizedInitialData).length > 0) {
28358
28490
  setFormData(normalizedInitialData);
28359
28491
  }
@@ -28410,6 +28542,7 @@ var init_Form = __esm({
28410
28542
  );
28411
28543
  const handleChange = (name, value) => {
28412
28544
  const newFormData = { ...formData, [name]: value };
28545
+ debug("forms", "field-change", { mode: formMode, name, value, prevFormData: formData, newFormData });
28413
28546
  setFormData(newFormData);
28414
28547
  eventBus.emit("UI:FIELD_CHANGED", {
28415
28548
  fieldId: name,
@@ -28448,11 +28581,18 @@ var init_Form = __esm({
28448
28581
  };
28449
28582
  const handleSubmit = (e) => {
28450
28583
  e.preventDefault();
28584
+ debug("forms", "submit-enter", {
28585
+ mode: formMode,
28586
+ submitEvent,
28587
+ formData,
28588
+ normalizedInitialData
28589
+ });
28451
28590
  const mergedData = {
28452
28591
  ...normalizedInitialData,
28453
28592
  ...formData
28454
28593
  };
28455
28594
  const payload = { data: mergedData };
28595
+ debug("forms", "submit-emit", { mode: formMode, submitEvent: `UI:${submitEvent}`, payloadData: payload.data });
28456
28596
  eventBus.emit(`UI:${submitEvent}`, payload);
28457
28597
  if (onSubmit) {
28458
28598
  eventBus.emit(`UI:${onSubmit}`, payload);
@@ -37683,6 +37823,14 @@ function SlotContentRenderer({
37683
37823
  patternPath
37684
37824
  }) {
37685
37825
  const entityProp = content.props.entity;
37826
+ if (content.pattern === "form-section") {
37827
+ slotLog.debug("SlotContentRenderer:form-section-render", {
37828
+ contentId: content.id,
37829
+ sourceTrait: content.sourceTrait,
37830
+ entityRefId: refId(entityProp),
37831
+ entityIsObject: entityProp !== null && typeof entityProp === "object" && !Array.isArray(entityProp)
37832
+ });
37833
+ }
37686
37834
  if (typeof entityProp === "string" && entityProp.length > 0) {
37687
37835
  if (typeof process !== "undefined" && process.env && process.env.NODE_ENV !== "production") {
37688
37836
  throw new Error(
@@ -37826,6 +37974,7 @@ var init_UISlotRenderer = __esm({
37826
37974
  init_Box();
37827
37975
  init_Typography();
37828
37976
  init_useEventBus();
37977
+ init_SlotsContext();
37829
37978
  init_cn();
37830
37979
  init_ErrorBoundary();
37831
37980
  init_Skeleton();
@@ -37986,7 +38135,13 @@ function useTraitStateMachine(traitBindings, slotsActions, options) {
37986
38135
  const { entities } = useEntitySchema();
37987
38136
  const manager = useMemo(() => {
37988
38137
  const traitDefs = traitBindings.map(toTraitDefinition);
37989
- return new StateMachineManager(traitDefs);
38138
+ const m = new StateMachineManager(traitDefs);
38139
+ for (const binding of traitBindings) {
38140
+ if (binding.config !== void 0) {
38141
+ m.setTraitConfig(binding.trait.name, binding.config);
38142
+ }
38143
+ }
38144
+ return m;
37990
38145
  }, [traitBindings]);
37991
38146
  const [traitStates, setTraitStates] = useState(() => {
37992
38147
  return manager.getAllStates();
@@ -38632,90 +38787,16 @@ function useTrait(traitName) {
38632
38787
  const context = useTraitContext();
38633
38788
  return context.getTrait(traitName);
38634
38789
  }
38635
- var DEFAULT_SOURCE_KEY = "__default__";
38636
- function slotEntriesInOrder(slot) {
38637
- if (!slot) return [];
38638
- const out = [];
38639
- for (const [sourceKey, entry] of Object.entries(slot)) {
38640
- if (entry.patterns.length > 0) {
38641
- out.push({ sourceKey, entry });
38642
- }
38643
- }
38644
- return out;
38645
- }
38646
- var SlotsStateContext = createContext({});
38647
- var SlotsActionsContext = createContext(null);
38648
- function SlotsProvider({ children }) {
38649
- const [slots, setSlots] = useState({});
38650
- const setSlotPatterns = useCallback((slot, patterns, source) => {
38651
- const sourceKey = source?.trait ?? DEFAULT_SOURCE_KEY;
38652
- setSlots((prev) => {
38653
- const prevSlot = prev[slot] ?? {};
38654
- return {
38655
- ...prev,
38656
- [slot]: {
38657
- ...prevSlot,
38658
- [sourceKey]: { patterns, source }
38659
- }
38660
- };
38661
- });
38662
- }, []);
38663
- const clearSlot = useCallback((slot) => {
38664
- setSlots((prev) => {
38665
- const existing = prev[slot];
38666
- if (existing && Object.keys(existing).length === 0) {
38667
- return prev;
38668
- }
38669
- return { ...prev, [slot]: {} };
38670
- });
38671
- }, []);
38672
- const clearSlotForSource = useCallback((slot, sourceTrait) => {
38673
- setSlots((prev) => {
38674
- const existing = prev[slot];
38675
- if (!existing || !(sourceTrait in existing)) return prev;
38676
- const next = { ...existing };
38677
- delete next[sourceTrait];
38678
- return { ...prev, [slot]: next };
38679
- });
38680
- }, []);
38681
- const clearAllSlots = useCallback(() => {
38682
- setSlots({});
38683
- }, []);
38684
- const actionsRef = useRef({
38685
- setSlotPatterns,
38686
- clearSlot,
38687
- clearSlotForSource,
38688
- clearAllSlots
38689
- });
38690
- actionsRef.current = { setSlotPatterns, clearSlot, clearSlotForSource, clearAllSlots };
38691
- const [stableActions] = useState(() => ({
38692
- setSlotPatterns: (...args) => actionsRef.current.setSlotPatterns(...args),
38693
- clearSlot: (...args) => actionsRef.current.clearSlot(...args),
38694
- clearSlotForSource: (...args) => actionsRef.current.clearSlotForSource(...args),
38695
- clearAllSlots: () => actionsRef.current.clearAllSlots()
38696
- }));
38697
- return /* @__PURE__ */ jsx(SlotsActionsContext.Provider, { value: stableActions, children: /* @__PURE__ */ jsx(SlotsStateContext.Provider, { value: slots, children }) });
38698
- }
38699
- function useSlots() {
38700
- return useContext(SlotsStateContext);
38701
- }
38702
- function useSlotContent(slotName) {
38703
- const slots = useContext(SlotsStateContext);
38704
- return slots[slotName] || null;
38705
- }
38706
- function useSlotsActions() {
38707
- const actions = useContext(SlotsActionsContext);
38708
- if (!actions) {
38709
- throw new Error("useSlotsActions must be used within a SlotsProvider");
38710
- }
38711
- return actions;
38712
- }
38790
+
38791
+ // runtime/index.ts
38792
+ init_SlotsContext();
38713
38793
 
38714
38794
  // runtime/OrbPreview.tsx
38715
38795
  init_Box();
38716
38796
  init_Typography();
38717
38797
  init_UISlotRenderer();
38718
38798
  init_useEventBus();
38799
+ init_SlotsContext();
38719
38800
  init_EntitySchemaContext();
38720
38801
 
38721
38802
  // runtime/ServerBridge.tsx
@@ -38935,6 +39016,10 @@ function SlotBridge() {
38935
39016
  const slots = useSlots();
38936
39017
  const { render, clear } = useUISlots();
38937
39018
  useEffect(() => {
39019
+ slotLog.debug("SlotBridge:effect-fired", {
39020
+ slotCount: Object.keys(slots).length,
39021
+ slots: Object.keys(slots)
39022
+ });
38938
39023
  for (const [slotName, slotState] of Object.entries(slots)) {
38939
39024
  const entries = slotEntriesInOrder(slotState);
38940
39025
  if (entries.length === 0) {
@@ -38956,6 +39041,12 @@ function SlotBridge() {
38956
39041
  const only = children[0];
38957
39042
  const { type, children: nested, ...rest } = only;
38958
39043
  const lastEntry = entries[entries.length - 1];
39044
+ slotLog.debug("SlotBridge:render-single", {
39045
+ slot: slotName,
39046
+ patternType: type,
39047
+ entityRefId: refId(rest.entity),
39048
+ sourceTrait: lastEntry.entry.source?.trait
39049
+ });
38959
39050
  render({
38960
39051
  target: slotName,
38961
39052
  pattern: type,
@@ -20,6 +20,9 @@
20
20
  */
21
21
  import React from 'react';
22
22
  import type { PatternConfig, EventSource, ResolvedTrait } from '@almadar/core';
23
+ declare const slotLog: import("../../lib").Logger;
24
+ export declare function refId(obj: unknown): number | null;
25
+ export { slotLog };
23
26
  /** A single pattern entry in a slot */
24
27
  export interface SlotPatternEntry {
25
28
  pattern: PatternConfig;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@almadar/ui",
3
- "version": "4.6.6",
3
+ "version": "4.6.10",
4
4
  "description": "React UI components, hooks, and providers for Almadar",
5
5
  "type": "module",
6
6
  "main": "./dist/components/index.js",
@@ -121,7 +121,7 @@
121
121
  "@almadar/core": "^7.0.0",
122
122
  "@almadar/evaluator": ">=2.9.2",
123
123
  "@almadar/patterns": ">=2.17.1",
124
- "@almadar/runtime": "^4.11.1",
124
+ "@almadar/runtime": "^5.3.0",
125
125
  "@almadar/std": ">=6.4.1",
126
126
  "@almadar/syntax": ">=1.3.1",
127
127
  "@xyflow/react": "12.10.1",