najm-kit 2.11.14 → 2.11.15

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,5 +1,12 @@
1
1
  # Changelog
2
2
 
3
+ ## 2.11.15 - 2026-09-04
4
+
5
+ - Fixed `ComboboxInput` keyboard interaction. Enter and Space now open its
6
+ focusable trigger, and Enter commits the active filtered result instead of
7
+ doing nothing when the previously active CmdK item was filtered out. Disabled
8
+ comboboxes remain non-activatable.
9
+
3
10
  ## 2.11.14 - 2026-09-04
4
11
 
5
12
  - Added `defineNajmPreferences` to `najm-kit/server`: the language, theme, and
package/dist/index.mjs CHANGED
@@ -29,7 +29,7 @@ import { HexColorPicker } from 'react-colorful';
29
29
  import * as PopoverPrimitive from '@radix-ui/react-popover';
30
30
  import { converter, parse, formatHsl, formatRgb, formatHex } from 'culori';
31
31
  import * as CollapsiblePrimitive from '@radix-ui/react-collapsible';
32
- import { Command as Command$1 } from 'cmdk';
32
+ import { Command as Command$1, defaultFilter } from 'cmdk';
33
33
  import * as SheetPrimitive from '@radix-ui/react-dialog';
34
34
  import { create } from 'zustand';
35
35
  import * as CheckboxPrimitive from '@radix-ui/react-checkbox';
