@motor-hero/ui-kit 0.24.0 → 0.25.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.
@@ -31,6 +31,12 @@ export interface ComboboxProps {
31
31
  /** Modo servidor: rótulo do valor já selecionado que pode não estar na
32
32
  * página carregada (ex.: formulário de edição). */
33
33
  selectedOption?: ComboboxOption;
34
+ /** Permite confirmar o texto digitado como valor, mesmo fora da lista
35
+ * (ex.: unidade de medida com texto livre). Mostra uma linha "criar" no
36
+ * topo e exibe o valor personalizado no gatilho. */
37
+ creatable?: boolean;
38
+ /** Rótulo da linha de criação. Padrão: `Usar "<texto>"`. */
39
+ formatCreateLabel?: (search: string) => string;
34
40
  }
35
41
  /**
36
42
  * Select com busca (combobox) acessível e responsivo.
@@ -46,5 +52,5 @@ export interface ComboboxProps {
46
52
  * Aceita `aria-invalid`/`aria-describedby` (encaminhados pelo FormField em
47
53
  * estado de erro) e fica com a borda vermelha quando inválido.
48
54
  */
49
- export declare function Combobox({ options, value, onChange, placeholder, searchPlaceholder, emptyMessage, disabled, id, className, "aria-invalid": ariaInvalid, "aria-describedby": ariaDescribedby, onSearchChange, onLoadMore, loading, hasMore, selectedOption, }: ComboboxProps): React.JSX.Element;
55
+ export declare function Combobox({ options, value, onChange, placeholder, searchPlaceholder, emptyMessage, disabled, id, className, "aria-invalid": ariaInvalid, "aria-describedby": ariaDescribedby, onSearchChange, onLoadMore, loading, hasMore, selectedOption, creatable, formatCreateLabel, }: ComboboxProps): React.JSX.Element;
50
56
  //# 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;AAM9B,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;IAC3B;qEACiE;IACjE,cAAc,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAA;IACzC,0DAA0D;IAC1D,UAAU,CAAC,EAAE,MAAM,IAAI,CAAA;IACvB,uEAAuE;IACvE,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,yDAAyD;IACzD,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB;wDACoD;IACpD,cAAc,CAAC,EAAE,cAAc,CAAA;CAChC;AAED;;;;;;;;;;;;;GAaG;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,EACnC,cAAc,EACd,UAAU,EACV,OAAO,EACP,OAAO,EACP,cAAc,GACf,EAAE,aAAa,qBAiIf"}
