najm-kit 2.11.6 → 2.11.7

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/CHANGELOG.md CHANGED
@@ -1,14 +1,31 @@
1
- # Changelog
2
-
3
- ## 2.11.6 - 2026-08-15
4
-
5
- - Fixed `FormInput` dropping React Hook Form's native field binding for text,
6
- number, password, textarea, and time controls. These controls now forward
7
- their field name, composed blur handler, and focus ref to the actual native
8
- element, preserving browser form semantics, touched-state tracking, and
9
- programmatic focus without changing composite-control contracts.
10
-
11
- ## 2.11.5 - 2026-08-14
1
+ # Changelog
2
+
3
+ ## 2.11.7 - 2026-08-17
4
+
5
+ - Fixed date, combobox, and multiselect `FormInput` controls reaching the
6
+ accessibility tree with no accessible name. These types render their trigger
7
+ as a styled `div`, so the `<label for>` that `FormControl` wires up pointed at
8
+ a non-labelable element and named nothing: screen readers announced an unnamed
9
+ control, and `getByRole(..., { name })` could not resolve one. The form label
10
+ now becomes the trigger's `aria-label`, and `DateInput` and `ComboboxInput`
11
+ accept an explicit `ariaLabel` to override it. `select` keeps naming itself
12
+ from `ariaLabel || placeholder`; renaming it would break consumers that select
13
+ it by placeholder today.
14
+ - Fixed `DateInput` rendering its popover trigger as a `div`. Radix only merges
15
+ trigger props onto the child, so the control had no role, no tab stop, and no
16
+ keyboard activation — it was unreachable without a mouse. It is now a real
17
+ `<button type="button">`, which also keeps it from submitting the surrounding
18
+ form when the calendar opens.
19
+
20
+ ## 2.11.6 - 2026-08-15
21
+
22
+ - Fixed `FormInput` dropping React Hook Form's native field binding for text,
23
+ number, password, textarea, and time controls. These controls now forward
24
+ their field name, composed blur handler, and focus ref to the actual native
25
+ element, preserving browser form semantics, touched-state tracking, and
26
+ programmatic focus without changing composite-control contracts.
27
+
28
+ ## 2.11.5 - 2026-08-14
12
29
 
13
30
  - Fixed numbered lists staying on an invalid final page after a deletion or
14
31
  another mutation reduced the server total. Paged lists now clamp before
package/dist/index.d.ts CHANGED
@@ -2238,6 +2238,7 @@ interface ComboboxInputProps extends BaseProps {
2238
2238
  showIcon?: boolean;
2239
2239
  disabled?: boolean;
2240
2240
  allowFreeText?: boolean;
2241
+ ariaLabel?: string;
2241
2242
  }
