@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.
@@ -1093,6 +1093,109 @@ var init_verificationRegistry = __esm({
1093
1093
  exposeOnWindow();
1094
1094
  }
1095
1095
  });
1096
+ function refId(obj) {
1097
+ if (obj === null || obj === void 0 || typeof obj !== "object") return null;
1098
+ const existing = refIds.get(obj);
1099
+ if (existing !== void 0) return existing;
1100
+ const id = nextRefId++;
1101
+ refIds.set(obj, id);
1102
+ return id;
1103
+ }
1104
+ function slotEntriesInOrder(slot) {
1105
+ if (!slot) return [];
1106
+ const out = [];
1107
+ for (const [sourceKey, entry] of Object.entries(slot)) {
1108
+ if (entry.patterns.length > 0) {
1109
+ out.push({ sourceKey, entry });
1110
+ }
1111
+ }
1112
+ return out;
1113
+ }
1114
+ function SlotsProvider({ children }) {
1115
+ const [slots, setSlots] = React115.useState({});
1116
+ const setSlotPatterns = React115.useCallback((slot, patterns, source) => {
1117
+ const sourceKey = source?.trait ?? DEFAULT_SOURCE_KEY;
1118
+ const entityProp = patterns[0]?.pattern && typeof patterns[0].pattern === "object" ? patterns[0].pattern.entity : void 0;
1119
+ slotLog.debug("setSlotPatterns", {
1120
+ slot,
1121
+ sourceKey,
1122
+ patternCount: patterns.length,
1123
+ firstPatternType: patterns[0]?.pattern && typeof patterns[0].pattern === "object" ? patterns[0].pattern.type : void 0,
1124
+ entityRefId: refId(entityProp)
1125
+ });
1126
+ setSlots((prev) => {
1127
+ const prevSlot = prev[slot] ?? {};
1128
+ return {
1129
+ ...prev,
1130
+ [slot]: {
1131
+ ...prevSlot,
1132
+ [sourceKey]: { patterns, source }
1133
+ }
1134
+ };
1135
+ });
1136
+ }, []);
1137
+ const clearSlot = React115.useCallback((slot) => {
1138
+ setSlots((prev) => {
1139
+ const existing = prev[slot];
1140
+ if (existing && Object.keys(existing).length === 0) {
1141
+ return prev;
1142
+ }
1143
+ return { ...prev, [slot]: {} };
1144
+ });
1145
+ }, []);
1146
+ const clearSlotForSource = React115.useCallback((slot, sourceTrait) => {
1147
+ setSlots((prev) => {
1148
+ const existing = prev[slot];
1149
+ if (!existing || !(sourceTrait in existing)) return prev;
1150
+ const next = { ...existing };
1151
+ delete next[sourceTrait];
1152
+ return { ...prev, [slot]: next };
1153
+ });
1154
+ }, []);
1155
+ const clearAllSlots = React115.useCallback(() => {
1156
+ setSlots({});
1157
+ }, []);
1158
+ const actionsRef = React115.useRef({
1159
+ setSlotPatterns,
1160
+ clearSlot,
1161
+ clearSlotForSource,
1162
+ clearAllSlots
1163
+ });
1164
+ actionsRef.current = { setSlotPatterns, clearSlot, clearSlotForSource, clearAllSlots };
1165
+ const [stableActions] = React115.useState(() => ({
1166
+ setSlotPatterns: (...args) => actionsRef.current.setSlotPatterns(...args),
1167
+ clearSlot: (...args) => actionsRef.current.clearSlot(...args),
1168
+ clearSlotForSource: (...args) => actionsRef.current.clearSlotForSource(...args),
1169
+ clearAllSlots: () => actionsRef.current.clearAllSlots()
1170
+ }));
1171
+ return /* @__PURE__ */ jsxRuntime.jsx(SlotsActionsContext.Provider, { value: stableActions, children: /* @__PURE__ */ jsxRuntime.jsx(SlotsStateContext.Provider, { value: slots, children }) });
1172
+ }
1173
+ function useSlots() {
1174
+ return React115.useContext(SlotsStateContext);
1175
+ }
1176
+ function useSlotContent(slotName) {
1177
+ const slots = React115.useContext(SlotsStateContext);
1178
+ return slots[slotName] || null;
1179
+ }
1180
+ function useSlotsActions() {
1181
+ const actions = React115.useContext(SlotsActionsContext);
1182
+ if (!actions) {
1183
+ throw new Error("useSlotsActions must be used within a SlotsProvider");
1184
+ }
1185
+ return actions;
1186
+ }
1187
+ var slotLog, refIds, nextRefId, DEFAULT_SOURCE_KEY, SlotsStateContext, SlotsActionsContext;
1188
+ var init_SlotsContext = __esm({
1189
+ "runtime/ui/SlotsContext.tsx"() {
1190
+ init_logger();
1191
+ slotLog = createLogger("almadar:ui:slot-render");
1192
+ refIds = /* @__PURE__ */ new WeakMap();
1193
+ nextRefId = 1;
1194
+ DEFAULT_SOURCE_KEY = "__default__";
1195
+ SlotsStateContext = React115.createContext({});
1196
+ SlotsActionsContext = React115.createContext(null);
1197
+ }
1198
+ });
1096
1199
  function cn(...inputs) {
1097
1200
  return tailwindMerge.twMerge(clsx.clsx(inputs));
1098
1201
  }
