@jsswift/ui 1.0.48 → 1.0.50

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.
package/dist/ui.js CHANGED
@@ -2228,6 +2228,7 @@ const unitCover = (v, name = 'size') => {
2228
2228
  // props: { model: rod OR [get,set] signal OR plain, placeholder, type }
2229
2229
 
2230
2230
 
2231
+ let uiFieldMessageId = 0;
2231
2232
  UI.FormField = (props = {}) => {
2232
2233
 
2233
2234
  applyCommonProps(props);
@@ -2360,6 +2361,14 @@ const unitCover = (v, name = 'size') => {
2360
2361
  return true;
2361
2362
  };
2362
2363
  let messageEl = null;
2364
+ const messageId = `jsswift-field-message-${++uiFieldMessageId}`;
2365
+ const syncDescription = () => {
2366
+ if (!controlEl?.setAttribute) return;
2367
+ const ids = [uiUnwrap(props.ariaDescribedBy), messageEl?.id].filter(Boolean).join(" ").trim();
2368
+ if (ids) controlEl.setAttribute("aria-describedby", [...new Set(ids.split(/\s+/))].join(" "));
2369
+ else controlEl.removeAttribute("aria-describedby");
2370
+ };
2371
+ wrap._syncDescription = syncDescription;
2363
2372
  const renderMessage = () => {
2364
2373
  const statusOrder = [
2365
2374
  { key: "error", value: resolveValue(props.error), slot: "errorMessage", className: "cms-error" },
@@ -2387,7 +2396,7 @@ const unitCover = (v, name = 'size') => {
2387
2396
  ? renderSlotToArray(slots, active.slot, ctx, active.value)
2388
2397
  : [];
2389
2398
  const nextEl = nodes.length
2390
- ? _.div({ class: active?.className }, ...nodes)
2399
+ ? _.div({ id: messageId, class: active?.className }, ...nodes)
2391
2400
  : null;
2392
2401
 
2393
2402
  const stateKeys = ["error", "warning", "success", "note"];
@@ -2400,6 +2409,7 @@ const unitCover = (v, name = 'size') => {
2400
2409
  wrap.appendChild(nextEl);
2401
2410
  }
2402
2411
  messageEl = nextEl;
2412
+ syncDescription();
2403
2413
  };
2404
2414
 
2405
2415
  // state updater
@@ -2541,6 +2551,30 @@ const unitCover = (v, name = 'size') => {
2541
2551
  return el;
2542
2552
  };
2543
2553
 
2554
+ // Public field attributes belong to the interactive control, not its wrapper.
2555
+ function uiConfigureFieldControl(field, control, props, native = false) {
2556
+ field.focus = (options) => control.focus(options);
2557
+ const set = (name, value) => {
2558
+ if (value == null || value === false) control.removeAttribute(name);
2559
+ else control.setAttribute(name, String(value));
2560
+ };
2561
+ JSswift.reactive.effect(() => {
2562
+ const label = uiUnwrap(props.ariaLabel) ?? (typeof props.label === "string" ? props.label : null);
2563
+ set("aria-label", label);
2564
+ set("aria-labelledby", uiUnwrap(props.ariaLabelledBy));
2565
+ field._syncDescription?.();
2566
+ const invalid = props.ariaInvalid == null ? !!uiUnwrap(props.error) : !!uiUnwrap(props.ariaInvalid);
2567
+ control.setAttribute("aria-invalid", String(invalid));
2568
+ const required = !!uiUnwrap(props.required);
2569
+ control.setAttribute("aria-required", String(required));
2570
+ if (native) {
2571
+ control.required = required;
2572
+ for (const name of ["min", "max", "step", "pattern", "minLength", "maxLength"])
2573
+ set(name.toLowerCase(), uiUnwrap(props[name]));
2574
+ }
2575
+ }, "UI.Field:controlAttributes");
2576
+ }
2577
+
2544
2578
  UI.Input = (props = {}) => {
2545
2579
  const slots = props.slots || {};
2546
2580
  const fieldProps = {
@@ -2702,6 +2736,7 @@ const unitCover = (v, name = 'size') => {
2702
2736
 
2703
2737
  // expose reference
2704
2738
  field._input = input;
2739
+ uiConfigureFieldControl(field, input, props, true);
2705
2740
  uiRegisterShortcode(input, props, {
2706
2741
  isEnabled: () => !input.disabled,
2707
2742
  action: () => uiFocusShortcutTarget(input, { selectText: !!props.selectOnShortcode })
@@ -4099,6 +4134,7 @@ const unitCover = (v, name = 'size') => {
4099
4134
  // refresh has-value when value changes
4100
4135
  JSswift.reactive.effect(() => { field._refresh?.(); }, "UI.Select:fieldRefresh");
4101
4136
 
4137
+ uiConfigureFieldControl(field, root, props);
4102
4138
  field._select = root;
4103
4139
  field._dispose = root._dispose;
4104
4140
  JSswift._registerCleanup?.(field, field._dispose);