2242
2243
  interface MultiSelectInputProps extends BaseProps {
2243
2244
  value: string[];
@@ -2294,6 +2295,7 @@ interface DateInputProps extends BaseProps {
2294
2295
  placeholder?: string;
2295
2296
  icon?: InputIcon;
2296
2297
  showIcon?: boolean;
2298
+ ariaLabel?: string;
2297
2299
  }
2298
2300
  interface StarRatingInputProps extends BaseProps {
2299
2301
  value: number;
package/dist/index.mjs CHANGED
@@ -4551,7 +4551,7 @@ var TextAreaInput = React66__default.forwardRef(({ value, onChange, placeholder
4551
4551
  );
4552
4552
  });
4553
4553
  TextAreaInput.displayName = "TextAreaInput";
4554
- var ComboboxInput = ({ placeholder = "Select...", searchPlaceholder = "Search...", emptyMessage = "No results found.", loading = false, loadingMessage = "Loading...", onSearchChange, shouldFilter = true, value, onChange, icon, showIcon = true, iconColor, items = [], className = "", variant = "default", status = "default", bordered, borderColor, disabled = false, allowFreeText = false }) => {
4554
+ var ComboboxInput = ({ placeholder = "Select...", searchPlaceholder = "Search...", emptyMessage = "No results found.", loading = false, loadingMessage = "Loading...", onSearchChange, shouldFilter = true, value, onChange, icon, showIcon = true, iconColor, items = [], className = "", variant = "default", status = "default", bordered, borderColor, disabled = false, allowFreeText = false, ariaLabel }) => {
4555
4555
  const [open, setOpen] = useState(false);
4556
4556
  const triggerRef = React66__default.useRef(null);
4557
4557
  const pointerDismissedRef = React66__default.useRef(false);
@@ -4590,6 +4590,7 @@ var ComboboxInput = ({ placeholder = "Select...", searchPlaceholder = "Search...
4590
4590
  bordered,
4591
4591
  borderColor,
4592
4592
  role: "combobox",
4593
+ "aria-label": ariaLabel,
4593
4594
  tabIndex: disabled ? -1 : 0,
4594
4595
  "aria-expanded": open,
4595
4596
  className: cn(
@@ -4782,13 +4783,13 @@ function Calendar(props) {
4782
4783
  }
4783
4784
  );
4784
4785
  }
4785
- var DateInput = ({ value, onChange, placeholder = "Pick a date", className = "", icon, showIcon = true, iconColor, variant = "default", status = "default", bordered, borderColor }) => {
4786
+ var DateInput = ({ value, onChange, placeholder = "Pick a date", className = "", icon, showIcon = true, iconColor, variant = "default", status = "default", bordered, borderColor, ariaLabel }) => {
4786
4787
  const iconProps = getIconColorProps(iconColor, "h-4 w-4");
4787
4788
  const toDateString = (date) => date ? format(date, "yyyy-MM-dd") : void 0;
4788
4789
  const toDate = (val) => typeof val === "string" ? parseISO(val) : val;
4789
4790
  return /* @__PURE__ */ jsxs(BaseInput, { variant, status, bordered, borderColor, className, children: [
4790
4791
  /* @__PURE__ */ jsxs(Popover, { children: [
4791
- /* @__PURE__ */ jsx(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsx("div", { className: "w-full flex items-center cursor-pointer gap-2 justify-start text-left font-normal", children: /* @__PURE__ */ jsx(Label2, { className: cn("cursor-pointer", value ? "text-foreground" : "text-muted-foreground"), children: value ? format(toDate(value), "PPP") : placeholder }) }) }),
4792
+ /* @__PURE__ */ jsx(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsx("button", { type: "button", "aria-label": ariaLabel, className: "w-full flex items-center cursor-pointer gap-2 justify-start text-left font-normal bg-transparent border-0 p-0 outline-none", children: /* @__PURE__ */ jsx("span", { className: cn("cursor-pointer", value ? "text-foreground" : "text-muted-foreground"), children: value ? format(toDate(value), "PPP") : placeholder }) }) }),
4792
4793
  /* @__PURE__ */ jsx(PopoverContent, { className: "w-auto p-0", align: "start", children: /* @__PURE__ */ jsx(Calendar, { mode: "single", selected: toDate(value), onSelect: (date) => onChange(toDateString(date)), captionLayout: "dropdown" }) })
4793
4794
  ] }),
4794
4795
  !icon && showIcon && /* @__PURE__ */ jsx(Calendar$1, { className: iconProps.className, style: iconProps.style })
@@ -10879,6 +10880,7 @@ var Inputs = {
10879
10880
  slider: SliderInput
10880
10881
  };
10881
10882
  var nativeFieldTypes = /* @__PURE__ */ new Set(["text", "number", "password", "textarea", "time"]);
10883
+ var labelNamedCompositeTypes = /* @__PURE__ */ new Set(["date", "combobox", "multiselect"]);
10882
10884
  var FormInput = ({ name, type, formLabel, formDescription, required = false, disabled = false, readOnly = false, hidden = false, icon, iconColor, classNames, background, ...rest }) => {
10883
10885
  const InputComponent = Inputs[type];
10884
10886
  const { control } = useFormContext();
@@ -10897,6 +10899,7 @@ var FormInput = ({ name, type, formLabel, formDescription, required = false, dis
10897
10899
  };
10898
10900
  const presetInput = type === "textarea" ? preset.input?.replace(/\bh-\d+\b/g, "").trim() : preset.input;
10899
10901
  const isFillAvatar = type === "avatar" && inputRest.fill === true;
10902
+ const compositeAriaLabel = labelNamedCompositeTypes.has(type) && typeof formLabel === "string" ? { ariaLabel: inputRest.ariaLabel ?? formLabel } : {};
10900
10903
  const slot = {
10901
10904
  item: cn(
10902
10905
  preset.item,
@@ -10929,7 +10932,7 @@ var FormInput = ({ name, type, formLabel, formDescription, required = false, dis
10929
10932
  formLabel,
10930
10933
  required && !disabled && !readOnly && /* @__PURE__ */ jsx("span", { className: "text-destructive ml-1", children: "*" })
10931
10934
  ] }),
10932
- /* @__PURE__ */ jsx(FormControl, { children: /* @__PURE__ */ jsx(InputComponent, { value: field.value ?? getDefaultValue(), onChange: handleChange, status: hasError && !isHidden ? "error" : "default", bordered: contextBordered, icon: formLabel ? void 0 : icon, iconColor: formLabel ? void 0 : iconColor, disabled, readOnly, ...inputRest, ...nativeFieldBinding, className: slot.input }) }),
10935
+ /* @__PURE__ */ jsx(FormControl, { children: /* @__PURE__ */ jsx(InputComponent, { value: field.value ?? getDefaultValue(), onChange: handleChange, status: hasError && !isHidden ? "error" : "default", bordered: contextBordered, icon: formLabel ? void 0 : icon, iconColor: formLabel ? void 0 : iconColor, disabled, readOnly, ...inputRest, ...compositeAriaLabel, ...nativeFieldBinding, className: slot.input }) }),
10933
10936
  !hasError && !disabled && !readOnly && formDescription && /* @__PURE__ */ jsx(FormDescription, { className: slot.description, children: formDescription }),
10934
10937
  !isHidden && /* @__PURE__ */ jsx(FormMessage, { className: slot.error })
10935
10938
  ] });
package/dist/theme.css CHANGED
@@ -307,10 +307,10 @@ input:autofill {
307
307
  overflow-x: auto;
308
308
  scrollbar-width: none;
309
309
  }
310
- .najm-overlay-scroll-x::-webkit-scrollbar {
311
- display: none;
312
- }
313
-
310
+ .najm-overlay-scroll-x::-webkit-scrollbar {
311
+ display: none;
312
+ }
313
+
314
314
  /* Responsive table actions stay discoverable on touch and tablet layouts.
315
315
  Fine-pointer desktops may keep the quieter hover/focus reveal treatment. */
316
316
  .ntable-card-action {
@@ -367,7 +367,7 @@ input:autofill {
367
367
  .nimage-input-compact-overlay:focus-visible {
368
368
  opacity: 1;
369
369
  }
370
- }
370
+ }
371
371
 
372
372
  /* OverlayScrollbars theme used by the <NajmScroll> component — a thin,
373
373
  translucent slate bar that floats over content with no reserved space.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "najm-kit",
3
- "version": "2.11.6",
3
+ "version": "2.11.7",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "description": "Reusable React UI component package for Najm framework",