1
+ {"version":3,"file":"combobox.d.ts","sourceRoot":"","sources":["../../src/components/combobox.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAM9B,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;IAC3B;qEACiE;IACjE,cAAc,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAA;IACzC,0DAA0D;IAC1D,UAAU,CAAC,EAAE,MAAM,IAAI,CAAA;IACvB,uEAAuE;IACvE,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,yDAAyD;IACzD,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB;wDACoD;IACpD,cAAc,CAAC,EAAE,cAAc,CAAA;IAC/B;;yDAEqD;IACrD,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,4DAA4D;IAC5D,iBAAiB,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,MAAM,CAAA;CAC/C;AAED;;;;;;;;;;;;;GAaG;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,EACnC,cAAc,EACd,UAAU,EACV,OAAO,EACP,OAAO,EACP,cAAc,EACd,SAAS,EACT,iBAAiB,GAClB,EAAE,aAAa,qBAwKf"}
package/dist/index.cjs CHANGED
@@ -762,12 +762,31 @@ function Combobox({
762
762
  onLoadMore,
763
763
  loading,
764
764
  hasMore,
765
- selectedOption
765
+ selectedOption,
766
+ creatable,
767
+ formatCreateLabel
766
768
  }) {
767
769
  const [open, setOpen] = React6.useState(false);
770
+ const [search, setSearch] = React6.useState("");
768
771
  const isDesktop = useIsDesktop();
769
772
  const isServer = onSearchChange !== void 0;
770
- const selected = selectedOption?.value === value ? selectedOption : options.find((option) => option.value === value);
773
+ const selected = selectedOption?.value === value ? selectedOption : options.find((option) => option.value === value) ?? (creatable && value ? { value, label: value } : void 0);
774
+ const handleOpenChange = (next) => {
775
+ setOpen(next);
776
+ if (!next) setSearch("");
777
+ };
778
+ const handleSelect = (next) => {
779
+ onChange(next);
780
+ handleOpenChange(false);
781
+ };
782
+ const handleSearchChange = (next) => {
783
+ setSearch(next);
784
+ onSearchChange?.(next);
785
+ };
786
+ const trimmedSearch = search.trim();
787
+ const showCreate = !!creatable && trimmedSearch.length > 0 && !options.some(
788
+ (option) => option.value.toLowerCase() === trimmedSearch.toLowerCase()
789
+ );
771
790
  const { listRef, sentinelRef } = useInfiniteScrollSentinel({
772
791
  enabled: isServer && !!hasMore,
773
792
  loading,
@@ -805,7 +824,7 @@ function Combobox({
805
824
  import_cmdk.Command.Input,
806
825
  {
807
826
  placeholder: searchPlaceholder,
808
- onValueChange: isServer ? onSearchChange : void 0,
827
+ onValueChange: isServer || creatable ? handleSearchChange : void 0,
809
828
  className: "flex h-11 w-full bg-transparent py-2 text-base outline-none placeholder:text-muted-foreground sm:h-9 sm:text-sm"
810
829
  }
811
830
  )
@@ -816,16 +835,27 @@ function Combobox({
816
835
  ref: listRef,
817
836
  className: "max-h-[50vh] overflow-y-auto overflow-x-hidden p-1 sm:max-h-60",
818
837
  children: [
819
- !isServer && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_cmdk.Command.Empty, { className: "py-6 text-center text-sm text-muted-foreground", children: emptyMessage }),
838
+ !isServer && !showCreate && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_cmdk.Command.Empty, { className: "py-6 text-center text-sm text-muted-foreground", children: emptyMessage }),
839
+ showCreate && /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
840
+ import_cmdk.Command.Item,
841
+ {
842
+ value: trimmedSearch,
843
+ onSelect: () => handleSelect(trimmedSearch),
844
+ 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 sm:py-1.5",
845
+ children: [
846
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_lucide_react4.Plus, { className: "h-4 w-4 shrink-0" }),
847
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "truncate", children: (formatCreateLabel ?? ((text) => `Usar "${text}"`))(
848
+ trimmedSearch
849
+ ) })
850
+ ]
851
+ }
852
+ ),
820
853
  options.map((option) => /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
821
854
  import_cmdk.Command.Item,
822
855
  {
823
856
  value: isServer ? option.value : option.label,
824
857
  disabled: option.disabled,
825
- onSelect: () => {
826
- onChange(option.value);
827
- setOpen(false);
828
- },
858
+ onSelect: () => handleSelect(option.value),
829
859
  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",
830
860
  children: [
831
861
  /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
@@ -852,7 +882,7 @@ function Combobox({
852
882
  }
853
883
  );
854
884
  if (isDesktop) {
855
- return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(PopoverPrimitive.Root, { open, onOpenChange: setOpen, children: [
885
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(PopoverPrimitive.Root, { open, onOpenChange: handleOpenChange, children: [
856
886
  /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(PopoverPrimitive.Trigger, { asChild: true, children: trigger }),
857
887
  /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(PopoverPrimitive.Portal, { children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
858
888
  PopoverPrimitive.Content,
@@ -866,7 +896,7 @@ function Combobox({
866
896
  ) })
867
897
  ] });
868
898
  }
869
- return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(import_vaul.Drawer.Root, { open, onOpenChange: setOpen, children: [
899
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(import_vaul.Drawer.Root, { open, onOpenChange: handleOpenChange, children: [
870
900
  /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_vaul.Drawer.Trigger, { asChild: true, children: trigger }),
871
901
  /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(import_vaul.Drawer.Portal, { children: [
872
902
  /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_vaul.Drawer.Overlay, { className: "fixed inset-0 z-50 bg-black/80" }),