@motor-hero/ui-kit 0.16.1 → 0.17.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.
- package/dist/components/combobox.d.ts +13 -0
- package/dist/components/combobox.d.ts.map +1 -1
- package/dist/index.cjs +98 -73
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +98 -73
- package/dist/index.js.map +1 -1
- package/package.json +3 -2
- package/src/components/combobox.tsx +127 -70
|
@@ -8,8 +8,11 @@ export interface ComboboxProps {
|
|
|
8
8
|
options: ComboboxOption[];
|
|
9
9
|
value?: string;
|
|
10
10
|
onChange: (value: string) => void;
|
|
11
|
+
/** Texto do gatilho quando nada está selecionado */
|
|
11
12
|
placeholder?: string;
|
|
13
|
+
/** Placeholder do campo de busca */
|
|
12
14
|
searchPlaceholder?: string;
|
|
15
|
+
/** Mensagem quando a busca não retorna nada */
|
|
13
16
|
emptyMessage?: string;
|
|
14
17
|
disabled?: boolean;
|
|
15
18
|
id?: string;
|
|
@@ -17,5 +20,15 @@ export interface ComboboxProps {
|
|
|
17
20
|
"aria-invalid"?: boolean | "true" | "false";
|
|
18
21
|
"aria-describedby"?: string;
|
|
19
22
|
}
|
|
23
|
+
/**
|
|
24
|
+
* Select com busca (combobox) acessível e responsivo.
|
|
25
|
+
*
|
|
26
|
+
* - Desktop: Popover (modal) + cmdk — o dropdown acompanha a largura do gatilho.
|
|
27
|
+
* - Mobile: Drawer (bottom sheet) + cmdk — evita os problemas de foco/clique de
|
|
28
|
+
* Popover dentro de modal no touch, então a busca funciona no celular.
|
|
29
|
+
*
|
|
30
|
+
* Aceita `aria-invalid`/`aria-describedby` (encaminhados pelo FormField em
|
|
31
|
+
* estado de erro) e fica com a borda vermelha quando inválido.
|
|
32
|
+
*/
|
|
20
33
|
export declare function Combobox({ options, value, onChange, placeholder, searchPlaceholder, emptyMessage, disabled, id, className, "aria-invalid": ariaInvalid, "aria-describedby": ariaDescribedby, }: ComboboxProps): React.JSX.Element;
|
|
21
34
|
//# sourceMappingURL=combobox.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"combobox.d.ts","sourceRoot":"","sources":["../../src/components/combobox.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;
|
|
1
|
+
{"version":3,"file":"combobox.d.ts","sourceRoot":"","sources":["../../src/components/combobox.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAI9B,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,MAAM,CAAA;IACb,KAAK,EAAE,MAAM,CAAA;IACb,QAAQ,CAAC,EAAE,OAAO,CAAA;CACnB;AAED,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,cAAc,EAAE,CAAA;IACzB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAA;IACjC,oDAAoD;IACpD,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,oCAAoC;IACpC,iBAAiB,CAAC,EAAE,MAAM,CAAA;IAC1B,+CAA+C;IAC/C,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,EAAE,CAAC,EAAE,MAAM,CAAA;IACX,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,cAAc,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,OAAO,CAAA;IAC3C,kBAAkB,CAAC,EAAE,MAAM,CAAA;CAC5B;AAsBD;;;;;;;;;GASG;AACH,wBAAgB,QAAQ,CAAC,EACvB,OAAO,EACP,KAAK,EACL,QAAQ,EACR,WAA4B,EAC5B,iBAA+B,EAC/B,YAA6C,EAC7C,QAAQ,EACR,EAAE,EACF,SAAS,EACT,cAAc,EAAE,WAAW,EAC3B,kBAAkB,EAAE,eAAe,GACpC,EAAE,aAAa,qBAgGf"}
|
package/dist/index.cjs
CHANGED
|
@@ -615,7 +615,22 @@ var PopoverPrimitive = __toESM(require("@radix-ui/react-popover"), 1);
|
|
|
615
615
|
var import_cmdk = require("cmdk");
|
|
616
616
|
var import_lucide_react4 = require("lucide-react");
|
|
617
617
|
var React4 = __toESM(require("react"), 1);
|
|
618
|
+
var import_vaul = require("vaul");
|
|
618
619
|
var import_jsx_runtime16 = require("react/jsx-runtime");
|
|
620
|
+
var DESKTOP_QUERY = "(min-width: 640px)";
|
|
621
|
+
function useIsDesktop() {
|
|
622
|
+
const [isDesktop, setIsDesktop] = React4.useState(
|
|
623
|
+
() => typeof window !== "undefined" ? window.matchMedia(DESKTOP_QUERY).matches : true
|
|
624
|
+
);
|
|
625
|
+
React4.useEffect(() => {
|
|
626
|
+
const mql = window.matchMedia(DESKTOP_QUERY);
|
|
627
|
+
const onChange = () => setIsDesktop(mql.matches);
|
|
628
|
+
onChange();
|
|
629
|
+
mql.addEventListener("change", onChange);
|
|
630
|
+
return () => mql.removeEventListener("change", onChange);
|
|
631
|
+
}, []);
|
|
632
|
+
return isDesktop;
|
|
633
|
+
}
|
|
619
634
|
function Combobox({
|
|
620
635
|
options,
|
|
621
636
|
value,
|
|
@@ -630,83 +645,93 @@ function Combobox({
|
|
|
630
645
|
"aria-describedby": ariaDescribedby
|
|
631
646
|
}) {
|
|
632
647
|
const [open, setOpen] = React4.useState(false);
|
|
648
|
+
const isDesktop = useIsDesktop();
|
|
633
649
|
const selected = options.find((option) => option.value === value);
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
children:
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
650
|
+
const trigger = /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
|
|
651
|
+
"button",
|
|
652
|
+
{
|
|
653
|
+
type: "button",
|
|
654
|
+
id,
|
|
655
|
+
role: "combobox",
|
|
656
|
+
"aria-expanded": open,
|
|
657
|
+
"aria-invalid": ariaInvalid,
|
|
658
|
+
"aria-describedby": ariaDescribedby,
|
|
659
|
+
disabled,
|
|
660
|
+
className: cn(
|
|
661
|
+
"flex h-9 w-full cursor-pointer items-center justify-between gap-2 rounded-md border border-input bg-transparent px-3 py-2 text-sm shadow-sm transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:border-destructive aria-invalid:focus-visible:ring-destructive",
|
|
662
|
+
className
|
|
663
|
+
),
|
|
664
|
+
children: [
|
|
665
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: cn("truncate", !selected && "text-muted-foreground"), children: selected ? selected.label : placeholder }),
|
|
666
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_lucide_react4.ChevronsUpDown, { className: "h-4 w-4 shrink-0 opacity-50" })
|
|
667
|
+
]
|
|
668
|
+
}
|
|
669
|
+
);
|
|
670
|
+
const command = /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(import_cmdk.Command, { className: "flex h-full w-full flex-col overflow-hidden", children: [
|
|
671
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "flex items-center border-b px-3", children: [
|
|
672
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_lucide_react4.Search, { className: "mr-2 h-4 w-4 shrink-0 opacity-50" }),
|
|
673
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
674
|
+
import_cmdk.Command.Input,
|
|
675
|
+
{
|
|
676
|
+
placeholder: searchPlaceholder,
|
|
677
|
+
className: "flex h-11 w-full bg-transparent py-2 text-base outline-none placeholder:text-muted-foreground sm:h-9 sm:text-sm"
|
|
678
|
+
}
|
|
679
|
+
)
|
|
680
|
+
] }),
|
|
681
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(import_cmdk.Command.List, { className: "max-h-[50vh] overflow-y-auto overflow-x-hidden p-1 sm:max-h-60", children: [
|
|
682
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_cmdk.Command.Empty, { className: "py-6 text-center text-sm text-muted-foreground", children: emptyMessage }),
|
|
683
|
+
options.map((option) => /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
|
|
684
|
+
import_cmdk.Command.Item,
|
|
685
|
+
{
|
|
686
|
+
value: option.label,
|
|
687
|
+
disabled: option.disabled,
|
|
688
|
+
onSelect: () => {
|
|
689
|
+
onChange(option.value);
|
|
690
|
+
setOpen(false);
|
|
691
|
+
},
|
|
692
|
+
className: "relative flex cursor-pointer select-none items-center gap-2 rounded-sm px-2 py-2.5 text-sm outline-none data-[selected=true]:bg-accent data-[selected=true]:text-accent-foreground data-[disabled=true]:pointer-events-none data-[disabled=true]:opacity-50 sm:py-1.5",
|
|
693
|
+
children: [
|
|
671
694
|
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
672
|
-
|
|
695
|
+
import_lucide_react4.Check,
|
|
673
696
|
{
|
|
674
|
-
|
|
675
|
-
|
|
697
|
+
className: cn(
|
|
698
|
+
"h-4 w-4 shrink-0",
|
|
699
|
+
value === option.value ? "opacity-100" : "opacity-0"
|
|
700
|
+
)
|
|
676
701
|
}
|
|
677
|
-
)
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
}
|
|
709
|
-
|
|
702
|
+
),
|
|
703
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "truncate", children: option.label })
|
|
704
|
+
]
|
|
705
|
+
},
|
|
706
|
+
option.value
|
|
707
|
+
))
|
|
708
|
+
] })
|
|
709
|
+
] });
|
|
710
|
+
if (isDesktop) {
|
|
711
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(PopoverPrimitive.Root, { open, onOpenChange: setOpen, modal: true, children: [
|
|
712
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(PopoverPrimitive.Trigger, { asChild: true, children: trigger }),
|
|
713
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(PopoverPrimitive.Portal, { children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
714
|
+
PopoverPrimitive.Content,
|
|
715
|
+
{
|
|
716
|
+
align: "start",
|
|
717
|
+
sideOffset: 4,
|
|
718
|
+
className: "z-50 overflow-hidden rounded-md border bg-popover p-0 text-popover-foreground shadow-md",
|
|
719
|
+
style: { width: "var(--radix-popover-trigger-width)" },
|
|
720
|
+
children: command
|
|
721
|
+
}
|
|
722
|
+
) })
|
|
723
|
+
] });
|
|
724
|
+
}
|
|
725
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(import_vaul.Drawer.Root, { open, onOpenChange: setOpen, children: [
|
|
726
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_vaul.Drawer.Trigger, { asChild: true, children: trigger }),
|
|
727
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(import_vaul.Drawer.Portal, { children: [
|
|
728
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_vaul.Drawer.Overlay, { className: "fixed inset-0 z-50 bg-black/80" }),
|
|
729
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(import_vaul.Drawer.Content, { className: "fixed inset-x-0 bottom-0 z-50 mt-24 flex max-h-[85vh] flex-col rounded-t-2xl border bg-popover text-popover-foreground outline-none", children: [
|
|
730
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_vaul.Drawer.Title, { className: "sr-only", children: placeholder }),
|
|
731
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { className: "mx-auto my-3 h-1.5 w-12 shrink-0 rounded-full bg-muted" }),
|
|
732
|
+
command
|
|
733
|
+
] })
|
|
734
|
+
] })
|
|
710
735
|
] });
|
|
711
736
|
}
|
|
712
737
|
|