@fabio.caffarello/react-design-system 4.0.0 → 4.2.0

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.
@@ -1,150 +1,161 @@
1
1
  "use client";
2
- import { jsxs as ee, jsx as x } from "react/jsx-runtime";
3
- import { forwardRef as te, useId as re, useState as g, useRef as k, useEffect as d } from "react";
4
- import ne from "../../primitives/Input/Input.js";
5
- import { Loader2 as oe, ChevronDown as se } from "lucide-react";
6
- import ie from "./AutocompleteList.js";
7
- import { mergeRefs as le } from "../../utils/mergeRefs.js";
8
- const ae = te(
2
+ import { jsxs as re, jsx as m } from "react/jsx-runtime";
3
+ import { forwardRef as ne, useId as oe, useState as y, useRef as g, useEffect as p } from "react";
4
+ import se from "../../primitives/Input/Input.js";
5
+ import { Loader2 as ie, ChevronDown as le } from "lucide-react";
6
+ import ae from "./AutocompleteList.js";
7
+ import { mergeRefs as ce } from "../../utils/mergeRefs.js";
8
+ const ue = ne(
9
9
  function({
10
- options: a,
11
- value: $,
10
+ options: c,
11
+ value: V,
12
12
  defaultValue: F,
13
- onChange: s,
14
- onSelect: y,
15
- placeholder: z = "Type to search...",
13
+ onChange: i,
14
+ onSelect: k,
15
+ placeholder: G = "Type to search...",
16
16
  loading: D = !1,
17
- disabled: G = !1,
17
+ disabled: J = !1,
18
18
  emptyMessage: j = "No options found",
19
- debounceMs: J = 300,
19
+ debounceMs: Q = 300,
20
20
  filterOptions: H,
21
- className: Q = "",
22
- inputClassName: W = "",
23
- size: X = "md",
21
+ className: W = "",
22
+ inputClassName: X = "",
23
+ size: Y = "md",
24
24
  label: A,
25
25
  "aria-label": O,
26
- "aria-labelledby": m,
27
- id: R
28
- }, Y) {
29
- const Z = re(), E = R != null ? R : Z, N = `${E}-listbox`, [_, K] = g(
26
+ "aria-labelledby": h,
27
+ id: R,
28
+ name: K,
29
+ form: Z
30
+ }, _) {
31
+ const M = oe(), E = R != null ? R : M, N = `${E}-listbox`, [B, L] = y(
30
32
  typeof F == "string" ? F : ""
31
- ), [c, i] = g(!1), [r, l] = g(-1), [p, u] = g(""), h = k(null), L = k(null), v = k(null), f = k(null), V = $ !== void 0, w = V ? $ : _, n = p.trim() ? H ? H(a, p) : a.filter(
32
- (e) => e.label.toLowerCase().includes(p.toLowerCase())
33
- ) : a, M = n.length > 0, B = (e) => {
33
+ ), [u, l] = y(!1), [r, a] = y(-1), [v, f] = y(""), w = g(null), S = g(null), b = g(null), d = g(null), T = V !== void 0, s = T ? V : B, n = v.trim() ? H ? H(c, v) : c.filter(
34
+ (e) => e.label.toLowerCase().includes(v.toLowerCase())
35
+ ) : c, C = n.length > 0, P = (e) => {
34
36
  const t = e.target.value;
35
- u(t), V || K(t), s == null || s(t), f.current && clearTimeout(f.current), f.current = setTimeout(() => {
36
- i(!0), l(-1);
37
- }, J);
38
- }, S = (e) => {
37
+ f(t), T || L(t), i == null || i(t), d.current && clearTimeout(d.current), d.current = setTimeout(() => {
38
+ l(!0), a(-1);
39
+ }, Q);
40
+ }, q = (e) => {
39
41
  var t;
40
- e.disabled || (V || K(e.value), u(e.label), i(!1), l(-1), s == null || s(e.value), y == null || y(e), (t = L.current) == null || t.focus());
41
- }, q = (e, t) => {
42
+ e.disabled || (T || L(e.value), f(e.label), l(!1), a(-1), i == null || i(e.value), k == null || k(e), (t = S.current) == null || t.focus());
43
+ }, U = (e, t) => {
42
44
  const o = n.length;
43
45
  if (o === 0) return -1;
44
- const I = e < 0 ? t === 1 ? -1 : 0 : e;
45
- for (let T = 1; T <= o; T++) {
46
- const U = ((I + t * T) % o + o) % o;
47
- if (!n[U].disabled) return U;
46
+ const x = e < 0 ? t === 1 ? -1 : 0 : e;
47
+ for (let $ = 1; $ <= o; $++) {
48
+ const z = ((x + t * $) % o + o) % o;
49
+ if (!n[z].disabled) return z;
48
50
  }
49
51
  return e;
50
- }, C = (e) => {
51
- if (!c || n.length === 0) {
52
- (e.key === "ArrowDown" || e.key === "Enter") && i(!0);
52
+ }, ee = (e) => {
53
+ if (!u || n.length === 0) {
54
+ (e.key === "ArrowDown" || e.key === "Enter") && l(!0);
53
55
  return;
54
56
  }
55
57
  switch (e.key) {
56
58
  case "ArrowDown":
57
- e.preventDefault(), l((t) => q(t, 1));
59
+ e.preventDefault(), a((t) => U(t, 1));
58
60
  break;
59
61
  case "ArrowUp":
60
- e.preventDefault(), l((t) => q(t, -1));
62
+ e.preventDefault(), a((t) => U(t, -1));
61
63
  break;
62
64
  case "Enter":
63
- e.preventDefault(), r >= 0 && r < n.length && S(n[r]);
65
+ e.preventDefault(), r >= 0 && r < n.length && q(n[r]);
64
66
  break;
65
67
  case "Escape":
66
- e.preventDefault(), i(!1), l(-1);
68
+ e.preventDefault(), l(!1), a(-1);
67
69
  break;
68
70
  }
69
71
  };
70
- d(() => {
71
- if (!c) return;
72
+ p(() => {
73
+ if (!u) return;
72
74
  const e = (t) => {
73
- var I;
75
+ var x;
74
76
  const o = t.target;
75
- h.current && !h.current.contains(o) && !((I = v.current) != null && I.contains(o)) && (i(!1), l(-1));
77
+ w.current && !w.current.contains(o) && !((x = b.current) != null && x.contains(o)) && (l(!1), a(-1));
76
78
  };
77
79
  return document.addEventListener("mousedown", e), () => document.removeEventListener("mousedown", e);
78
- }, [c]), d(() => () => {
79
- f.current && clearTimeout(f.current);
80
- }, []), d(() => {
81
- if (r >= 0 && v.current) {
82
- const e = v.current.querySelectorAll('[role="option"]');
80
+ }, [u]), p(() => () => {
81
+ d.current && clearTimeout(d.current);
82
+ }, []), p(() => {
83
+ if (r >= 0 && b.current) {
84
+ const e = b.current.querySelectorAll('[role="option"]');
83
85
  e[r] && typeof e[r].scrollIntoView == "function" && e[r].scrollIntoView({
84
86
  block: "nearest",
85
87
  behavior: "smooth"
86
88
  });
87
89
  }
88
- }, [r]), d(() => {
89
- if (w) {
90
- const e = a.find((t) => t.value === w);
91
- u(e ? e.label : w);
90
+ }, [r]), p(() => {
91
+ if (s) {
92
+ const e = c.find((t) => t.value === s);
93
+ f(e ? e.label : s);
92
94
  } else
93
- u("");
94
- }, [w, a]), d(() => {
95
- }, [A, O, m, E]);
96
- const b = c && (M || D || !!j), P = b && r >= 0 && r < n.length ? `${N}-option-${r}` : void 0;
97
- return /* @__PURE__ */ ee("div", { ref: h, className: `relative ${Q}`, children: [
98
- /* @__PURE__ */ x(
99
- ne,
95
+ f("");
96
+ }, [s, c]), p(() => {
97
+ }, [A, O, h, E]);
98
+ const I = u && (C || D || !!j), te = I && r >= 0 && r < n.length ? `${N}-option-${r}` : void 0;
99
+ return /* @__PURE__ */ re("div", { ref: w, className: `relative ${W}`, children: [
100
+ /* @__PURE__ */ m(
101
+ se,
100
102
  {
101
- ref: le(L, Y),
103
+ ref: ce(S, _),
102
104
  id: E,
103
105
  label: A,
104
106
  "aria-label": O,
105
- "aria-labelledby": m,
107
+ "aria-labelledby": h,
106
108
  role: "combobox",
107
- "aria-expanded": b,
108
- "aria-controls": b ? N : void 0,
109
+ "aria-expanded": I,
110
+ "aria-controls": I ? N : void 0,
109
111
  "aria-haspopup": "listbox",
110
112
  "aria-autocomplete": "list",
111
- "aria-activedescendant": P,
112
- value: p,
113
- onChange: B,
114
- onKeyDown: C,
115
- onFocus: () => i(!0),
116
- placeholder: z,
117
- disabled: G,
118
- size: X,
119
- rightIcon: D ? /* @__PURE__ */ x(oe, { className: "h-4 w-4 animate-spin" }) : /* @__PURE__ */ x(
120
- se,
113
+ "aria-activedescendant": te,
114
+ value: v,
115
+ onChange: P,
116
+ onKeyDown: ee,
117
+ onFocus: () => l(!0),
118
+ placeholder: G,
119
+ disabled: J,
120
+ size: Y,
121
+ rightIcon: D ? /* @__PURE__ */ m(ie, { className: "h-4 w-4 animate-spin" }) : /* @__PURE__ */ m(
122
+ le,
121
123
  {
122
- className: `h-4 w-4 transition-transform ${c ? "rotate-180" : ""}`
124
+ className: `h-4 w-4 transition-transform ${u ? "rotate-180" : ""}`
123
125
  }
124
126
  ),
125
- className: W
127
+ className: X
126
128
  }
127
129
  ),
128
- b && /* @__PURE__ */ x(
129
- ie,
130
+ K && /* @__PURE__ */ m(
131
+ "input",
130
132
  {
131
- ref: v,
133
+ type: "hidden",
134
+ name: K,
135
+ value: s != null ? s : "",
136
+ form: Z
137
+ }
138
+ ),
139
+ I && /* @__PURE__ */ m(
140
+ ae,
141
+ {
142
+ ref: b,
132
143
  id: N,
133
144
  options: n,
134
145
  highlightedIndex: r,
135
- onSelect: S,
146
+ onSelect: q,
136
147
  loading: D,
137
148
  emptyMessage: j,
138
- containerRef: h,
139
- "aria-labelledby": m,
140
- "aria-label": m ? void 0 : O || A
149
+ containerRef: w,
150
+ "aria-labelledby": h,
151
+ "aria-label": h ? void 0 : O || A
141
152
  }
142
153
  )
143
154
  ] });
144
155
  }
145
156
  );
146
- ae.displayName = "Autocomplete";
157
+ ue.displayName = "Autocomplete";
147
158
  export {
148
- ae as default
159
+ ue as default
149
160
  };
150
161
  //# sourceMappingURL=Autocomplete.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"Autocomplete.js","sources":["../../../../../src/ui/components/Autocomplete/Autocomplete.tsx"],"sourcesContent":["\"use client\";\n\nimport { useState, useRef, useEffect, useId, forwardRef } from \"react\";\nimport Input from \"../../primitives/Input/Input\";\nimport { mergeRefs } from \"../../utils\";\nimport { ChevronDown, Loader2 } from \"lucide-react\";\nimport AutocompleteList from \"./AutocompleteList\";\nimport type { AutocompleteOptionType } from \"./AutocompleteOption\";\n\nexport interface AutocompleteProps {\n options: AutocompleteOptionType[];\n value?: string;\n defaultValue?: string;\n onChange?: (value: string) => void;\n onSelect?: (option: AutocompleteOptionType) => void;\n placeholder?: string;\n loading?: boolean;\n disabled?: boolean;\n emptyMessage?: string;\n debounceMs?: number;\n filterOptions?: (\n options: AutocompleteOptionType[],\n searchValue: string,\n ) => AutocompleteOptionType[];\n className?: string;\n inputClassName?: string;\n size?: \"sm\" | \"md\" | \"lg\";\n /**\n * Visible label rendered above the input via the `Input` primitive's\n * `label` API, which wires `<label htmlFor>` to the inner `<input>`.\n * Provides the accessible name axe `aria-input-field-name` requires.\n */\n label?: string;\n /**\n * Invisible accessible name. Use when the input has no visible label\n * (e.g. a tightly-packed toolbar combobox). One of `label`,\n * `aria-label`, or `aria-labelledby` MUST be present — without any,\n * the input has no programmatic name and axe `aria-input-field-name`\n * (serious) flags it. A dev-only warning fires when all are missing.\n */\n \"aria-label\"?: string;\n /**\n * Override path: point at an id the consumer manages externally.\n */\n \"aria-labelledby\"?: string;\n id?: string;\n}\n\n/**\n * Autocomplete Component\n *\n * An input component with autocomplete suggestions.\n * Supports keyboard navigation, loading states, and custom filtering.\n *\n * @example\n * ```tsx\n * <Autocomplete\n * options={[\n * { value: '1', label: 'Option 1' },\n * { value: '2', label: 'Option 2' },\n * ]}\n * onSelect={(option) => console.log(option)}\n * />\n * ```\n */\nconst Autocomplete = forwardRef<HTMLInputElement, AutocompleteProps>(\n function Autocomplete(\n {\n options,\n value: controlledValue,\n defaultValue,\n onChange,\n onSelect,\n placeholder = \"Type to search...\",\n loading = false,\n disabled = false,\n emptyMessage = \"No options found\",\n debounceMs = 300,\n filterOptions,\n className = \"\",\n inputClassName = \"\",\n size = \"md\",\n label,\n \"aria-label\": ariaLabel,\n \"aria-labelledby\": ariaLabelledBy,\n id: idProp,\n },\n ref,\n ) {\n const autoId = useId();\n const inputId = idProp ?? autoId;\n const listboxId = `${inputId}-listbox`;\n const [internalValue, setInternalValue] = useState<string>(\n typeof defaultValue === \"string\" ? defaultValue : \"\",\n );\n const [isOpen, setIsOpen] = useState(false);\n const [highlightedIndex, setHighlightedIndex] = useState(-1);\n const [searchValue, setSearchValue] = useState(\"\");\n const containerRef = useRef<HTMLDivElement>(null);\n const inputRef = useRef<HTMLInputElement>(null);\n const listRef = useRef<HTMLDivElement>(null);\n const debounceTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n const isControlled = controlledValue !== undefined;\n const currentValue = isControlled ? controlledValue : internalValue;\n\n // Filter options\n const getFilteredOptions = (): AutocompleteOptionType[] => {\n if (!searchValue.trim()) {\n return options;\n }\n\n if (filterOptions) {\n return filterOptions(options, searchValue);\n }\n\n // Default filter: case-insensitive search in label\n return options.filter((option) =>\n option.label.toLowerCase().includes(searchValue.toLowerCase()),\n );\n };\n\n const filteredOptions = getFilteredOptions();\n const hasOptions = filteredOptions.length > 0;\n\n // Handle input change\n const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n const newValue = e.target.value;\n setSearchValue(newValue);\n\n if (!isControlled) {\n setInternalValue(newValue);\n }\n\n onChange?.(newValue);\n\n // Debounce search\n if (debounceTimerRef.current) {\n clearTimeout(debounceTimerRef.current);\n }\n\n debounceTimerRef.current = setTimeout(() => {\n setIsOpen(true);\n setHighlightedIndex(-1);\n }, debounceMs);\n };\n\n // Handle option select\n const handleSelect = (option: AutocompleteOptionType) => {\n if (option.disabled) return;\n\n if (!isControlled) {\n setInternalValue(option.value);\n }\n\n setSearchValue(option.label);\n setIsOpen(false);\n setHighlightedIndex(-1);\n onChange?.(option.value);\n onSelect?.(option);\n inputRef.current?.focus();\n };\n\n // Next/previous ENABLED option index, wrapping, skipping disabled\n // options (arrow nav previously landed on disabled options where\n // Enter then did nothing — a dead keypress).\n const moveHighlight = (prev: number, dir: 1 | -1): number => {\n const n = filteredOptions.length;\n if (n === 0) return -1;\n const start = prev < 0 ? (dir === 1 ? -1 : 0) : prev;\n for (let i = 1; i <= n; i++) {\n const idx = (((start + dir * i) % n) + n) % n;\n if (!filteredOptions[idx].disabled) return idx;\n }\n return prev;\n };\n\n // Handle keyboard navigation\n const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {\n if (!isOpen || filteredOptions.length === 0) {\n if (e.key === \"ArrowDown\" || e.key === \"Enter\") {\n setIsOpen(true);\n }\n return;\n }\n\n switch (e.key) {\n case \"ArrowDown\":\n e.preventDefault();\n setHighlightedIndex((prev) => moveHighlight(prev, 1));\n break;\n case \"ArrowUp\":\n e.preventDefault();\n setHighlightedIndex((prev) => moveHighlight(prev, -1));\n break;\n case \"Enter\":\n e.preventDefault();\n if (\n highlightedIndex >= 0 &&\n highlightedIndex < filteredOptions.length\n ) {\n handleSelect(filteredOptions[highlightedIndex]);\n }\n break;\n case \"Escape\":\n e.preventDefault();\n setIsOpen(false);\n setHighlightedIndex(-1);\n break;\n }\n };\n\n // Close on click outside\n useEffect(() => {\n if (!isOpen) return;\n\n const handleClickOutside = (e: MouseEvent) => {\n const target = e.target as Node;\n // The list is portalled to document.body, so it is NOT inside\n // containerRef — without the listRef check, a mousedown on an\n // option closed the list before its click fired, losing the\n // selection.\n if (\n containerRef.current &&\n !containerRef.current.contains(target) &&\n !listRef.current?.contains(target)\n ) {\n setIsOpen(false);\n setHighlightedIndex(-1);\n }\n };\n\n document.addEventListener(\"mousedown\", handleClickOutside);\n return () =>\n document.removeEventListener(\"mousedown\", handleClickOutside);\n }, [isOpen]);\n\n // Clear any pending debounce timer on unmount (avoids a state update\n // on an unmounted component / a dangling timer).\n useEffect(() => {\n return () => {\n if (debounceTimerRef.current) clearTimeout(debounceTimerRef.current);\n };\n }, []);\n\n // Scroll highlighted item into view\n useEffect(() => {\n if (highlightedIndex >= 0 && listRef.current) {\n const items = listRef.current.querySelectorAll('[role=\"option\"]');\n if (\n items[highlightedIndex] &&\n typeof items[highlightedIndex].scrollIntoView === \"function\"\n ) {\n items[highlightedIndex].scrollIntoView({\n block: \"nearest\",\n behavior: \"smooth\",\n });\n }\n }\n }, [highlightedIndex]);\n\n // Sync search value with current value\n useEffect(() => {\n if (currentValue) {\n const option = options.find((opt) => opt.value === currentValue);\n if (option) {\n setSearchValue(option.label);\n } else {\n setSearchValue(currentValue);\n }\n } else {\n setSearchValue(\"\");\n }\n }, [currentValue, options]);\n\n // Dev-only accessible-name warning. Same four-path shape as the\n // Textarea 6c guard: label / aria-label / aria-labelledby / external\n // `<label htmlFor={id}>`. Without any source, axe\n // `aria-input-field-name` (serious) flags the input. Silent in\n // production.\n useEffect(() => {\n if (!import.meta.env.DEV) return;\n if (label || ariaLabel || ariaLabelledBy) return;\n const externalLabel =\n typeof document !== \"undefined\"\n ? document.querySelector(`label[for=\"${CSS.escape(inputId)}\"]`)\n : null;\n if (externalLabel) return;\n console.warn(\n \"[Autocomplete] Missing accessible name. Provide a `label` prop, `aria-label`, `aria-labelledby`, or pair an external `<label htmlFor={id}>` with the same `id`.\",\n );\n }, [label, ariaLabel, ariaLabelledBy, inputId]);\n\n const shouldShowList =\n isOpen && (hasOptions || loading || Boolean(emptyMessage));\n const activeOptionId =\n shouldShowList &&\n highlightedIndex >= 0 &&\n highlightedIndex < filteredOptions.length\n ? `${listboxId}-option-${highlightedIndex}`\n : undefined;\n\n return (\n <div ref={containerRef} className={`relative ${className}`}>\n <Input\n ref={mergeRefs(inputRef, ref)}\n id={inputId}\n label={label}\n aria-label={ariaLabel}\n aria-labelledby={ariaLabelledBy}\n role=\"combobox\"\n aria-expanded={shouldShowList}\n aria-controls={shouldShowList ? listboxId : undefined}\n aria-haspopup=\"listbox\"\n aria-autocomplete=\"list\"\n aria-activedescendant={activeOptionId}\n value={searchValue}\n onChange={handleInputChange}\n onKeyDown={handleKeyDown}\n onFocus={() => setIsOpen(true)}\n placeholder={placeholder}\n disabled={disabled}\n size={size}\n rightIcon={\n loading ? (\n <Loader2 className=\"h-4 w-4 animate-spin\" />\n ) : (\n <ChevronDown\n className={`h-4 w-4 transition-transform ${\n isOpen ? \"rotate-180\" : \"\"\n }`}\n />\n )\n }\n className={inputClassName}\n />\n\n {shouldShowList && (\n <AutocompleteList\n ref={listRef}\n id={listboxId}\n options={filteredOptions}\n highlightedIndex={highlightedIndex}\n onSelect={handleSelect}\n loading={loading}\n emptyMessage={emptyMessage}\n containerRef={containerRef}\n // Cascade the same accessible-name source the consumer\n // provided for the input to the listbox portal — keeps\n // axe `aria-input-field-name` satisfied on the listbox\n // without making the consumer re-state the name.\n aria-labelledby={ariaLabelledBy}\n aria-label={ariaLabelledBy ? undefined : ariaLabel || label}\n />\n )}\n </div>\n );\n },\n);\n\nAutocomplete.displayName = \"Autocomplete\";\n\nexport default Autocomplete;\n"],"names":["Autocomplete","forwardRef","options","controlledValue","defaultValue","onChange","onSelect","placeholder","loading","disabled","emptyMessage","debounceMs","filterOptions","className","inputClassName","size","label","ariaLabel","ariaLabelledBy","idProp","ref","autoId","useId","inputId","listboxId","internalValue","setInternalValue","useState","isOpen","setIsOpen","highlightedIndex","setHighlightedIndex","searchValue","setSearchValue","containerRef","useRef","inputRef","listRef","debounceTimerRef","isControlled","currentValue","filteredOptions","option","hasOptions","handleInputChange","newValue","handleSelect","_a","moveHighlight","prev","dir","n","start","i","idx","handleKeyDown","useEffect","handleClickOutside","e","target","items","opt","shouldShowList","activeOptionId","jsx","Input","mergeRefs","Loader2","ChevronDown","AutocompleteList"],"mappings":"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"}
1
+ {"version":3,"file":"Autocomplete.js","sources":["../../../../../src/ui/components/Autocomplete/Autocomplete.tsx"],"sourcesContent":["\"use client\";\n\nimport { useState, useRef, useEffect, useId, forwardRef } from \"react\";\nimport Input from \"../../primitives/Input/Input\";\nimport { mergeRefs } from \"../../utils\";\nimport { ChevronDown, Loader2 } from \"lucide-react\";\nimport AutocompleteList from \"./AutocompleteList\";\nimport type { AutocompleteOptionType } from \"./AutocompleteOption\";\n\nexport interface AutocompleteProps {\n options: AutocompleteOptionType[];\n value?: string;\n defaultValue?: string;\n onChange?: (value: string) => void;\n onSelect?: (option: AutocompleteOptionType) => void;\n placeholder?: string;\n loading?: boolean;\n disabled?: boolean;\n emptyMessage?: string;\n debounceMs?: number;\n filterOptions?: (\n options: AutocompleteOptionType[],\n searchValue: string,\n ) => AutocompleteOptionType[];\n className?: string;\n inputClassName?: string;\n size?: \"sm\" | \"md\" | \"lg\";\n /**\n * Visible label rendered above the input via the `Input` primitive's\n * `label` API, which wires `<label htmlFor>` to the inner `<input>`.\n * Provides the accessible name axe `aria-input-field-name` requires.\n */\n label?: string;\n /**\n * Invisible accessible name. Use when the input has no visible label\n * (e.g. a tightly-packed toolbar combobox). One of `label`,\n * `aria-label`, or `aria-labelledby` MUST be present — without any,\n * the input has no programmatic name and axe `aria-input-field-name`\n * (serious) flags it. A dev-only warning fires when all are missing.\n */\n \"aria-label\"?: string;\n /**\n * Override path: point at an id the consumer manages externally.\n */\n \"aria-labelledby\"?: string;\n id?: string;\n /**\n * Name of the form field (issue #225). When set, the component renders\n * a synchronized `<input type=\"hidden\" name={name}>` carrying the\n * **selected option value** (not the visible search text), so the\n * Autocomplete participates in native form submission exactly like a\n * `<select name>` — a `<form method=\"GET\">` picks up `name=value` with\n * no `onChange`/router wiring on the consumer side. This is the\n * form-native integration the brasil-a-vera filter bars need.\n *\n * Caveat: the component is interactive (`\"use client\"`), so the hidden\n * field is populated once hydrated — it is NOT a pre-hydration no-JS\n * fallback. For a true zero-JS fallback, pair it with a `<noscript>`\n * native `<select name>`.\n */\n name?: string;\n /**\n * Associates the hidden field with a form by id (the native `form`\n * attribute), for when the Autocomplete renders outside the `<form>`\n * it submits to. No effect unless `name` is also set.\n */\n form?: string;\n}\n\n/**\n * Autocomplete Component\n *\n * An input component with autocomplete suggestions.\n * Supports keyboard navigation, loading states, and custom filtering.\n *\n * @example\n * ```tsx\n * <Autocomplete\n * options={[\n * { value: '1', label: 'Option 1' },\n * { value: '2', label: 'Option 2' },\n * ]}\n * onSelect={(option) => console.log(option)}\n * />\n * ```\n */\nconst Autocomplete = forwardRef<HTMLInputElement, AutocompleteProps>(\n function Autocomplete(\n {\n options,\n value: controlledValue,\n defaultValue,\n onChange,\n onSelect,\n placeholder = \"Type to search...\",\n loading = false,\n disabled = false,\n emptyMessage = \"No options found\",\n debounceMs = 300,\n filterOptions,\n className = \"\",\n inputClassName = \"\",\n size = \"md\",\n label,\n \"aria-label\": ariaLabel,\n \"aria-labelledby\": ariaLabelledBy,\n id: idProp,\n name,\n form,\n },\n ref,\n ) {\n const autoId = useId();\n const inputId = idProp ?? autoId;\n const listboxId = `${inputId}-listbox`;\n const [internalValue, setInternalValue] = useState<string>(\n typeof defaultValue === \"string\" ? defaultValue : \"\",\n );\n const [isOpen, setIsOpen] = useState(false);\n const [highlightedIndex, setHighlightedIndex] = useState(-1);\n const [searchValue, setSearchValue] = useState(\"\");\n const containerRef = useRef<HTMLDivElement>(null);\n const inputRef = useRef<HTMLInputElement>(null);\n const listRef = useRef<HTMLDivElement>(null);\n const debounceTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n const isControlled = controlledValue !== undefined;\n const currentValue = isControlled ? controlledValue : internalValue;\n\n // Filter options\n const getFilteredOptions = (): AutocompleteOptionType[] => {\n if (!searchValue.trim()) {\n return options;\n }\n\n if (filterOptions) {\n return filterOptions(options, searchValue);\n }\n\n // Default filter: case-insensitive search in label\n return options.filter((option) =>\n option.label.toLowerCase().includes(searchValue.toLowerCase()),\n );\n };\n\n const filteredOptions = getFilteredOptions();\n const hasOptions = filteredOptions.length > 0;\n\n // Handle input change\n const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n const newValue = e.target.value;\n setSearchValue(newValue);\n\n if (!isControlled) {\n setInternalValue(newValue);\n }\n\n onChange?.(newValue);\n\n // Debounce search\n if (debounceTimerRef.current) {\n clearTimeout(debounceTimerRef.current);\n }\n\n debounceTimerRef.current = setTimeout(() => {\n setIsOpen(true);\n setHighlightedIndex(-1);\n }, debounceMs);\n };\n\n // Handle option select\n const handleSelect = (option: AutocompleteOptionType) => {\n if (option.disabled) return;\n\n if (!isControlled) {\n setInternalValue(option.value);\n }\n\n setSearchValue(option.label);\n setIsOpen(false);\n setHighlightedIndex(-1);\n onChange?.(option.value);\n onSelect?.(option);\n inputRef.current?.focus();\n };\n\n // Next/previous ENABLED option index, wrapping, skipping disabled\n // options (arrow nav previously landed on disabled options where\n // Enter then did nothing — a dead keypress).\n const moveHighlight = (prev: number, dir: 1 | -1): number => {\n const n = filteredOptions.length;\n if (n === 0) return -1;\n const start = prev < 0 ? (dir === 1 ? -1 : 0) : prev;\n for (let i = 1; i <= n; i++) {\n const idx = (((start + dir * i) % n) + n) % n;\n if (!filteredOptions[idx].disabled) return idx;\n }\n return prev;\n };\n\n // Handle keyboard navigation\n const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {\n if (!isOpen || filteredOptions.length === 0) {\n if (e.key === \"ArrowDown\" || e.key === \"Enter\") {\n setIsOpen(true);\n }\n return;\n }\n\n switch (e.key) {\n case \"ArrowDown\":\n e.preventDefault();\n setHighlightedIndex((prev) => moveHighlight(prev, 1));\n break;\n case \"ArrowUp\":\n e.preventDefault();\n setHighlightedIndex((prev) => moveHighlight(prev, -1));\n break;\n case \"Enter\":\n e.preventDefault();\n if (\n highlightedIndex >= 0 &&\n highlightedIndex < filteredOptions.length\n ) {\n handleSelect(filteredOptions[highlightedIndex]);\n }\n break;\n case \"Escape\":\n e.preventDefault();\n setIsOpen(false);\n setHighlightedIndex(-1);\n break;\n }\n };\n\n // Close on click outside\n useEffect(() => {\n if (!isOpen) return;\n\n const handleClickOutside = (e: MouseEvent) => {\n const target = e.target as Node;\n // The list is portalled to document.body, so it is NOT inside\n // containerRef — without the listRef check, a mousedown on an\n // option closed the list before its click fired, losing the\n // selection.\n if (\n containerRef.current &&\n !containerRef.current.contains(target) &&\n !listRef.current?.contains(target)\n ) {\n setIsOpen(false);\n setHighlightedIndex(-1);\n }\n };\n\n document.addEventListener(\"mousedown\", handleClickOutside);\n return () =>\n document.removeEventListener(\"mousedown\", handleClickOutside);\n }, [isOpen]);\n\n // Clear any pending debounce timer on unmount (avoids a state update\n // on an unmounted component / a dangling timer).\n useEffect(() => {\n return () => {\n if (debounceTimerRef.current) clearTimeout(debounceTimerRef.current);\n };\n }, []);\n\n // Scroll highlighted item into view\n useEffect(() => {\n if (highlightedIndex >= 0 && listRef.current) {\n const items = listRef.current.querySelectorAll('[role=\"option\"]');\n if (\n items[highlightedIndex] &&\n typeof items[highlightedIndex].scrollIntoView === \"function\"\n ) {\n items[highlightedIndex].scrollIntoView({\n block: \"nearest\",\n behavior: \"smooth\",\n });\n }\n }\n }, [highlightedIndex]);\n\n // Sync search value with current value\n useEffect(() => {\n if (currentValue) {\n const option = options.find((opt) => opt.value === currentValue);\n if (option) {\n setSearchValue(option.label);\n } else {\n setSearchValue(currentValue);\n }\n } else {\n setSearchValue(\"\");\n }\n }, [currentValue, options]);\n\n // Dev-only accessible-name warning. Same four-path shape as the\n // Textarea 6c guard: label / aria-label / aria-labelledby / external\n // `<label htmlFor={id}>`. Without any source, axe\n // `aria-input-field-name` (serious) flags the input. Silent in\n // production.\n useEffect(() => {\n if (!import.meta.env.DEV) return;\n if (label || ariaLabel || ariaLabelledBy) return;\n const externalLabel =\n typeof document !== \"undefined\"\n ? document.querySelector(`label[for=\"${CSS.escape(inputId)}\"]`)\n : null;\n if (externalLabel) return;\n console.warn(\n \"[Autocomplete] Missing accessible name. Provide a `label` prop, `aria-label`, `aria-labelledby`, or pair an external `<label htmlFor={id}>` with the same `id`.\",\n );\n }, [label, ariaLabel, ariaLabelledBy, inputId]);\n\n const shouldShowList =\n isOpen && (hasOptions || loading || Boolean(emptyMessage));\n const activeOptionId =\n shouldShowList &&\n highlightedIndex >= 0 &&\n highlightedIndex < filteredOptions.length\n ? `${listboxId}-option-${highlightedIndex}`\n : undefined;\n\n return (\n <div ref={containerRef} className={`relative ${className}`}>\n <Input\n ref={mergeRefs(inputRef, ref)}\n id={inputId}\n label={label}\n aria-label={ariaLabel}\n aria-labelledby={ariaLabelledBy}\n role=\"combobox\"\n aria-expanded={shouldShowList}\n aria-controls={shouldShowList ? listboxId : undefined}\n aria-haspopup=\"listbox\"\n aria-autocomplete=\"list\"\n aria-activedescendant={activeOptionId}\n value={searchValue}\n onChange={handleInputChange}\n onKeyDown={handleKeyDown}\n onFocus={() => setIsOpen(true)}\n placeholder={placeholder}\n disabled={disabled}\n size={size}\n rightIcon={\n loading ? (\n <Loader2 className=\"h-4 w-4 animate-spin\" />\n ) : (\n <ChevronDown\n className={`h-4 w-4 transition-transform ${\n isOpen ? \"rotate-180\" : \"\"\n }`}\n />\n )\n }\n className={inputClassName}\n />\n\n {/*\n Form-native participation (issue #225). The hidden field carries\n the SELECTED OPTION VALUE (`currentValue`), not the visible\n `searchValue` label, so a native `<form>` submits `name=value`\n like a `<select name>`. Rendered only when `name` is set; `form`\n lets it associate with a form by id when rendered outside it.\n */}\n {name && (\n <input\n type=\"hidden\"\n name={name}\n value={currentValue ?? \"\"}\n form={form}\n />\n )}\n\n {shouldShowList && (\n <AutocompleteList\n ref={listRef}\n id={listboxId}\n options={filteredOptions}\n highlightedIndex={highlightedIndex}\n onSelect={handleSelect}\n loading={loading}\n emptyMessage={emptyMessage}\n containerRef={containerRef}\n // Cascade the same accessible-name source the consumer\n // provided for the input to the listbox portal — keeps\n // axe `aria-input-field-name` satisfied on the listbox\n // without making the consumer re-state the name.\n aria-labelledby={ariaLabelledBy}\n aria-label={ariaLabelledBy ? undefined : ariaLabel || label}\n />\n )}\n </div>\n );\n },\n);\n\nAutocomplete.displayName = \"Autocomplete\";\n\nexport default Autocomplete;\n"],"names":["Autocomplete","forwardRef","options","controlledValue","defaultValue","onChange","onSelect","placeholder","loading","disabled","emptyMessage","debounceMs","filterOptions","className","inputClassName","size","label","ariaLabel","ariaLabelledBy","idProp","name","form","ref","autoId","useId","inputId","listboxId","internalValue","setInternalValue","useState","isOpen","setIsOpen","highlightedIndex","setHighlightedIndex","searchValue","setSearchValue","containerRef","useRef","inputRef","listRef","debounceTimerRef","isControlled","currentValue","filteredOptions","option","hasOptions","handleInputChange","newValue","handleSelect","_a","moveHighlight","prev","dir","n","start","i","idx","handleKeyDown","useEffect","handleClickOutside","e","target","items","opt","shouldShowList","activeOptionId","jsx","Input","mergeRefs","Loader2","ChevronDown","AutocompleteList"],"mappings":";;;;;;;AAsFA,MAAMA,KAAeC;AAAA,EACnB,SACE;AAAA,IACE,SAAAC;AAAA,IACA,OAAOC;AAAA,IACP,cAAAC;AAAA,IACA,UAAAC;AAAA,IACA,UAAAC;AAAA,IACA,aAAAC,IAAc;AAAA,IACd,SAAAC,IAAU;AAAA,IACV,UAAAC,IAAW;AAAA,IACX,cAAAC,IAAe;AAAA,IACf,YAAAC,IAAa;AAAA,IACb,eAAAC;AAAA,IACA,WAAAC,IAAY;AAAA,IACZ,gBAAAC,IAAiB;AAAA,IACjB,MAAAC,IAAO;AAAA,IACP,OAAAC;AAAA,IACA,cAAcC;AAAA,IACd,mBAAmBC;AAAA,IACnB,IAAIC;AAAA,IACJ,MAAAC;AAAA,IACA,MAAAC;AAAA,EAAA,GAEFC,GACA;AACA,UAAMC,IAASC,GAAA,GACTC,IAAUN,KAAA,OAAAA,IAAUI,GACpBG,IAAY,GAAGD,CAAO,YACtB,CAACE,GAAeC,CAAgB,IAAIC;AAAA,MACxC,OAAOzB,KAAiB,WAAWA,IAAe;AAAA,IAAA,GAE9C,CAAC0B,GAAQC,CAAS,IAAIF,EAAS,EAAK,GACpC,CAACG,GAAkBC,CAAmB,IAAIJ,EAAS,EAAE,GACrD,CAACK,GAAaC,CAAc,IAAIN,EAAS,EAAE,GAC3CO,IAAeC,EAAuB,IAAI,GAC1CC,IAAWD,EAAyB,IAAI,GACxCE,IAAUF,EAAuB,IAAI,GACrCG,IAAmBH,EAA6C,IAAI,GAEpEI,IAAetC,MAAoB,QACnCuC,IAAeD,IAAetC,IAAkBwB,GAkBhDgB,IAdCT,EAAY,SAIbtB,IACKA,EAAcV,GAASgC,CAAW,IAIpChC,EAAQ;AAAA,MAAO,CAAC0C,MACrBA,EAAO,MAAM,cAAc,SAASV,EAAY,YAAA,CAAa;AAAA,IAAA,IATtDhC,GAcL2C,IAAaF,EAAgB,SAAS,GAGtCG,IAAoB,CAAC,MAA2C;AACpE,YAAMC,IAAW,EAAE,OAAO;AAC1B,MAAAZ,EAAeY,CAAQ,GAElBN,KACHb,EAAiBmB,CAAQ,GAG3B1C,KAAA,QAAAA,EAAW0C,IAGPP,EAAiB,WACnB,aAAaA,EAAiB,OAAO,GAGvCA,EAAiB,UAAU,WAAW,MAAM;AAC1C,QAAAT,EAAU,EAAI,GACdE,EAAoB,EAAE;AAAA,MACxB,GAAGtB,CAAU;AAAA,IACf,GAGMqC,IAAe,CAACJ,MAAmC;;AACvD,MAAIA,EAAO,aAENH,KACHb,EAAiBgB,EAAO,KAAK,GAG/BT,EAAeS,EAAO,KAAK,GAC3Bb,EAAU,EAAK,GACfE,EAAoB,EAAE,GACtB5B,KAAA,QAAAA,EAAWuC,EAAO,QAClBtC,KAAA,QAAAA,EAAWsC,KACXK,IAAAX,EAAS,YAAT,QAAAW,EAAkB;AAAA,IACpB,GAKMC,IAAgB,CAACC,GAAcC,MAAwB;AAC3D,YAAMC,IAAIV,EAAgB;AAC1B,UAAIU,MAAM,EAAG,QAAO;AACpB,YAAMC,IAAQH,IAAO,IAAKC,MAAQ,IAAI,KAAK,IAAKD;AAChD,eAASI,IAAI,GAAGA,KAAKF,GAAGE,KAAK;AAC3B,cAAMC,MAASF,IAAQF,IAAMG,KAAKF,IAAKA,KAAKA;AAC5C,YAAI,CAACV,EAAgBa,CAAG,EAAE,SAAU,QAAOA;AAAA,MAC7C;AACA,aAAOL;AAAA,IACT,GAGMM,KAAgB,CAAC,MAA6C;AAClE,UAAI,CAAC3B,KAAUa,EAAgB,WAAW,GAAG;AAC3C,SAAI,EAAE,QAAQ,eAAe,EAAE,QAAQ,YACrCZ,EAAU,EAAI;AAEhB;AAAA,MACF;AAEA,cAAQ,EAAE,KAAA;AAAA,QACR,KAAK;AACH,YAAE,eAAA,GACFE,EAAoB,CAACkB,MAASD,EAAcC,GAAM,CAAC,CAAC;AACpD;AAAA,QACF,KAAK;AACH,YAAE,eAAA,GACFlB,EAAoB,CAACkB,MAASD,EAAcC,GAAM,EAAE,CAAC;AACrD;AAAA,QACF,KAAK;AACH,YAAE,eAAA,GAEAnB,KAAoB,KACpBA,IAAmBW,EAAgB,UAEnCK,EAAaL,EAAgBX,CAAgB,CAAC;AAEhD;AAAA,QACF,KAAK;AACH,YAAE,eAAA,GACFD,EAAU,EAAK,GACfE,EAAoB,EAAE;AACtB;AAAA,MAAA;AAAA,IAEN;AAGA,IAAAyB,EAAU,MAAM;AACd,UAAI,CAAC5B,EAAQ;AAEb,YAAM6B,IAAqB,CAACC,MAAkB;;AAC5C,cAAMC,IAASD,EAAE;AAKjB,QACExB,EAAa,WACb,CAACA,EAAa,QAAQ,SAASyB,CAAM,KACrC,GAACZ,IAAAV,EAAQ,YAAR,QAAAU,EAAiB,SAASY,QAE3B9B,EAAU,EAAK,GACfE,EAAoB,EAAE;AAAA,MAE1B;AAEA,sBAAS,iBAAiB,aAAa0B,CAAkB,GAClD,MACL,SAAS,oBAAoB,aAAaA,CAAkB;AAAA,IAChE,GAAG,CAAC7B,CAAM,CAAC,GAIX4B,EAAU,MACD,MAAM;AACX,MAAIlB,EAAiB,WAAS,aAAaA,EAAiB,OAAO;AAAA,IACrE,GACC,CAAA,CAAE,GAGLkB,EAAU,MAAM;AACd,UAAI1B,KAAoB,KAAKO,EAAQ,SAAS;AAC5C,cAAMuB,IAAQvB,EAAQ,QAAQ,iBAAiB,iBAAiB;AAChE,QACEuB,EAAM9B,CAAgB,KACtB,OAAO8B,EAAM9B,CAAgB,EAAE,kBAAmB,cAElD8B,EAAM9B,CAAgB,EAAE,eAAe;AAAA,UACrC,OAAO;AAAA,UACP,UAAU;AAAA,QAAA,CACX;AAAA,MAEL;AAAA,IACF,GAAG,CAACA,CAAgB,CAAC,GAGrB0B,EAAU,MAAM;AACd,UAAIhB,GAAc;AAChB,cAAME,IAAS1C,EAAQ,KAAK,CAAC6D,MAAQA,EAAI,UAAUrB,CAAY;AAC/D,QACEP,EADES,IACaA,EAAO,QAEPF,CAFY;AAAA,MAI/B;AACE,QAAAP,EAAe,EAAE;AAAA,IAErB,GAAG,CAACO,GAAcxC,CAAO,CAAC,GAO1BwD,EAAU,MAAM;AAAA,IAWhB,GAAG,CAAC1C,GAAOC,GAAWC,GAAgBO,CAAO,CAAC;AAE9C,UAAMuC,IACJlC,MAAWe,KAAcrC,KAAW,EAAQE,IACxCuD,KACJD,KACAhC,KAAoB,KACpBA,IAAmBW,EAAgB,SAC/B,GAAGjB,CAAS,WAAWM,CAAgB,KACvC;AAEN,8BACG,OAAA,EAAI,KAAKI,GAAc,WAAW,YAAYvB,CAAS,IACtD,UAAA;AAAA,MAAA,gBAAAqD;AAAA,QAACC;AAAA,QAAA;AAAA,UACC,KAAKC,GAAU9B,GAAUhB,CAAG;AAAA,UAC5B,IAAIG;AAAA,UACJ,OAAAT;AAAA,UACA,cAAYC;AAAA,UACZ,mBAAiBC;AAAA,UACjB,MAAK;AAAA,UACL,iBAAe8C;AAAA,UACf,iBAAeA,IAAiBtC,IAAY;AAAA,UAC5C,iBAAc;AAAA,UACd,qBAAkB;AAAA,UAClB,yBAAuBuC;AAAA,UACvB,OAAO/B;AAAA,UACP,UAAUY;AAAA,UACV,WAAWW;AAAA,UACX,SAAS,MAAM1B,EAAU,EAAI;AAAA,UAC7B,aAAAxB;AAAA,UACA,UAAAE;AAAA,UACA,MAAAM;AAAA,UACA,WACEP,IACE,gBAAA0D,EAACG,IAAA,EAAQ,WAAU,uBAAA,CAAuB,IAE1C,gBAAAH;AAAA,YAACI;AAAA,YAAA;AAAA,cACC,WAAW,gCACTxC,IAAS,eAAe,EAC1B;AAAA,YAAA;AAAA,UAAA;AAAA,UAIN,WAAWhB;AAAA,QAAA;AAAA,MAAA;AAAA,MAUZM,KACC,gBAAA8C;AAAA,QAAC;AAAA,QAAA;AAAA,UACC,MAAK;AAAA,UACL,MAAA9C;AAAA,UACA,OAAOsB,KAAA,OAAAA,IAAgB;AAAA,UACvB,MAAArB;AAAA,QAAA;AAAA,MAAA;AAAA,MAIH2C,KACC,gBAAAE;AAAA,QAACK;AAAA,QAAA;AAAA,UACC,KAAKhC;AAAA,UACL,IAAIb;AAAA,UACJ,SAASiB;AAAA,UACT,kBAAAX;AAAA,UACA,UAAUgB;AAAA,UACV,SAAAxC;AAAA,UACA,cAAAE;AAAA,UACA,cAAA0B;AAAA,UAKA,mBAAiBlB;AAAA,UACjB,cAAYA,IAAiB,SAAYD,KAAaD;AAAA,QAAA;AAAA,MAAA;AAAA,IACxD,GAEJ;AAAA,EAEJ;AACF;AAEAhB,GAAa,cAAc;"}