@@ -19807,20 +19910,21 @@ var init_InputGroup = __esm({
19807
19910
 
19808
19911
  // lib/debug.ts
19809
19912
  function isDebugEnabled() {
19810
- return DEBUG_ENABLED;
19913
+ if (DEBUG_ENABLED) return true;
19914
+ return typeof window !== "undefined" && window.__ALMADAR_DEBUG_VERIFY__ === true;
19811
19915
  }
19812
19916
  function debug(...args) {
19813
- if (DEBUG_ENABLED) {
19917
+ if (isDebugEnabled()) {
19814
19918
  console.log("[DEBUG]", ...args);
19815
19919
  }
19816
19920
  }
19817
19921
  function debugGroup(label) {
19818
- if (DEBUG_ENABLED) {
19922
+ if (isDebugEnabled()) {
19819
19923
  console.group(`[DEBUG] ${label}`);
19820
19924
  }
19821
19925
  }
19822
19926
  function debugGroupEnd() {
19823
- if (DEBUG_ENABLED) {
19927
+ if (isDebugEnabled()) {
19824
19928
  console.groupEnd();
19825
19929
  }
19826
19930
  }
@@ -28333,7 +28437,14 @@ var init_Form = __esm({
28333
28437
  // Schema-based props
28334
28438
  entity,
28335
28439
  fields,
28336
- initialData = {},
28440
+ // No `= {}` default: a fresh `{}` evaluated inline on every render
28441
+ // would change the prop reference every tick and bust the useMemo
28442
+ // cache below (`[entity, initialData]` deps), reigniting the
28443
+ // setFormData useEffect on every keystroke and producing an
28444
+ // infinite re-render loop with stuck form inputs. The memo and
28445
+ // submit handler both handle `undefined` already via the
28446
+ // `typeof initialData === 'object'` guard.
28447
+ initialData,
28337
28448
  isLoading = false,
28338
28449
  error,
28339
28450
  submitLabel,
@@ -28360,9 +28471,11 @@ var init_Form = __esm({
28360
28471
  const isSchemaEntity = isOrbitalEntitySchema(entity);
28361
28472
  const resolvedEntity = isSchemaEntity ? entity : void 0;
28362
28473
  const entityName = typeof entity === "string" ? entity : resolvedEntity?.name;
28363
- const entityRowAsInitial = isPlainEntityRow(entity) ? entity : void 0;
28364
- const callerInitial = initialData !== null && typeof initialData === "object" && !Array.isArray(initialData) ? initialData : {};
28365
- const normalizedInitialData = entityRowAsInitial !== void 0 ? { ...entityRowAsInitial, ...callerInitial } : callerInitial;
28474
+ const normalizedInitialData = React115__namespace.default.useMemo(() => {
28475
+ const entityRowAsInitial = isPlainEntityRow(entity) ? entity : void 0;
28476
+ const callerInitial = initialData !== null && typeof initialData === "object" && !Array.isArray(initialData) ? initialData : {};
28477
+ return entityRowAsInitial !== void 0 ? { ...entityRowAsInitial, ...callerInitial } : callerInitial;
28478
+ }, [entity, initialData]);
28366
28479
  const entityDerivedFields = React115__namespace.default.useMemo(() => {
28367
28480
  if (fields && fields.length > 0) return void 0;
28368
28481
  if (!resolvedEntity) return void 0;
@@ -28388,6 +28501,19 @@ var init_Form = __esm({
28388
28501
  const [collapsedSections, setCollapsedSections] = React115__namespace.default.useState(
28389
28502
  /* @__PURE__ */ new Set()
28390
28503
  );
28504
+ const formMode = props.mode;
28505
+ const mountedRef = React115__namespace.default.useRef(false);
28506
+ if (!mountedRef.current) {
28507
+ mountedRef.current = true;
28508
+ debug("forms", "mount", {
28509
+ mode: formMode,
28510
+ submitEvent,
28511
+ cancelEvent,
28512
+ fieldNames: (fields ?? []).map((f3) => f3.name ?? f3.field).filter(Boolean),
28513
+ initialDataKeys: Object.keys(normalizedInitialData),
28514
+ initialData: normalizedInitialData
28515
+ });
28516
+ }
28391
28517
  const shouldShowCancel = showCancel ?? (fields && fields.length > 0);
28392
28518
  const evalContext = React115__namespace.default.useMemo(
28393
28519
  () => ({
@@ -28399,6 +28525,12 @@ var init_Form = __esm({
28399
28525
  [formData, externalContext]
28400
28526
  );
28401
28527
  React115__namespace.default.useEffect(() => {
28528
+ debug("forms", "initialData-sync", {
28529
+ mode: formMode,
28530
+ normalizedInitialData,
28531
+ prevFormData: formData,
28532
+ willSet: Object.keys(normalizedInitialData).length > 0
28533
+ });
28402
28534
  if (Object.keys(normalizedInitialData).length > 0) {
28403
28535
  setFormData(normalizedInitialData);
28404
28536
  }
@@ -28455,6 +28587,7 @@ var init_Form = __esm({
28455
28587
  );
28456
28588
  const handleChange = (name, value) => {
28457
28589
  const newFormData = { ...formData, [name]: value };
28590
+ debug("forms", "field-change", { mode: formMode, name, value, prevFormData: formData, newFormData });
28458
28591
  setFormData(newFormData);
28459
28592
  eventBus.emit("UI:FIELD_CHANGED", {
28460
28593
  fieldId: name,
@@ -28493,11 +28626,18 @@ var init_Form = __esm({
28493
28626
  };
28494
28627
  const handleSubmit = (e) => {
28495
28628
  e.preventDefault();
28629
+ debug("forms", "submit-enter", {
28630
+ mode: formMode,
28631
+ submitEvent,
28632
+ formData,
28633
+ normalizedInitialData
28634
+ });
28496
28635
  const mergedData = {
28497
28636
  ...normalizedInitialData,
28498
28637
  ...formData
28499
28638
  };
28500
28639
  const payload = { data: mergedData };
28640
+ debug("forms", "submit-emit", { mode: formMode, submitEvent: `UI:${submitEvent}`, payloadData: payload.data });
28501
28641
  eventBus.emit(`UI:${submitEvent}`, payload);
28502
28642
  if (onSubmit) {
28503
28643
  eventBus.emit(`UI:${onSubmit}`, payload);
@@ -37728,6 +37868,14 @@ function SlotContentRenderer({
37728
37868
  patternPath
37729
37869
  }) {
37730
37870
  const entityProp = content.props.entity;
37871
+ if (content.pattern === "form-section") {
37872
+ slotLog.debug("SlotContentRenderer:form-section-render", {
37873
+ contentId: content.id,
37874
+ sourceTrait: content.sourceTrait,
37875
+ entityRefId: refId(entityProp),
37876
+ entityIsObject: entityProp !== null && typeof entityProp === "object" && !Array.isArray(entityProp)
37877
+ });
37878
+ }
37731
37879
  if (typeof entityProp === "string" && entityProp.length > 0) {
37732
37880
  if (typeof process !== "undefined" && process.env && process.env.NODE_ENV !== "production") {
37733
37881
  throw new Error(
@@ -37871,6 +38019,7 @@ var init_UISlotRenderer = __esm({
37871
38019
  init_Box();
37872
38020
  init_Typography();
37873
38021
  init_useEventBus();
38022
+ init_SlotsContext();
37874
38023
  init_cn();
37875
38024
  init_ErrorBoundary();
37876
38025
  init_Skeleton();
@@ -38031,7 +38180,13 @@ function useTraitStateMachine(traitBindings, slotsActions, options) {
38031
38180
  const { entities } = useEntitySchema();
38032
38181
  const manager = React115.useMemo(() => {
38033
38182
  const traitDefs = traitBindings.map(toTraitDefinition);
38034
- return new runtime.StateMachineManager(traitDefs);
38183
+ const m = new runtime.StateMachineManager(traitDefs);
38184
+ for (const binding of traitBindings) {
38185
+ if (binding.config !== void 0) {
38186
+ m.setTraitConfig(binding.trait.name, binding.config);
38187
+ }
38188
+ }
38189
+ return m;
38035
38190
  }, [traitBindings]);
38036
38191
  const [traitStates, setTraitStates] = React115.useState(() => {
38037
38192
  return manager.getAllStates();
@@ -38677,90 +38832,16 @@ function useTrait(traitName) {
38677
38832
  const context = useTraitContext();
38678
38833
  return context.getTrait(traitName);
38679
38834
  }
38680
- var DEFAULT_SOURCE_KEY = "__default__";
38681
- function slotEntriesInOrder(slot) {
38682
- if (!slot) return [];
38683
- const out = [];
38684
- for (const [sourceKey, entry] of Object.entries(slot)) {
38685
- if (entry.patterns.length > 0) {
38686
- out.push({ sourceKey, entry });
38687
- }
38688
- }
38689
- return out;
38690
- }
38691
- var SlotsStateContext = React115.createContext({});
38692
- var SlotsActionsContext = React115.createContext(null);
38693
- function SlotsProvider({ children }) {
38694
- const [slots, setSlots] = React115.useState({});
38695
- const setSlotPatterns = React115.useCallback((slot, patterns, source) => {
38696
- const sourceKey = source?.trait ?? DEFAULT_SOURCE_KEY;
38697
- setSlots((prev) => {
38698
- const prevSlot = prev[slot] ?? {};
38699
- return {
38700
- ...prev,
38701
- [slot]: {
38702
- ...prevSlot,
38703
- [sourceKey]: { patterns, source }
38704
- }
38705
- };
38706
- });
38707
- }, []);
38708
- const clearSlot = React115.useCallback((slot) => {
38709
- setSlots((prev) => {
38710
- const existing = prev[slot];
38711
- if (existing && Object.keys(existing).length === 0) {
38712
- return prev;
38713
- }
38714
- return { ...prev, [slot]: {} };
38715
- });
38716
- }, []);
38717
- const clearSlotForSource = React115.useCallback((slot, sourceTrait) => {
38718
- setSlots((prev) => {
38719
- const existing = prev[slot];
38720
- if (!existing || !(sourceTrait in existing)) return prev;
38721
- const next = { ...existing };
38722
- delete next[sourceTrait];
38723
- return { ...prev, [slot]: next };
38724
- });
38725
- }, []);
38726
- const clearAllSlots = React115.useCallback(() => {
38727
- setSlots({});
38728
- }, []);
38729
- const actionsRef = React115.useRef({
38730
- setSlotPatterns,
38731
- clearSlot,
38732
- clearSlotForSource,
38733
- clearAllSlots
38734
- });
38735
- actionsRef.current = { setSlotPatterns, clearSlot, clearSlotForSource, clearAllSlots };
38736
- const [stableActions] = React115.useState(() => ({
38737
- setSlotPatterns: (...args) => actionsRef.current.setSlotPatterns(...args),
38738
- clearSlot: (...args) => actionsRef.current.clearSlot(...args),
38739
- clearSlotForSource: (...args) => actionsRef.current.clearSlotForSource(...args),
38740
- clearAllSlots: () => actionsRef.current.clearAllSlots()
38741
- }));
38742
- return /* @__PURE__ */ jsxRuntime.jsx(SlotsActionsContext.Provider, { value: stableActions, children: /* @__PURE__ */ jsxRuntime.jsx(SlotsStateContext.Provider, { value: slots, children }) });
38743
- }
38744
- function useSlots() {
38745
- return React115.useContext(SlotsStateContext);
38746
- }
38747
- function useSlotContent(slotName) {
38748
- const slots = React115.useContext(SlotsStateContext);
38749
- return slots[slotName] || null;
38750
- }
38751
- function useSlotsActions() {
38752
- const actions = React115.useContext(SlotsActionsContext);
38753
- if (!actions) {
38754
- throw new Error("useSlotsActions must be used within a SlotsProvider");
38755
- }
38756
- return actions;
38757
- }
38835
+
38836
+ // runtime/index.ts
38837
+ init_SlotsContext();
38758
38838
 
38759
38839
  // runtime/OrbPreview.tsx
38760
38840
  init_Box();
38761
38841
  init_Typography();
38762
38842
  init_UISlotRenderer();
38763
38843
  init_useEventBus();
38844
+ init_SlotsContext();
38764
38845
  init_EntitySchemaContext();
38765
38846
 
38766
38847
  // runtime/ServerBridge.tsx
@@ -38980,6 +39061,10 @@ function SlotBridge() {
38980
39061
  const slots = useSlots();
38981
39062
  const { render, clear } = context.useUISlots();
38982
39063
  React115.useEffect(() => {
39064
+ slotLog.debug("SlotBridge:effect-fired", {
39065
+ slotCount: Object.keys(slots).length,
39066
+ slots: Object.keys(slots)
39067
+ });
38983
39068
  for (const [slotName, slotState] of Object.entries(slots)) {
38984
39069
  const entries = slotEntriesInOrder(slotState);
38985
39070
  if (entries.length === 0) {
@@ -39001,6 +39086,12 @@ function SlotBridge() {
39001
39086
  const only = children[0];
39002
39087
  const { type, children: nested, ...rest } = only;
39003
39088
  const lastEntry = entries[entries.length - 1];
39089
+ slotLog.debug("SlotBridge:render-single", {
39090
+ slot: slotName,
39091
+ patternType: type,
39092
+ entityRefId: refId(rest.entity),
39093
+ sourceTrait: lastEntry.entry.source?.trait
39094
+ });
39004
39095
  render({
39005
39096
  target: slotName,
39006
39097
  pattern: type,