@almadar/ui 4.28.0 → 4.29.1

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.
@@ -25613,6 +25613,8 @@ var init_Form = __esm({
25613
25613
  const [collapsedSections, setCollapsedSections] = React104__default.useState(
25614
25614
  /* @__PURE__ */ new Set()
25615
25615
  );
25616
+ const [submitError, setSubmitError] = React104__default.useState(null);
25617
+ const formRef = React104__default.useRef(null);
25616
25618
  const formMode = props.mode;
25617
25619
  const mountedRef = React104__default.useRef(false);
25618
25620
  if (!mountedRef.current) {
@@ -25738,6 +25740,7 @@ var init_Form = __esm({
25738
25740
  };
25739
25741
  const handleSubmit = (e) => {
25740
25742
  e.preventDefault();
25743
+ setSubmitError(null);
25741
25744
  debug("forms", "submit-enter", {
25742
25745
  mode: formMode,
25743
25746
  submitEvent,
@@ -25755,6 +25758,37 @@ var init_Form = __esm({
25755
25758
  eventBus.emit(`UI:${onSubmit}`, payload);
25756
25759
  }
25757
25760
  };
25761
+ const handleInvalid = (e) => {
25762
+ const target = e.target;
25763
+ const fieldName = target.getAttribute("data-field-name") ?? target.name ?? "";
25764
+ const fieldMessage = target.validationMessage || "Invalid value";
25765
+ debug("forms", "invalid", { mode: formMode, fieldName, fieldMessage });
25766
+ queueMicrotask(() => {
25767
+ const form = formRef.current;
25768
+ if (!form) return;
25769
+ const invalidEls = Array.from(
25770
+ form.querySelectorAll(
25771
+ ":invalid"
25772
+ )
25773
+ );
25774
+ if (invalidEls.length === 0) return;
25775
+ const missing = invalidEls.map(
25776
+ (el) => el.getAttribute("data-field-name") ?? el.name ?? ""
25777
+ );
25778
+ const messages = invalidEls.map((el) => ({
25779
+ field: el.getAttribute("data-field-name") ?? el.name ?? "",
25780
+ message: el.validationMessage
25781
+ }));
25782
+ const summary = missing.length === 1 ? `${missing[0]}: ${messages[0]?.message}` : `Please fix ${missing.length} fields: ${missing.join(", ")}`;
25783
+ setSubmitError(summary);
25784
+ eventBus.emit("UI:VALIDATION_FAILED", {
25785
+ submitEvent,
25786
+ missing,
25787
+ messages,
25788
+ summary
25789
+ });
25790
+ });
25791
+ };
25758
25792
  const handleCancel = () => {
25759
25793
  eventBus.emit(`UI:${cancelEvent}`);
25760
25794
  eventBus.emit("UI:CLOSE");
@@ -25858,7 +25892,8 @@ var init_Form = __esm({
25858
25892
  "data-field-name": fieldName,
25859
25893
  required: field.required,
25860
25894
  disabled: isLoading,
25861
- placeholder: field.placeholder
25895
+ placeholder: field.placeholder,
25896
+ pattern: field.pattern
25862
25897
  };
25863
25898
  switch (inputType) {
25864
25899
  case "checkbox":
@@ -25954,7 +25989,9 @@ var init_Form = __esm({
25954
25989
  ...commonProps,
25955
25990
  type: "email",
25956
25991
  value: String(currentValue),
25957
- onChange: (e) => handleChange(fieldName, e.target.value)
25992
+ onChange: (e) => handleChange(fieldName, e.target.value),
25993
+ minLength: field.min,
25994
+ maxLength: field.max
25958
25995
  }
25959
25996
  );
25960
25997
  case "url":
@@ -25964,7 +26001,9 @@ var init_Form = __esm({
25964
26001
  ...commonProps,
25965
26002
  type: "url",
25966
26003
  value: String(currentValue),
25967
- onChange: (e) => handleChange(fieldName, e.target.value)
26004
+ onChange: (e) => handleChange(fieldName, e.target.value),
26005
+ minLength: field.min,
26006
+ maxLength: field.max
25968
26007
  }
25969
26008
  );
25970
26009
  case "password":
@@ -25974,7 +26013,9 @@ var init_Form = __esm({
25974
26013
  ...commonProps,
25975
26014
  type: "password",
25976
26015
  value: String(currentValue),
25977
- onChange: (e) => handleChange(fieldName, e.target.value)
26016
+ onChange: (e) => handleChange(fieldName, e.target.value),
26017
+ minLength: field.min,
26018
+ maxLength: field.max
25978
26019
  }
25979
26020
  );
25980
26021
  case "text":
@@ -25987,8 +26028,7 @@ var init_Form = __esm({
25987
26028
  value: String(currentValue),
25988
26029
  onChange: (e) => handleChange(fieldName, e.target.value),
25989
26030
  minLength: field.min,
25990
- maxLength: field.max,
25991
- pattern: field.pattern
26031
+ maxLength: field.max
25992
26032
  }
25993
26033
  );
25994
26034
  }
@@ -25996,12 +26036,14 @@ var init_Form = __esm({
25996
26036
  return /* @__PURE__ */ jsxs(
25997
26037
  "form",
25998
26038
  {
25999
- noValidate: true,
26039
+ ref: formRef,
26000
26040
  "data-pattern": "form-section",
26001
26041
  className: cn(layoutStyles[layout], gapStyles8[gap], className),
26002
26042
  onSubmit: handleSubmit,
26043
+ onInvalid: handleInvalid,
26003
26044
  ...props,
26004
26045
  children: [
26046
+ submitError && /* @__PURE__ */ jsx(Alert, { variant: "error", className: "mb-4", children: submitError }),
26005
26047
  error && /* @__PURE__ */ jsx(Alert, { variant: "error", className: "mb-4", children: error.message || t("error.occurred") }),
26006
26048
  sectionElements && sectionElements.length > 0 && /* @__PURE__ */ jsx(VStack, { gap: gap === "sm" ? "sm" : gap === "lg" ? "lg" : "md", children: sectionElements }),
26007
26049
  schemaFields,
@@ -36061,6 +36103,7 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
36061
36103
  }
36062
36104
  console.log("[TraitStateMachine] Subscribing to events:", Array.from(allEvents));
36063
36105
  const unsubscribes = [];
36106
+ const subscribedBusKeys = /* @__PURE__ */ new Set();
36064
36107
  for (const binding of traitBindings) {
36065
36108
  const traitName = binding.trait.name;
36066
36109
  const orbitalName = orbitalsByTrait?.[traitName];
@@ -36071,6 +36114,8 @@ function useTraitStateMachine(traitBindings, uiSlots, options) {
36071
36114
  continue;
36072
36115
  }
36073
36116
  const selfBusKey = `UI:${orbitalName}.${traitName}.${eventKey}`;
36117
+ if (subscribedBusKeys.has(selfBusKey)) continue;
36118
+ subscribedBusKeys.add(selfBusKey);
36074
36119
  crossTraitLog.debug("self:subscribe", { traitName, busKey: selfBusKey, eventKey });
36075
36120
  const unsub = eventBus.on(selfBusKey, (event) => {
36076
36121
  if (event.source && event.source.dispatched) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@almadar/ui",
3
- "version": "4.28.0",
3
+ "version": "4.29.1",
4
4
  "description": "React UI components, hooks, and providers for Almadar",
5
5
  "type": "module",
6
6
  "sideEffects": [