@@ -4564,21 +4564,39 @@ var ComboboxInput = ({ placeholder = "Select...", searchPlaceholder = "Search...
4564
4564
  const displayLabel = selectedItem?.label ?? (allowFreeText && value ? value : "");
4565
4565
  const shouldDisplayIcon = Boolean(icon) && showIcon && !value;
4566
4566
  const iconProps = getIconColorProps(iconColor, "h-4 w-4");
4567
+ const [activeItem, setActiveItem] = useState(selectedItem?.label ?? normalizedItems[0]?.label ?? "");
4567
4568
  const trimmedQuery = query.trim();
4568
4569
  const queryMatchesItem = trimmedQuery !== "" && normalizedItems.some((i) => i.value === trimmedQuery || i.label.toLowerCase() === trimmedQuery.toLowerCase());
4569
4570
  const showFreeTextOption = allowFreeText && trimmedQuery !== "" && !queryMatchesItem;
4571
+ const rankItems = (search) => normalizedItems.map((item, index) => ({
4572
+ index,
4573
+ item,
4574
+ score: shouldFilter ? defaultFilter(item.label, search.trim(), [item.value, item.label]) : 1
4575
+ })).filter(({ score }) => score > 0).sort((left, right) => right.score - left.score || left.index - right.index);
4570
4576
  const commit = (next) => {
4571
4577
  onChange(next);
4578
+ setActiveItem(normalizedItems.find((item) => item.value === next)?.label ?? "");
4572
4579
  setOpen(false);
4573
4580
  setQuery("");
4574
4581
  onSearchChange?.("");
4575
4582
  };
4576
4583
  const updateQuery = (next) => {
4584
+ setActiveItem(rankItems(next)[0]?.item.label ?? "");
4577
4585
  setQuery(next);
4578
4586
  onSearchChange?.(next);
4579
4587
  };
4588
+ const updateActiveItem = (next) => {
4589
+ const nextItem = normalizedItems.find((item) => item.label === next);
4590
+ if (trimmedQuery !== "" && shouldFilter && (!nextItem || defaultFilter(nextItem.label, trimmedQuery, [nextItem.value, nextItem.label]) <= 0)) {
4591
+ return;
4592
+ }
4593
+ setActiveItem(next);
4594
+ };
4580
4595
  return /* @__PURE__ */ jsxs(Popover, { open, onOpenChange: (o) => {
4581
4596
  setOpen(o);
4597
+ if (o) {
4598
+ setActiveItem(selectedItem?.label ?? normalizedItems[0]?.label ?? "");
4599
+ }
4582
4600
  if (!o) {
4583
4601
  setQuery("");
4584
4602
  onSearchChange?.("");
@@ -4596,6 +4614,11 @@ var ComboboxInput = ({ placeholder = "Select...", searchPlaceholder = "Search...
4596
4614
  "aria-label": ariaLabel,
4597
4615
  tabIndex: disabled ? -1 : 0,
4598
4616
  "aria-expanded": open,
4617
+ onKeyDown: (event) => {
4618
+ if (disabled || event.key !== "Enter" && event.key !== " ") return;
4619
+ event.preventDefault();
4620
+ setOpen(true);
4621
+ },
4599
4622
  className: cn(
4600
4623
  "cursor-pointer outline-none data-[state=open]:border-ring",
4601
4624
  className
@@ -4621,38 +4644,69 @@ var ComboboxInput = ({ placeholder = "Select...", searchPlaceholder = "Search...
4621
4644
  pointerDismissedRef.current = false;
4622
4645
  triggerRef.current?.blur();
4623
4646
  },
4624
- children: /* @__PURE__ */ jsxs(Command, { shouldFilter, children: [
4625
- /* @__PURE__ */ jsx(
4626
- CommandInput,
4627
- {
4628
- placeholder: searchPlaceholder,
4629
- className: "h-9",
4630
- value: query,
4631
- onValueChange: updateQuery,
4632
- onKeyDown: (e) => {
4633
- if (e.key === "Enter" && showFreeTextOption) {
4634
- e.preventDefault();
4635
- commit(trimmedQuery);
4647
+ children: /* @__PURE__ */ jsxs(
4648
+ Command,
4649
+ {
4650
+ shouldFilter,
4651
+ value: activeItem,
4652
+ onValueChange: updateActiveItem,
4653
+ children: [
4654
+ /* @__PURE__ */ jsx(
4655
+ CommandInput,
4656
+ {
4657
+ placeholder: searchPlaceholder,
4658
+ className: "h-9",
4659
+ value: query,
4660
+ onValueChange: updateQuery,
4661
+ onKeyDown: (e) => {
4662
+ const rankedItems = rankItems(trimmedQuery);
4663
+ if (trimmedQuery !== "" && rankedItems.length > 0 && ["ArrowDown", "ArrowUp", "Home", "End"].includes(e.key)) {
4664
+ e.preventDefault();
4665
+ e.stopPropagation();
4666
+ const currentIndex = rankedItems.findIndex(({ item }) => item.label === activeItem);
4667
+ const nextIndex = e.key === "Home" ? 0 : e.key === "End" ? rankedItems.length - 1 : e.key === "ArrowDown" ? Math.min(currentIndex + 1, rankedItems.length - 1) : Math.max(currentIndex < 0 ? 0 : currentIndex - 1, 0);
4668
+ setActiveItem(rankedItems[nextIndex]?.item.label ?? "");
4669
+ return;
4670
+ }
4671
+ if (e.key !== "Enter") return;
4672
+ if (showFreeTextOption) {
4673
+ e.preventDefault();
4674
+ commit(trimmedQuery);
4675
+ return;
4676
+ }
4677
+ if (trimmedQuery !== "") {
4678
+ const activeMatch = normalizedItems.find((item) => item.label === activeItem);
4679
+ const nextItem = activeMatch && defaultFilter(
4680
+ activeMatch.label,
4681
+ trimmedQuery,
4682
+ [activeMatch.value, activeMatch.label]
4683
+ ) > 0 ? activeMatch : rankedItems[0]?.item;
4684
+ if (nextItem) {
4685
+ e.preventDefault();
4686
+ commit(nextItem.value);
4687
+ }
4688
+ }
4689
+ }
4636
4690
  }
4637
- }
4638
- }
4639
- ),
4640
- /* @__PURE__ */ jsxs(CommandList, { children: [
4641
- /* @__PURE__ */ jsx(CommandEmpty, { children: loading ? loadingMessage : emptyMessage }),
4642
- /* @__PURE__ */ jsxs(CommandGroup, { children: [
4643
- showFreeTextOption && /* @__PURE__ */ jsxs(CommandItem, { value: trimmedQuery, onSelect: () => commit(trimmedQuery), className: "cursor-pointer", children: [
4644
- /* @__PURE__ */ jsx(Check, { className: "mr-2 h-4 w-4 opacity-0" }),
4645
- 'Use "',
4646
- trimmedQuery,
4647
- '"'
4648
- ] }, "__free_text__"),
4649
- normalizedItems.map((item) => /* @__PURE__ */ jsxs(CommandItem, { value: item.label, keywords: [item.value, item.label], onSelect: () => commit(value === item.value ? "" : item.value), className: "cursor-pointer", children: [
4650
- /* @__PURE__ */ jsx(Check, { className: cn("mr-2 h-4 w-4", value === item.value ? "opacity-100" : "opacity-0") }),
4651
- item.label
4652
- ] }, item.value))
4653
- ] })
4654
- ] })
4655
- ] })
4691
+ ),
4692
+ /* @__PURE__ */ jsxs(CommandList, { children: [
4693
+ /* @__PURE__ */ jsx(CommandEmpty, { children: loading ? loadingMessage : emptyMessage }),
4694
+ /* @__PURE__ */ jsxs(CommandGroup, { children: [
4695
+ showFreeTextOption && /* @__PURE__ */ jsxs(CommandItem, { value: trimmedQuery, onSelect: () => commit(trimmedQuery), className: "cursor-pointer", children: [
4696
+ /* @__PURE__ */ jsx(Check, { className: "mr-2 h-4 w-4 opacity-0" }),
4697
+ 'Use "',
4698
+ trimmedQuery,
4699
+ '"'
4700
+ ] }, "__free_text__"),
4701
+ normalizedItems.map((item) => /* @__PURE__ */ jsxs(CommandItem, { value: item.label, keywords: [item.value, item.label], onSelect: () => commit(value === item.value ? "" : item.value), className: "cursor-pointer", children: [
4702
+ /* @__PURE__ */ jsx(Check, { className: cn("mr-2 h-4 w-4", value === item.value ? "opacity-100" : "opacity-0") }),
4703
+ item.label
4704
+ ] }, item.value))
4705
+ ] })
4706
+ ] })
4707
+ ]
4708
+ }
4709
+ )
4656
4710
  }
4657
4711
  )
4658
4712
  ] });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "najm-kit",
3
- "version": "2.11.14",
3
+ "version": "2.11.15",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "description": "Reusable React UI component package for Najm framework",