@iclips/ui 2.0.2 → 3.0.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.
Files changed (122) hide show
  1. package/MIGRATION-v3.md +244 -0
  2. package/README.md +1 -1
  3. package/dist/alert-theme.css +20 -79
  4. package/dist/components/ui/charts/donut-chart.cjs +1 -1
  5. package/dist/components/ui/charts/donut-chart.cjs.map +1 -1
  6. package/dist/components/ui/charts/donut-chart.js +39 -60
  7. package/dist/components/ui/charts/donut-chart.js.map +1 -1
  8. package/dist/components/ui/charts/kpi-card.cjs +1 -1
  9. package/dist/components/ui/charts/kpi-card.cjs.map +1 -1
  10. package/dist/components/ui/charts/kpi-card.js +19 -19
  11. package/dist/components/ui/charts/kpi-card.js.map +1 -1
  12. package/dist/components/ui/data/comment-system.cjs +1 -1
  13. package/dist/components/ui/data/comment-system.cjs.map +1 -1
  14. package/dist/components/ui/data/comment-system.js +67 -67
  15. package/dist/components/ui/data/comment-system.js.map +1 -1
  16. package/dist/components/ui/data/data-table.cjs +1 -1
  17. package/dist/components/ui/data/data-table.cjs.map +1 -1
  18. package/dist/components/ui/data/data-table.js +112 -101
  19. package/dist/components/ui/data/data-table.js.map +1 -1
  20. package/dist/components/ui/data/editorial-calendar.cjs +1 -1
  21. package/dist/components/ui/data/editorial-calendar.cjs.map +1 -1
  22. package/dist/components/ui/data/editorial-calendar.js +291 -291
  23. package/dist/components/ui/data/editorial-calendar.js.map +1 -1
  24. package/dist/components/ui/data/filter-builder.cjs +1 -1
  25. package/dist/components/ui/data/filter-builder.cjs.map +1 -1
  26. package/dist/components/ui/data/filter-builder.js +1 -1
  27. package/dist/components/ui/data/filter-builder.js.map +1 -1
  28. package/dist/components/ui/feedback/empty-state.cjs +1 -1
  29. package/dist/components/ui/feedback/empty-state.cjs.map +1 -1
  30. package/dist/components/ui/feedback/empty-state.js +14 -14
  31. package/dist/components/ui/feedback/empty-state.js.map +1 -1
  32. package/dist/components/ui/feedback/toast.cjs +1 -1
  33. package/dist/components/ui/feedback/toast.cjs.map +1 -1
  34. package/dist/components/ui/feedback/toast.js +53 -22
  35. package/dist/components/ui/feedback/toast.js.map +1 -1
  36. package/dist/components/ui/forms/calendar.cjs +1 -1
  37. package/dist/components/ui/forms/calendar.cjs.map +1 -1
  38. package/dist/components/ui/forms/calendar.js +16 -16
  39. package/dist/components/ui/forms/calendar.js.map +1 -1
  40. package/dist/components/ui/forms/combobox.cjs +1 -1
  41. package/dist/components/ui/forms/combobox.cjs.map +1 -1
  42. package/dist/components/ui/forms/combobox.js +78 -76
  43. package/dist/components/ui/forms/combobox.js.map +1 -1
  44. package/dist/components/ui/forms/file-attachment-list.cjs +1 -1
  45. package/dist/components/ui/forms/file-attachment-list.cjs.map +1 -1
  46. package/dist/components/ui/forms/file-attachment-list.js +4 -4
  47. package/dist/components/ui/forms/file-attachment-list.js.map +1 -1
  48. package/dist/components/ui/forms/file-upload-zone.cjs +2 -2
  49. package/dist/components/ui/forms/file-upload-zone.cjs.map +1 -1
  50. package/dist/components/ui/forms/file-upload-zone.js +55 -49
  51. package/dist/components/ui/forms/file-upload-zone.js.map +1 -1
  52. package/dist/components/ui/forms/form.cjs +1 -1
  53. package/dist/components/ui/forms/form.cjs.map +1 -1
  54. package/dist/components/ui/forms/form.js +11 -11
  55. package/dist/components/ui/forms/form.js.map +1 -1
  56. package/dist/components/ui/forms/input-validation.cjs +1 -1
  57. package/dist/components/ui/forms/input-validation.cjs.map +1 -1
  58. package/dist/components/ui/forms/input-validation.js +20 -20
  59. package/dist/components/ui/forms/input-validation.js.map +1 -1
  60. package/dist/components/ui/forms/multi-select.cjs +1 -1
  61. package/dist/components/ui/forms/multi-select.cjs.map +1 -1
  62. package/dist/components/ui/forms/multi-select.js +69 -67
  63. package/dist/components/ui/forms/multi-select.js.map +1 -1
  64. package/dist/components/ui/forms/radio-group.cjs +1 -1
  65. package/dist/components/ui/forms/radio-group.cjs.map +1 -1
  66. package/dist/components/ui/forms/radio-group.js +19 -19
  67. package/dist/components/ui/forms/radio-group.js.map +1 -1
  68. package/dist/components/ui/forms/social-button.cjs +1 -1
  69. package/dist/components/ui/forms/social-button.cjs.map +1 -1
  70. package/dist/components/ui/forms/social-button.js +6 -6
  71. package/dist/components/ui/forms/social-button.js.map +1 -1
  72. package/dist/components/ui/forms/toggle.cjs +1 -1
  73. package/dist/components/ui/forms/toggle.cjs.map +1 -1
  74. package/dist/components/ui/forms/toggle.js +7 -7
  75. package/dist/components/ui/forms/toggle.js.map +1 -1
  76. package/dist/components/ui/navigation/navigation-menu.cjs +1 -1
  77. package/dist/components/ui/navigation/navigation-menu.cjs.map +1 -1
  78. package/dist/components/ui/navigation/navigation-menu.js +14 -14
  79. package/dist/components/ui/navigation/navigation-menu.js.map +1 -1
  80. package/dist/components/ui/navigation/sidebar.cjs +1 -1
  81. package/dist/components/ui/navigation/sidebar.cjs.map +1 -1
  82. package/dist/components/ui/navigation/sidebar.js +44 -44
  83. package/dist/components/ui/navigation/sidebar.js.map +1 -1
  84. package/dist/components/ui/overlays/context-menu.cjs +1 -1
  85. package/dist/components/ui/overlays/context-menu.cjs.map +1 -1
  86. package/dist/components/ui/overlays/context-menu.js +1 -1
  87. package/dist/components/ui/overlays/context-menu.js.map +1 -1
  88. package/dist/components/ui/overlays/dropdown-menu.cjs +1 -1
  89. package/dist/components/ui/overlays/dropdown-menu.cjs.map +1 -1
  90. package/dist/components/ui/overlays/dropdown-menu.js +5 -5
  91. package/dist/components/ui/overlays/dropdown-menu.js.map +1 -1
  92. package/dist/components/ui/overlays/menubar.cjs +1 -1
  93. package/dist/components/ui/overlays/menubar.cjs.map +1 -1
  94. package/dist/components/ui/overlays/menubar.js +29 -29
  95. package/dist/components/ui/overlays/menubar.js.map +1 -1
  96. package/dist/components/ui/overlays/tooltip.cjs +1 -1
  97. package/dist/components/ui/overlays/tooltip.cjs.map +1 -1
  98. package/dist/components/ui/overlays/tooltip.js +12 -12
  99. package/dist/components/ui/overlays/tooltip.js.map +1 -1
  100. package/dist/components/ui/primitives/avatar.cjs +1 -1
  101. package/dist/components/ui/primitives/avatar.cjs.map +1 -1
  102. package/dist/components/ui/primitives/avatar.js +20 -27
  103. package/dist/components/ui/primitives/avatar.js.map +1 -1
  104. package/dist/components/ui/primitives/badge.cjs +1 -1
  105. package/dist/components/ui/primitives/badge.cjs.map +1 -1
  106. package/dist/components/ui/primitives/badge.js +13 -13
  107. package/dist/components/ui/primitives/badge.js.map +1 -1
  108. package/dist/components/ui/primitives/button.cjs +1 -1
  109. package/dist/components/ui/primitives/button.cjs.map +1 -1
  110. package/dist/components/ui/primitives/button.js +11 -8
  111. package/dist/components/ui/primitives/button.js.map +1 -1
  112. package/dist/index.cjs +1 -1
  113. package/dist/index.css +1 -1
  114. package/dist/index.d.cts +3 -3
  115. package/dist/index.d.ts +3 -3
  116. package/dist/index.js +34 -35
  117. package/dist/index.js.map +1 -1
  118. package/dist/preset.css +1 -2
  119. package/dist/toast-theme.css +100 -64
  120. package/dist/tokens.css +59 -159
  121. package/package.json +5 -3
  122. package/scripts/check-colors.mjs +208 -0
@@ -1 +1 @@
1
- {"version":3,"file":"multi-select.cjs","sources":["../../../../src/components/ui/forms/multi-select.tsx"],"sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\nimport { Check, ChevronsUpDown, X, Search, Loader2, Plus } from \"lucide-react\";\nimport { cn, mergeRefs, pressableKeyDown } from \"../utils\";\nimport { Button } from \"../primitives/button\";\nimport { Badge } from \"../primitives/badge\";\nimport { Popover, PopoverContent, PopoverTrigger } from \"../overlays/popover\";\nimport { Input } from \"./input\";\n\nexport interface MultiSelectOption {\n value: string;\n label: string;\n disabled?: boolean;\n /** Slot para renderização customizada à direita do label — ex: <Badge>Externo</Badge> */\n badge?: React.ReactNode;\n}\n\nexport interface MultiSelectGroup {\n label: string;\n options: MultiSelectOption[];\n /** Quando presente, o header do grupo torna-se clicável e seleciona/deseleciona o grupo */\n value?: string;\n}\n\nexport interface MultiSelectProps {\n /** Valores atualmente selecionados */\n value: string[];\n /** Callback disparado ao alterar a seleção */\n onValueChange: (values: string[]) => void;\n\n /**\n * Opções em lista plana.\n * Use `options` OU `groups` — nunca os dois ao mesmo tempo.\n */\n options?: MultiSelectOption[];\n /**\n * Opções agrupadas hierarquicamente.\n * Use `options` OU `groups` — nunca os dois ao mesmo tempo.\n */\n groups?: MultiSelectGroup[];\n\n placeholder?: string;\n searchPlaceholder?: string;\n emptyMessage?: string;\n\n /** Rótulo acessível do gatilho quando não há `<Label>` associado */\n \"aria-label\"?: string;\n \"aria-labelledby\"?: string;\n\n disabled?: boolean;\n /** Exibe estado de carregamento — substitui a lista por spinner */\n loading?: boolean;\n\n /**\n * Número máximo de chips visíveis no trigger antes de exibir \"+N\".\n * @default 2\n */\n maxVisibleChips?: number;\n\n /**\n * Callback de busca assíncrona — chamado a cada keystroke e ao abrir o dropdown.\n * Quando presente, a filtragem local é desativada (o caller controla `options`/`groups`).\n */\n onSearch?: (query: string) => void;\n\n /**\n * Habilita criação de uma nova opção diretamente no dropdown.\n * Chamado quando o usuário clica em \"Criar '{busca}'\" — o caller é responsável por\n * persistir a opção (ex: chamada de API), atualizar `options`/`value` com o resultado\n * e sinalizar falhas ao usuário (ex: toast). Rejeitar a promise preserva o termo\n * buscado no campo, permitindo corrigir e tentar novamente.\n * Exibido apenas quando não há opção com label idêntico ao termo buscado.\n */\n onCreateOption?: (inputValue: string) => void | Promise<void>;\n /** Customiza o label do botão de criação. @default (query) => `Criar \"${query}\"` */\n createOptionLabel?: (query: string) => string;\n\n className?: string;\n}\n\n/**\n * MultiSelect — Seleção múltipla com chips, busca, grupos hierárquicos e slots de badge por opção.\n *\n * @example\n * ```tsx\n * // Lista plana\n * <MultiSelect\n * value={selectedSquads}\n * onValueChange={setSelectedSquads}\n * options={squads.map(s => ({ value: String(s.id), label: s.name }))}\n * placeholder=\"Selecione os squads\"\n * />\n *\n * // Com badge por opção (ex: funcionários externos)\n * <MultiSelect\n * value={selectedEmployees}\n * onValueChange={setSelectedEmployees}\n * options={employees.map(e => ({\n * value: String(e.id),\n * label: e.name,\n * badge: e.isExternalUser\n * ? <Badge variant=\"secondary\" className=\"text-xs\">Externo</Badge>\n * : undefined,\n * }))}\n * />\n *\n * // Lista hierárquica (grupos de clientes)\n * <MultiSelect\n * value={selectedClients}\n * onValueChange={setSelectedClients}\n * groups={customerGroups.map(g => ({\n * label: g.name,\n * options: g.children.map(c => ({ value: String(c.id), label: c.name })),\n * }))}\n * />\n * ```\n */\nexport const MultiSelect = React.forwardRef<\n React.ElementRef<typeof Button>,\n MultiSelectProps\n>(({\n value,\n onValueChange,\n options,\n groups,\n placeholder = \"Selecione...\",\n searchPlaceholder = \"Buscar...\",\n emptyMessage = \"Nenhum resultado encontrado\",\n disabled = false,\n loading = false,\n maxVisibleChips = 2,\n onSearch,\n onCreateOption,\n createOptionLabel,\n className,\n \"aria-label\": ariaLabel,\n \"aria-labelledby\": ariaLabelledby,\n}, ref) => {\n const [open, setOpen] = React.useState(false);\n const [search, setSearch] = React.useState(\"\");\n const [isCreating, setIsCreating] = React.useState(false);\n const triggerRef = React.useRef<HTMLButtonElement>(null);\n const searchInputRef = React.useRef<HTMLInputElement>(null);\n const mergedTriggerRef = React.useMemo(() => mergeRefs(triggerRef, ref), [ref]);\n\n // Callback ref: chamado imediatamente ao montar o elemento (sem timing issue do useEffect).\n // Para a propagação nativa do wheel antes de chegar ao document, onde o\n // react-remove-scroll do Sheet chama preventDefault() em eventos de Portal.\n const listCallbackRef = React.useCallback((el: HTMLDivElement | null) => {\n if (!el) return;\n el.addEventListener(\"wheel\", (e) => e.stopPropagation(), { passive: true });\n }, []);\n\n const allOptions = React.useMemo((): MultiSelectOption[] => {\n if (options) return options;\n if (groups) {\n const groupHeaders: MultiSelectOption[] = groups\n .filter((g) => g.value != null)\n .map((g) => ({ value: g.value!, label: g.label }));\n return [...groupHeaders, ...groups.flatMap((g) => g.options)];\n }\n return [];\n }, [options, groups]);\n\n const isAsyncSearch = !!onSearch;\n\n const filteredOptions = React.useMemo(() => {\n if (!options) return [];\n if (isAsyncSearch) return options;\n const term = search.toLowerCase().trim();\n if (!term) return options;\n return options.filter(\n (o) =>\n o.label.toLowerCase().includes(term) ||\n o.value.toLowerCase().includes(term)\n );\n }, [options, search, isAsyncSearch]);\n\n const filteredGroups = React.useMemo(() => {\n if (!groups) return undefined;\n if (isAsyncSearch) return groups;\n const term = search.toLowerCase().trim();\n if (!term) return groups;\n return groups\n .map((g) => ({\n ...g,\n options: g.options.filter(\n (o) =>\n o.label.toLowerCase().includes(term) ||\n o.value.toLowerCase().includes(term)\n ),\n }))\n .filter((g) => g.options.length > 0);\n }, [groups, search, isAsyncSearch]);\n\n const selectedOptions = React.useMemo(\n () => allOptions.filter((o) => value.includes(o.value)),\n [allOptions, value]\n );\n\n const hasResults = groups\n ? (filteredGroups?.some((g) => g.options.length > 0) ?? false)\n : filteredOptions.length > 0;\n\n const trimmedSearch = search.trim();\n const hasExactMatch = allOptions.some(\n (o) => o.label.trim().toLowerCase() === trimmedSearch.toLowerCase()\n );\n const canCreate = !!onCreateOption && trimmedSearch.length > 0 && !hasExactMatch;\n\n const handleCreate = async () => {\n if (!onCreateOption || isCreating || !trimmedSearch) return;\n setIsCreating(true);\n try {\n await onCreateOption(trimmedSearch);\n setSearch(\"\");\n } catch {\n // Falha na criação: mantém o termo buscado para o usuário corrigir e tentar\n // novamente. O caller é responsável por sinalizar o erro (ex: toast).\n } finally {\n setIsCreating(false);\n }\n };\n\n const handleToggle = (optionValue: string) => {\n if (value.includes(optionValue)) {\n onValueChange(value.filter((v) => v !== optionValue));\n } else {\n onValueChange([...value, optionValue]);\n }\n };\n\n const handleRemoveChip = (optionValue: string, e: React.MouseEvent) => {\n e.stopPropagation();\n onValueChange(value.filter((v) => v !== optionValue));\n };\n\n const handleOpenChange = (next: boolean) => {\n if (disabled) return;\n setOpen(next);\n if (!next) setSearch(\"\");\n };\n\n React.useEffect(() => {\n if (open) onSearch?.(\"\");\n }, [open]);\n\n const handleSearchChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n setSearch(e.target.value);\n onSearch?.(e.target.value);\n };\n\n const visibleChips = selectedOptions.slice(0, maxVisibleChips);\n const overflowCount = selectedOptions.length - maxVisibleChips;\n\n const renderOption = (option: MultiSelectOption) => {\n const selected = value.includes(option.value);\n return (\n <button\n key={option.value}\n type=\"button\"\n role=\"option\"\n aria-selected={selected}\n disabled={option.disabled}\n onClick={() => handleToggle(option.value)}\n className={cn(\n \"flex w-full items-center gap-2 rounded-sm px-2 py-1.5 text-sm\",\n \"hover:bg-accent hover:text-accent-foreground\",\n \"focus:bg-accent focus:text-accent-foreground focus:outline-none\",\n \"transition-colors duration-100\",\n option.disabled && \"pointer-events-none opacity-50\"\n )}\n >\n <Check\n className={cn(\n \"h-4 w-4 shrink-0 transition-opacity duration-100\",\n selected ? \"opacity-100\" : \"opacity-0\"\n )}\n />\n <span className=\"flex-1 text-left truncate\">{option.label}</span>\n {option.badge}\n </button>\n );\n };\n\n return (\n <Popover open={open} onOpenChange={handleOpenChange}>\n <PopoverTrigger asChild>\n <Button\n ref={mergedTriggerRef}\n type=\"button\"\n variant=\"outline\"\n role=\"combobox\"\n aria-expanded={open}\n aria-label={ariaLabel}\n aria-labelledby={ariaLabelledby}\n disabled={disabled}\n className={cn(\n \"w-full min-h-10 h-auto justify-between font-normal px-3 py-2\",\n !value.length && \"text-muted-foreground\",\n className\n )}\n >\n <div className=\"flex flex-wrap items-center gap-1 flex-1 min-w-0\">\n {value.length === 0 ? (\n <span className=\"truncate text-sm\">\n {loading ? \"Carregando...\" : placeholder}\n </span>\n ) : (\n <>\n {visibleChips.map((opt) => (\n <Badge\n key={opt.value}\n variant=\"secondary\"\n className=\"rounded-sm h-5 gap-0.5 pr-1 font-normal max-w-[160px]\"\n >\n <span className=\"truncate text-xs\">{opt.label}</span>\n <span\n role=\"button\"\n tabIndex={0}\n aria-label={`Remover ${opt.label}`}\n className=\"inline-flex items-center justify-center rounded-sm hover:bg-muted/80 cursor-pointer shrink-0 outline-none focus-visible:ring-2 focus-visible:ring-ring/60\"\n onMouseDown={(e) => e.preventDefault()}\n onClick={(e) => handleRemoveChip(opt.value, e)}\n onKeyDown={pressableKeyDown}\n >\n <X className=\"h-3 w-3\" />\n </span>\n </Badge>\n ))}\n {overflowCount > 0 && (\n <Badge\n variant=\"secondary\"\n className=\"rounded-sm h-5 px-1.5 font-normal text-xs shrink-0\"\n >\n +{overflowCount}\n </Badge>\n )}\n </>\n )}\n </div>\n <ChevronsUpDown className=\"ml-2 h-4 w-4 shrink-0 opacity-50\" />\n </Button>\n </PopoverTrigger>\n\n <PopoverContent\n className=\"p-0 overflow-hidden\"\n style={{\n width: triggerRef.current?.offsetWidth\n ? `${triggerRef.current.offsetWidth}px`\n : \"auto\",\n }}\n align=\"start\"\n onOpenAutoFocus={(e) => {\n // O Radix suprime o autofocus padrão quando este Popover está aninhado em um\n // Dialog/Sheet (o focus-trap do pai disputa o foco com o do Popover). Focamos\n // o input manualmente via ref assim que o conteúdo transiciona para visível.\n e.preventDefault();\n searchInputRef.current?.focus();\n }}\n onWheel={(e) => e.stopPropagation()}\n >\n {/* Busca */}\n <div className=\"flex items-center border-b px-3\">\n <Search className=\"mr-2 h-4 w-4 shrink-0 opacity-50\" />\n <Input\n ref={searchInputRef}\n placeholder={searchPlaceholder}\n value={search}\n onChange={handleSearchChange}\n className=\"h-10 border-0 focus-visible:ring-0 focus-visible:ring-offset-0 px-0\"\n />\n </div>\n\n {/* Criar nova opção */}\n {canCreate && (\n <button\n type=\"button\"\n onClick={handleCreate}\n disabled={isCreating}\n className={cn(\n \"flex w-full items-center gap-2 border-b px-3 py-2 text-sm text-primary\",\n \"hover:bg-accent transition-colors duration-100\",\n \"disabled:opacity-50 disabled:pointer-events-none\"\n )}\n >\n {isCreating ? (\n <Loader2 className=\"h-4 w-4 shrink-0 animate-spin\" />\n ) : (\n <Plus className=\"h-4 w-4 shrink-0\" />\n )}\n <span className=\"truncate\">\n {isCreating\n ? \"Criando...\"\n : (createOptionLabel?.(trimmedSearch) ?? `Criar \"${trimmedSearch}\"`)}\n </span>\n </button>\n )}\n\n {/* Lista */}\n <div ref={listCallbackRef} className=\"max-h-70 overflow-y-auto [&::-webkit-scrollbar]:w-2.5 [&::-webkit-scrollbar-track]:bg-transparent [&::-webkit-scrollbar-thumb]:rounded-full [&::-webkit-scrollbar-thumb]:bg-primary/30 [&::-webkit-scrollbar-thumb:hover]:bg-primary/50\">\n <div className=\"p-1\" role=\"listbox\" aria-multiselectable>\n {loading ? (\n <div className=\"flex items-center justify-center gap-2 py-6 text-sm text-muted-foreground\">\n <Loader2 className=\"h-4 w-4 animate-spin\" />\n Carregando...\n </div>\n ) : !hasResults ? (\n <div className=\"py-6 text-center text-sm text-muted-foreground\">\n {emptyMessage}\n </div>\n ) : groups ? (\n filteredGroups?.map((group) => (\n <div key={group.label}>\n {group.value ? (\n <button\n type=\"button\"\n onClick={() => handleToggle(group.value!)}\n className={cn(\n \"flex w-full items-center gap-2 rounded-sm px-2 py-1.5\",\n \"hover:bg-accent hover:text-accent-foreground transition-colors duration-100\",\n value.includes(group.value) && \"text-foreground\"\n )}\n >\n <Check\n className={cn(\n \"h-4 w-4 shrink-0 transition-opacity duration-100\",\n value.includes(group.value) ? \"opacity-100\" : \"opacity-0\"\n )}\n />\n <span className=\"text-xs font-semibold uppercase tracking-wide\">\n {group.label}\n </span>\n </button>\n ) : (\n <div className=\"px-2 py-1.5 text-xs font-semibold text-muted-foreground uppercase tracking-wide\">\n {group.label}\n </div>\n )}\n {group.options.map(renderOption)}\n </div>\n ))\n ) : (\n filteredOptions.map(renderOption)\n )}\n </div>\n </div>\n </PopoverContent>\n </Popover>\n );\n});\nMultiSelect.displayName = \"MultiSelect\";\n\nexport default MultiSelect;\n"],"names":["MultiSelect","React","value","onValueChange","options","groups","placeholder","searchPlaceholder","emptyMessage","disabled","loading","maxVisibleChips","onSearch","onCreateOption","createOptionLabel","className","ariaLabel","ariaLabelledby","ref","open","setOpen","search","setSearch","isCreating","setIsCreating","triggerRef","searchInputRef","mergedTriggerRef","mergeRefs","listCallbackRef","el","e","allOptions","g","isAsyncSearch","filteredOptions","term","o","filteredGroups","selectedOptions","hasResults","trimmedSearch","hasExactMatch","canCreate","handleCreate","handleToggle","optionValue","v","handleRemoveChip","handleOpenChange","next","handleSearchChange","visibleChips","overflowCount","renderOption","option","selected","jsxs","cn","jsx","Check","Popover","PopoverTrigger","Button","Fragment","opt","Badge","pressableKeyDown","X","ChevronsUpDown","PopoverContent","_a","Search","Input","Loader2","Plus","group"],"mappings":"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"}
1
+ {"version":3,"file":"multi-select.cjs","sources":["../../../../src/components/ui/forms/multi-select.tsx"],"sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\nimport { Check, ChevronsUpDown, X, Search, Loader2, Plus } from \"lucide-react\";\nimport { cn, mergeRefs, pressableKeyDown } from \"../utils\";\nimport { Button } from \"../primitives/button\";\nimport { Badge } from \"../primitives/badge\";\nimport { Popover, PopoverContent, PopoverTrigger } from \"../overlays/popover\";\nimport { Input } from \"./input\";\n\nexport interface MultiSelectOption {\n value: string;\n label: string;\n disabled?: boolean;\n /** Slot para renderização customizada à direita do label — ex: <Badge>Externo</Badge> */\n badge?: React.ReactNode;\n}\n\nexport interface MultiSelectGroup {\n label: string;\n options: MultiSelectOption[];\n /** Quando presente, o header do grupo torna-se clicável e seleciona/deseleciona o grupo */\n value?: string;\n}\n\nexport interface MultiSelectProps {\n /** Valores atualmente selecionados */\n value: string[];\n /** Callback disparado ao alterar a seleção */\n onValueChange: (values: string[]) => void;\n\n /**\n * Opções em lista plana.\n * Use `options` OU `groups` — nunca os dois ao mesmo tempo.\n */\n options?: MultiSelectOption[];\n /**\n * Opções agrupadas hierarquicamente.\n * Use `options` OU `groups` — nunca os dois ao mesmo tempo.\n */\n groups?: MultiSelectGroup[];\n\n placeholder?: string;\n searchPlaceholder?: string;\n emptyMessage?: string;\n\n /** Rótulo acessível do gatilho quando não há `<Label>` associado */\n \"aria-label\"?: string;\n \"aria-labelledby\"?: string;\n\n disabled?: boolean;\n /** Exibe estado de carregamento — substitui a lista por spinner */\n loading?: boolean;\n\n /**\n * Número máximo de chips visíveis no trigger antes de exibir \"+N\".\n * @default 2\n */\n maxVisibleChips?: number;\n\n /**\n * Callback de busca assíncrona — chamado a cada keystroke e ao abrir o dropdown.\n * Quando presente, a filtragem local é desativada (o caller controla `options`/`groups`).\n */\n onSearch?: (query: string) => void;\n\n /**\n * Habilita criação de uma nova opção diretamente no dropdown.\n * Chamado quando o usuário clica em \"Criar '{busca}'\" — o caller é responsável por\n * persistir a opção (ex: chamada de API), atualizar `options`/`value` com o resultado\n * e sinalizar falhas ao usuário (ex: toast). Rejeitar a promise preserva o termo\n * buscado no campo, permitindo corrigir e tentar novamente.\n * Exibido apenas quando não há opção com label idêntico ao termo buscado.\n */\n onCreateOption?: (inputValue: string) => void | Promise<void>;\n /** Customiza o label do botão de criação. @default (query) => `Criar \"${query}\"` */\n createOptionLabel?: (query: string) => string;\n\n className?: string;\n}\n\n/**\n * MultiSelect — Seleção múltipla com chips, busca, grupos hierárquicos e slots de badge por opção.\n *\n * @example\n * ```tsx\n * // Lista plana\n * <MultiSelect\n * value={selectedSquads}\n * onValueChange={setSelectedSquads}\n * options={squads.map(s => ({ value: String(s.id), label: s.name }))}\n * placeholder=\"Selecione os squads\"\n * />\n *\n * // Com badge por opção (ex: funcionários externos)\n * <MultiSelect\n * value={selectedEmployees}\n * onValueChange={setSelectedEmployees}\n * options={employees.map(e => ({\n * value: String(e.id),\n * label: e.name,\n * badge: e.isExternalUser\n * ? <Badge variant=\"secondary\" className=\"text-xs\">Externo</Badge>\n * : undefined,\n * }))}\n * />\n *\n * // Lista hierárquica (grupos de clientes)\n * <MultiSelect\n * value={selectedClients}\n * onValueChange={setSelectedClients}\n * groups={customerGroups.map(g => ({\n * label: g.name,\n * options: g.children.map(c => ({ value: String(c.id), label: c.name })),\n * }))}\n * />\n * ```\n */\nexport const MultiSelect = React.forwardRef<\n React.ElementRef<typeof Button>,\n MultiSelectProps\n>(({\n value,\n onValueChange,\n options,\n groups,\n placeholder = \"Selecione...\",\n searchPlaceholder = \"Buscar...\",\n emptyMessage = \"Nenhum resultado encontrado\",\n disabled = false,\n loading = false,\n maxVisibleChips = 2,\n onSearch,\n onCreateOption,\n createOptionLabel,\n className,\n \"aria-label\": ariaLabel,\n \"aria-labelledby\": ariaLabelledby,\n}, ref) => {\n const [open, setOpen] = React.useState(false);\n const [search, setSearch] = React.useState(\"\");\n const [isCreating, setIsCreating] = React.useState(false);\n const triggerRef = React.useRef<HTMLButtonElement>(null);\n const searchInputRef = React.useRef<HTMLInputElement>(null);\n const mergedTriggerRef = React.useMemo(() => mergeRefs(triggerRef, ref), [ref]);\n\n // Callback ref: chamado imediatamente ao montar o elemento (sem timing issue do useEffect).\n // Para a propagação nativa do wheel antes de chegar ao document, onde o\n // react-remove-scroll do Sheet chama preventDefault() em eventos de Portal.\n const listCallbackRef = React.useCallback((el: HTMLDivElement | null) => {\n if (!el) return;\n el.addEventListener(\"wheel\", (e) => e.stopPropagation(), { passive: true });\n }, []);\n\n const allOptions = React.useMemo((): MultiSelectOption[] => {\n if (options) return options;\n if (groups) {\n const groupHeaders: MultiSelectOption[] = groups\n .filter((g) => g.value != null)\n .map((g) => ({ value: g.value!, label: g.label }));\n return [...groupHeaders, ...groups.flatMap((g) => g.options)];\n }\n return [];\n }, [options, groups]);\n\n const isAsyncSearch = !!onSearch;\n\n const filteredOptions = React.useMemo(() => {\n if (!options) return [];\n if (isAsyncSearch) return options;\n const term = search.toLowerCase().trim();\n if (!term) return options;\n return options.filter(\n (o) =>\n o.label.toLowerCase().includes(term) ||\n o.value.toLowerCase().includes(term)\n );\n }, [options, search, isAsyncSearch]);\n\n const filteredGroups = React.useMemo(() => {\n if (!groups) return undefined;\n if (isAsyncSearch) return groups;\n const term = search.toLowerCase().trim();\n if (!term) return groups;\n return groups\n .map((g) => ({\n ...g,\n options: g.options.filter(\n (o) =>\n o.label.toLowerCase().includes(term) ||\n o.value.toLowerCase().includes(term)\n ),\n }))\n .filter((g) => g.options.length > 0);\n }, [groups, search, isAsyncSearch]);\n\n const selectedOptions = React.useMemo(\n () => allOptions.filter((o) => value.includes(o.value)),\n [allOptions, value]\n );\n\n const hasResults = groups\n ? (filteredGroups?.some((g) => g.options.length > 0) ?? false)\n : filteredOptions.length > 0;\n\n const trimmedSearch = search.trim();\n const hasExactMatch = allOptions.some(\n (o) => o.label.trim().toLowerCase() === trimmedSearch.toLowerCase()\n );\n const canCreate = !!onCreateOption && trimmedSearch.length > 0 && !hasExactMatch;\n\n const handleCreate = async () => {\n if (!onCreateOption || isCreating || !trimmedSearch) return;\n setIsCreating(true);\n try {\n await onCreateOption(trimmedSearch);\n setSearch(\"\");\n } catch {\n // Falha na criação: mantém o termo buscado para o usuário corrigir e tentar\n // novamente. O caller é responsável por sinalizar o erro (ex: toast).\n } finally {\n setIsCreating(false);\n }\n };\n\n const handleToggle = (optionValue: string) => {\n if (value.includes(optionValue)) {\n onValueChange(value.filter((v) => v !== optionValue));\n } else {\n onValueChange([...value, optionValue]);\n }\n };\n\n const handleRemoveChip = (optionValue: string, e: React.MouseEvent) => {\n e.stopPropagation();\n onValueChange(value.filter((v) => v !== optionValue));\n };\n\n const handleOpenChange = (next: boolean) => {\n if (disabled) return;\n setOpen(next);\n if (!next) setSearch(\"\");\n };\n\n React.useEffect(() => {\n if (open) onSearch?.(\"\");\n }, [open]);\n\n const handleSearchChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n setSearch(e.target.value);\n onSearch?.(e.target.value);\n };\n\n const visibleChips = selectedOptions.slice(0, maxVisibleChips);\n const overflowCount = selectedOptions.length - maxVisibleChips;\n\n const renderOption = (option: MultiSelectOption) => {\n const selected = value.includes(option.value);\n return (\n <button\n key={option.value}\n type=\"button\"\n role=\"option\"\n aria-selected={selected}\n disabled={option.disabled}\n onClick={() => handleToggle(option.value)}\n className={cn(\n \"flex w-full items-center gap-2 rounded-sm px-2 py-1.5 text-sm\",\n \"aria-selected:bg-secondary aria-selected:text-secondary-foreground aria-selected:font-medium\",\n \"not-aria-selected:hover:bg-accent not-aria-selected:hover:text-accent-foreground\",\n \"focus:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-inset\",\n \"transition-colors duration-100\",\n option.disabled && \"pointer-events-none opacity-50\"\n )}\n >\n <Check\n className={cn(\n \"h-4 w-4 shrink-0 transition-opacity duration-100\",\n selected ? \"opacity-100\" : \"opacity-0\"\n )}\n />\n <span className=\"flex-1 text-left truncate\">{option.label}</span>\n {option.badge}\n </button>\n );\n };\n\n return (\n <Popover open={open} onOpenChange={handleOpenChange}>\n <PopoverTrigger asChild>\n <Button\n ref={mergedTriggerRef}\n type=\"button\"\n variant=\"outline\"\n role=\"combobox\"\n aria-expanded={open}\n aria-label={ariaLabel}\n aria-labelledby={ariaLabelledby}\n disabled={disabled}\n className={cn(\n \"w-full min-h-10 h-auto justify-between font-normal px-3 py-2\",\n !value.length && \"text-muted-foreground\",\n className\n )}\n >\n <div className=\"flex flex-wrap items-center gap-1 flex-1 min-w-0\">\n {value.length === 0 ? (\n <span className=\"truncate text-sm\">\n {loading ? \"Carregando...\" : placeholder}\n </span>\n ) : (\n <>\n {visibleChips.map((opt) => (\n <Badge\n key={opt.value}\n variant=\"secondary\"\n className=\"rounded-sm h-5 gap-0.5 pr-1 font-normal max-w-[160px]\"\n >\n <span className=\"truncate text-xs\">{opt.label}</span>\n <span\n role=\"button\"\n tabIndex={0}\n aria-label={`Remover ${opt.label}`}\n className=\"inline-flex items-center justify-center rounded-sm hover:bg-muted/80 cursor-pointer shrink-0 outline-none focus-visible:ring-2 focus-visible:ring-ring/60\"\n onMouseDown={(e) => e.preventDefault()}\n onClick={(e) => handleRemoveChip(opt.value, e)}\n onKeyDown={pressableKeyDown}\n >\n <X className=\"h-3 w-3\" />\n </span>\n </Badge>\n ))}\n {overflowCount > 0 && (\n <Badge\n variant=\"secondary\"\n className=\"rounded-sm h-5 px-1.5 font-normal text-xs shrink-0\"\n >\n +{overflowCount}\n </Badge>\n )}\n </>\n )}\n </div>\n <ChevronsUpDown className=\"ml-2 h-4 w-4 shrink-0 opacity-50\" />\n </Button>\n </PopoverTrigger>\n\n <PopoverContent\n className=\"p-0 overflow-hidden\"\n style={{\n width: triggerRef.current?.offsetWidth\n ? `${triggerRef.current.offsetWidth}px`\n : \"auto\",\n }}\n align=\"start\"\n onOpenAutoFocus={(e) => {\n // O Radix suprime o autofocus padrão quando este Popover está aninhado em um\n // Dialog/Sheet (o focus-trap do pai disputa o foco com o do Popover). Focamos\n // o input manualmente via ref assim que o conteúdo transiciona para visível.\n e.preventDefault();\n searchInputRef.current?.focus();\n }}\n onWheel={(e) => e.stopPropagation()}\n >\n {/* Busca */}\n <div className=\"flex items-center border-b px-3\">\n <Search className=\"mr-2 h-4 w-4 shrink-0 opacity-50\" />\n <Input\n ref={searchInputRef}\n placeholder={searchPlaceholder}\n value={search}\n onChange={handleSearchChange}\n className=\"h-10 border-0 focus-visible:ring-0 focus-visible:ring-offset-0 px-0\"\n />\n </div>\n\n {/* Criar nova opção */}\n {canCreate && (\n <button\n type=\"button\"\n onClick={handleCreate}\n disabled={isCreating}\n className={cn(\n \"flex w-full items-center gap-2 border-b px-3 py-2 text-sm text-primary\",\n // hover neutro: roxo sobre accent (gray-600) no escuro dá 4,4:1\n \"hover:bg-accent hover:text-accent-foreground transition-colors duration-100\",\n \"disabled:opacity-50 disabled:pointer-events-none\"\n )}\n >\n {isCreating ? (\n <Loader2 className=\"h-4 w-4 shrink-0 animate-spin\" />\n ) : (\n <Plus className=\"h-4 w-4 shrink-0\" />\n )}\n <span className=\"truncate\">\n {isCreating\n ? \"Criando...\"\n : (createOptionLabel?.(trimmedSearch) ?? `Criar \"${trimmedSearch}\"`)}\n </span>\n </button>\n )}\n\n {/* Lista */}\n <div ref={listCallbackRef} className=\"max-h-70 overflow-y-auto [&::-webkit-scrollbar]:w-2.5 [&::-webkit-scrollbar-track]:bg-transparent [&::-webkit-scrollbar-thumb]:rounded-full [&::-webkit-scrollbar-thumb]:bg-primary/30 [&::-webkit-scrollbar-thumb:hover]:bg-primary/50\">\n <div className=\"p-1\" role=\"listbox\" aria-multiselectable>\n {loading ? (\n <div className=\"flex items-center justify-center gap-2 py-6 text-sm text-muted-foreground\">\n <Loader2 className=\"h-4 w-4 animate-spin\" />\n Carregando...\n </div>\n ) : !hasResults ? (\n <div className=\"py-6 text-center text-sm text-muted-foreground\">\n {emptyMessage}\n </div>\n ) : groups ? (\n filteredGroups?.map((group) => (\n <div key={group.label}>\n {group.value ? (\n <button\n type=\"button\"\n onClick={() => handleToggle(group.value!)}\n className={cn(\n \"flex w-full items-center gap-2 rounded-sm px-2 py-1.5\",\n \"hover:bg-accent hover:text-accent-foreground transition-colors duration-100\",\n value.includes(group.value) && \"text-foreground\"\n )}\n >\n <Check\n className={cn(\n \"h-4 w-4 shrink-0 transition-opacity duration-100\",\n value.includes(group.value) ? \"opacity-100\" : \"opacity-0\"\n )}\n />\n <span className=\"text-xs font-semibold uppercase tracking-wide\">\n {group.label}\n </span>\n </button>\n ) : (\n <div className=\"px-2 py-1.5 text-xs font-semibold text-muted-foreground uppercase tracking-wide\">\n {group.label}\n </div>\n )}\n {group.options.map(renderOption)}\n </div>\n ))\n ) : (\n filteredOptions.map(renderOption)\n )}\n </div>\n </div>\n </PopoverContent>\n </Popover>\n );\n});\nMultiSelect.displayName = \"MultiSelect\";\n\nexport default MultiSelect;\n"],"names":["MultiSelect","React","value","onValueChange","options","groups","placeholder","searchPlaceholder","emptyMessage","disabled","loading","maxVisibleChips","onSearch","onCreateOption","createOptionLabel","className","ariaLabel","ariaLabelledby","ref","open","setOpen","search","setSearch","isCreating","setIsCreating","triggerRef","searchInputRef","mergedTriggerRef","mergeRefs","listCallbackRef","el","e","allOptions","g","isAsyncSearch","filteredOptions","term","o","filteredGroups","selectedOptions","hasResults","trimmedSearch","hasExactMatch","canCreate","handleCreate","handleToggle","optionValue","v","handleRemoveChip","handleOpenChange","next","handleSearchChange","visibleChips","overflowCount","renderOption","option","selected","jsxs","cn","jsx","Check","Popover","PopoverTrigger","Button","Fragment","opt","Badge","pressableKeyDown","X","ChevronsUpDown","PopoverContent","_a","Search","Input","Loader2","Plus","group"],"mappings":"knBAsHaA,EAAcC,EAAM,WAG/B,CAAC,CACD,MAAAC,EACA,cAAAC,EACA,QAAAC,EACA,OAAAC,EACA,YAAAC,EAAc,eACd,kBAAAC,EAAoB,YACpB,aAAAC,EAAe,8BACf,SAAAC,EAAW,GACX,QAAAC,EAAU,GACV,gBAAAC,EAAkB,EAClB,SAAAC,EACA,eAAAC,EACA,kBAAAC,EACA,UAAAC,EACA,aAAcC,EACd,kBAAmBC,CACrB,EAAGC,IAAQ,OACT,KAAM,CAACC,EAAMC,CAAO,EAAInB,EAAM,SAAS,EAAK,EACtC,CAACoB,EAAQC,CAAS,EAAIrB,EAAM,SAAS,EAAE,EACvC,CAACsB,EAAYC,CAAa,EAAIvB,EAAM,SAAS,EAAK,EAClDwB,EAAaxB,EAAM,OAA0B,IAAI,EACjDyB,EAAiBzB,EAAM,OAAyB,IAAI,EACpD0B,EAAmB1B,EAAM,QAAQ,IAAM2B,EAAAA,UAAUH,EAAYP,CAAG,EAAG,CAACA,CAAG,CAAC,EAKxEW,EAAkB5B,EAAM,YAAa6B,GAA8B,CAClEA,GACLA,EAAG,iBAAiB,QAAUC,GAAMA,EAAE,kBAAmB,CAAE,QAAS,GAAM,CAC5E,EAAG,CAAA,CAAE,EAECC,EAAa/B,EAAM,QAAQ,IAC3BG,IACAC,EAIK,CAAC,GAHkCA,EACvC,OAAQ4B,GAAMA,EAAE,OAAS,IAAI,EAC7B,IAAKA,IAAO,CAAE,MAAOA,EAAE,MAAQ,MAAOA,EAAE,OAAQ,EAC1B,GAAG5B,EAAO,QAAS4B,GAAMA,EAAE,OAAO,CAAC,EAEvD,CAAA,GACN,CAAC7B,EAASC,CAAM,CAAC,EAEd6B,EAAgB,CAAC,CAACtB,EAElBuB,EAAkBlC,EAAM,QAAQ,IAAM,CAC1C,GAAI,CAACG,EAAS,MAAO,CAAA,EACrB,GAAI8B,EAAe,OAAO9B,EAC1B,MAAMgC,EAAOf,EAAO,YAAA,EAAc,KAAA,EAClC,OAAKe,EACEhC,EAAQ,OACZiC,GACCA,EAAE,MAAM,cAAc,SAASD,CAAI,GACnCC,EAAE,MAAM,YAAA,EAAc,SAASD,CAAI,CAAA,EAJrBhC,CAMpB,EAAG,CAACA,EAASiB,EAAQa,CAAa,CAAC,EAE7BI,EAAiBrC,EAAM,QAAQ,IAAM,CACzC,GAAI,CAACI,EAAQ,OACb,GAAI6B,EAAe,OAAO7B,EAC1B,MAAM+B,EAAOf,EAAO,YAAA,EAAc,KAAA,EAClC,OAAKe,EACE/B,EACJ,IAAK4B,IAAO,CACX,GAAGA,EACH,QAASA,EAAE,QAAQ,OAChBI,GACCA,EAAE,MAAM,cAAc,SAASD,CAAI,GACnCC,EAAE,MAAM,YAAA,EAAc,SAASD,CAAI,CAAA,CACvC,EACA,EACD,OAAQH,GAAMA,EAAE,QAAQ,OAAS,CAAC,EAVnB5B,CAWpB,EAAG,CAACA,EAAQgB,EAAQa,CAAa,CAAC,EAE5BK,EAAkBtC,EAAM,QAC5B,IAAM+B,EAAW,OAAQK,GAAMnC,EAAM,SAASmC,EAAE,KAAK,CAAC,EACtD,CAACL,EAAY9B,CAAK,CAAA,EAGdsC,EAAanC,GACdiC,GAAA,YAAAA,EAAgB,KAAML,GAAMA,EAAE,QAAQ,OAAS,KAAM,GACtDE,EAAgB,OAAS,EAEvBM,EAAgBpB,EAAO,KAAA,EACvBqB,EAAgBV,EAAW,KAC9BK,GAAMA,EAAE,MAAM,OAAO,YAAA,IAAkBI,EAAc,YAAA,CAAY,EAE9DE,EAAY,CAAC,CAAC9B,GAAkB4B,EAAc,OAAS,GAAK,CAACC,EAE7DE,EAAe,SAAY,CAC/B,GAAI,GAAC/B,GAAkBU,GAAc,CAACkB,GACtC,CAAAjB,EAAc,EAAI,EAClB,GAAI,CACF,MAAMX,EAAe4B,CAAa,EAClCnB,EAAU,EAAE,CACd,MAAQ,CAGR,QAAA,CACEE,EAAc,EAAK,CACrB,EACF,EAEMqB,EAAgBC,GAAwB,CACxC5C,EAAM,SAAS4C,CAAW,EAC5B3C,EAAcD,EAAM,OAAQ6C,GAAMA,IAAMD,CAAW,CAAC,EAEpD3C,EAAc,CAAC,GAAGD,EAAO4C,CAAW,CAAC,CAEzC,EAEME,EAAmB,CAACF,EAAqBf,IAAwB,CACrEA,EAAE,gBAAA,EACF5B,EAAcD,EAAM,OAAQ6C,GAAMA,IAAMD,CAAW,CAAC,CACtD,EAEMG,EAAoBC,GAAkB,CACtCzC,IACJW,EAAQ8B,CAAI,EACPA,GAAM5B,EAAU,EAAE,EACzB,EAEArB,EAAM,UAAU,IAAM,CAChBkB,eAAiB,IACvB,EAAG,CAACA,CAAI,CAAC,EAET,MAAMgC,EAAsB,GAA2C,CACrE7B,EAAU,EAAE,OAAO,KAAK,EACxBV,GAAA,MAAAA,EAAW,EAAE,OAAO,MACtB,EAEMwC,GAAeb,EAAgB,MAAM,EAAG5B,CAAe,EACvD0C,EAAgBd,EAAgB,OAAS5B,EAEzC2C,EAAgBC,GAA8B,CAClD,MAAMC,EAAWtD,EAAM,SAASqD,EAAO,KAAK,EAC5C,OACEE,EAAAA,KAAC,SAAA,CAEC,KAAK,SACL,KAAK,SACL,gBAAeD,EACf,SAAUD,EAAO,SACjB,QAAS,IAAMV,EAAaU,EAAO,KAAK,EACxC,UAAWG,EAAAA,GACT,gEACA,+FACA,mFACA,2FACA,iCACAH,EAAO,UAAY,gCAAA,EAGrB,SAAA,CAAAI,EAAAA,IAACC,EAAAA,MAAA,CACC,UAAWF,EAAAA,GACT,mDACAF,EAAW,cAAgB,WAAA,CAC7B,CAAA,EAEFG,EAAAA,IAAC,OAAA,CAAK,UAAU,4BAA6B,WAAO,MAAM,EACzDJ,EAAO,KAAA,CAAA,EAtBHA,EAAO,KAAA,CAyBlB,EAEA,OACEE,EAAAA,KAACI,EAAAA,QAAA,CAAQ,KAAA1C,EAAY,aAAc8B,EACjC,SAAA,CAAAU,EAAAA,IAACG,EAAAA,eAAA,CAAe,QAAO,GACrB,SAAAL,EAAAA,KAACM,GAAAA,OAAA,CACC,IAAKpC,EACL,KAAK,SACL,QAAQ,UACR,KAAK,WACL,gBAAeR,EACf,aAAYH,EACZ,kBAAiBC,EACjB,SAAAR,EACA,UAAWiD,EAAAA,GACT,+DACA,CAACxD,EAAM,QAAU,wBACjBa,CAAA,EAGF,SAAA,CAAA4C,MAAC,MAAA,CAAI,UAAU,mDACZ,SAAAzD,EAAM,SAAW,EAChByD,EAAAA,IAAC,OAAA,CAAK,UAAU,mBACb,SAAAjD,EAAU,gBAAkBJ,CAAA,CAC/B,EAEAmD,EAAAA,KAAAO,WAAA,CACG,SAAA,CAAAZ,GAAa,IAAKa,GACjBR,EAAAA,KAACS,EAAAA,MAAA,CAEC,QAAQ,YACR,UAAU,wDAEV,SAAA,CAAAP,EAAAA,IAAC,OAAA,CAAK,UAAU,mBAAoB,SAAAM,EAAI,MAAM,EAC9CN,EAAAA,IAAC,OAAA,CACC,KAAK,SACL,SAAU,EACV,aAAY,WAAWM,EAAI,KAAK,GAChC,UAAU,4JACV,YAAclC,GAAMA,EAAE,eAAA,EACtB,QAAUA,GAAMiB,EAAiBiB,EAAI,MAAOlC,CAAC,EAC7C,UAAWoC,EAAAA,iBAEX,SAAAR,EAAAA,IAACS,EAAAA,EAAA,CAAE,UAAU,SAAA,CAAU,CAAA,CAAA,CACzB,CAAA,EAfKH,EAAI,KAAA,CAiBZ,EACAZ,EAAgB,GACfI,EAAAA,KAACS,EAAAA,MAAA,CACC,QAAQ,YACR,UAAU,qDACX,SAAA,CAAA,IACGb,CAAA,CAAA,CAAA,CACJ,CAAA,CAEJ,CAAA,CAEJ,EACAM,EAAAA,IAACU,EAAAA,eAAA,CAAe,UAAU,kCAAA,CAAmC,CAAA,CAAA,CAAA,EAEjE,EAEAZ,EAAAA,KAACa,EAAAA,eAAA,CACC,UAAU,sBACV,MAAO,CACL,OAAOC,EAAA9C,EAAW,UAAX,MAAA8C,EAAoB,YACvB,GAAG9C,EAAW,QAAQ,WAAW,KACjC,MAAA,EAEN,MAAM,QACN,gBAAkB,GAAM,OAItB,EAAE,eAAA,GACF8C,EAAA7C,EAAe,UAAf,MAAA6C,EAAwB,OAC1B,EACA,QAAU,GAAM,EAAE,gBAAA,EAGlB,SAAA,CAAAd,EAAAA,KAAC,MAAA,CAAI,UAAU,kCACb,SAAA,CAAAE,EAAAA,IAACa,EAAAA,OAAA,CAAO,UAAU,kCAAA,CAAmC,EACrDb,EAAAA,IAACc,GAAAA,MAAA,CACC,IAAK/C,EACL,YAAanB,EACb,MAAOc,EACP,SAAU8B,EACV,UAAU,qEAAA,CAAA,CACZ,EACF,EAGCR,GACCc,EAAAA,KAAC,SAAA,CACC,KAAK,SACL,QAASb,EACT,SAAUrB,EACV,UAAWmC,EAAAA,GACT,yEAEA,8EACA,kDAAA,EAGD,SAAA,CAAAnC,EACCoC,EAAAA,IAACe,WAAQ,UAAU,+BAAA,CAAgC,EAEnDf,EAAAA,IAACgB,EAAAA,KAAA,CAAK,UAAU,kBAAA,CAAmB,EAErChB,EAAAA,IAAC,OAAA,CAAK,UAAU,WACb,SAAApC,EACG,cACCT,GAAA,YAAAA,EAAoB2B,KAAkB,UAAUA,CAAa,GAAA,CACpE,CAAA,CAAA,CAAA,QAKH,MAAA,CAAI,IAAKZ,EAAiB,UAAU,0OACnC,eAAC,MAAA,CAAI,UAAU,MAAM,KAAK,UAAU,uBAAoB,GACrD,WACC4B,EAAAA,KAAC,MAAA,CAAI,UAAU,4EACb,SAAA,CAAAE,EAAAA,IAACe,EAAAA,QAAA,CAAQ,UAAU,sBAAA,CAAuB,EAAE,eAAA,EAE9C,EACGlC,EAIDnC,EACFiC,GAAA,YAAAA,EAAgB,IAAKsC,UAClB,MAAA,CACE,SAAA,CAAAA,EAAM,MACLnB,EAAAA,KAAC,SAAA,CACC,KAAK,SACL,QAAS,IAAMZ,EAAa+B,EAAM,KAAM,EACxC,UAAWlB,EAAAA,GACT,wDACA,8EACAxD,EAAM,SAAS0E,EAAM,KAAK,GAAK,iBAAA,EAGjC,SAAA,CAAAjB,EAAAA,IAACC,EAAAA,MAAA,CACC,UAAWF,EAAAA,GACT,mDACAxD,EAAM,SAAS0E,EAAM,KAAK,EAAI,cAAgB,WAAA,CAChD,CAAA,EAEFjB,EAAAA,IAAC,OAAA,CAAK,UAAU,gDACb,WAAM,KAAA,CACT,CAAA,CAAA,CAAA,EAGFA,EAAAA,IAAC,MAAA,CAAI,UAAU,kFACZ,WAAM,MACT,EAEDiB,EAAM,QAAQ,IAAItB,CAAY,CAAA,GA1BvBsB,EAAM,KA2BhB,GAGFzC,EAAgB,IAAImB,CAAY,EAnChCK,EAAAA,IAAC,OAAI,UAAU,iDACZ,SAAAnD,CAAA,CACH,EAmCJ,CAAA,CACF,CAAA,CAAA,CAAA,CACF,EACF,CAEJ,CAAC,EACDR,EAAY,YAAc"}
@@ -1,14 +1,14 @@
1
1
  "use client";
2
- import { jsxs as n, jsx as a, Fragment as te } from "react/jsx-runtime";
3
- import * as r from "react";
4
- import { X as ae, ChevronsUpDown as re, Search as ne, Loader2 as W, Plus as se, Check as $ } from "lucide-react";
5
- import { mergeRefs as le, pressableKeyDown as ie, cn as u } from "../utils.js";
2
+ import { jsxs as s, jsx as r, Fragment as te } from "react/jsx-runtime";
3
+ import * as a from "react";
4
+ import { X as re, ChevronsUpDown as ae, Search as se, Loader2 as W, Plus as ne, Check as $ } from "lucide-react";
5
+ import { mergeRefs as le, pressableKeyDown as ie, cn as m } from "../utils.js";
6
6
  import { Button as oe } from "../primitives/button.js";
7
7
  import { Badge as A } from "../primitives/badge.js";
8
- import { Popover as ce, PopoverTrigger as de, PopoverContent as me } from "../overlays/popover.js";
9
- import { Input as ue } from "./input.js";
10
- const fe = r.forwardRef(({
11
- value: s,
8
+ import { Popover as ce, PopoverTrigger as de, PopoverContent as ue } from "../overlays/popover.js";
9
+ import { Input as me } from "./input.js";
10
+ const fe = a.forwardRef(({
11
+ value: n,
12
12
  onValueChange: x,
13
13
  options: i,
14
14
  groups: l,
@@ -26,55 +26,55 @@ const fe = r.forwardRef(({
26
26
  "aria-labelledby": U
27
27
  }, M) => {
28
28
  var T;
29
- const [f, X] = r.useState(!1), [c, w] = r.useState(""), [h, P] = r.useState(!1), y = r.useRef(null), D = r.useRef(null), q = r.useMemo(() => le(y, M), [M]), z = r.useCallback((e) => {
29
+ const [f, X] = a.useState(!1), [c, w] = a.useState(""), [h, P] = a.useState(!1), y = a.useRef(null), D = a.useRef(null), q = a.useMemo(() => le(y, M), [M]), z = a.useCallback((e) => {
30
30
  e && e.addEventListener("wheel", (t) => t.stopPropagation(), { passive: !0 });
31
- }, []), N = r.useMemo(() => i || (l ? [...l.filter((t) => t.value != null).map((t) => ({ value: t.value, label: t.label })), ...l.flatMap((t) => t.options)] : []), [i, l]), p = !!o, L = r.useMemo(() => {
31
+ }, []), N = a.useMemo(() => i || (l ? [...l.filter((t) => t.value != null).map((t) => ({ value: t.value, label: t.label })), ...l.flatMap((t) => t.options)] : []), [i, l]), b = !!o, L = a.useMemo(() => {
32
32
  if (!i) return [];
33
- if (p) return i;
33
+ if (b) return i;
34
34
  const e = c.toLowerCase().trim();
35
35
  return e ? i.filter(
36
36
  (t) => t.label.toLowerCase().includes(e) || t.value.toLowerCase().includes(e)
37
37
  ) : i;
38
- }, [i, c, p]), d = r.useMemo(() => {
38
+ }, [i, c, b]), d = a.useMemo(() => {
39
39
  if (!l) return;
40
- if (p) return l;
40
+ if (b) return l;
41
41
  const e = c.toLowerCase().trim();
42
42
  return e ? l.map((t) => ({
43
43
  ...t,
44
44
  options: t.options.filter(
45
- (b) => b.label.toLowerCase().includes(e) || b.value.toLowerCase().includes(e)
45
+ (p) => p.label.toLowerCase().includes(e) || p.value.toLowerCase().includes(e)
46
46
  )
47
47
  })).filter((t) => t.options.length > 0) : l;
48
- }, [l, c, p]), j = r.useMemo(
49
- () => N.filter((e) => s.includes(e.value)),
50
- [N, s]
51
- ), J = l ? (d == null ? void 0 : d.some((e) => e.options.length > 0)) ?? !1 : L.length > 0, m = c.trim(), Q = N.some(
52
- (e) => e.label.trim().toLowerCase() === m.toLowerCase()
53
- ), Y = !!v && m.length > 0 && !Q, Z = async () => {
54
- if (!(!v || h || !m)) {
48
+ }, [l, c, b]), j = a.useMemo(
49
+ () => N.filter((e) => n.includes(e.value)),
50
+ [N, n]
51
+ ), J = l ? (d == null ? void 0 : d.some((e) => e.options.length > 0)) ?? !1 : L.length > 0, u = c.trim(), Q = N.some(
52
+ (e) => e.label.trim().toLowerCase() === u.toLowerCase()
53
+ ), Y = !!v && u.length > 0 && !Q, Z = async () => {
54
+ if (!(!v || h || !u)) {
55
55
  P(!0);
56
56
  try {
57
- await v(m), w("");
57
+ await v(u), w("");
58
58
  } catch {
59
59
  } finally {
60
60
  P(!1);
61
61
  }
62
62
  }
63
63
  }, I = (e) => {
64
- s.includes(e) ? x(s.filter((t) => t !== e)) : x([...s, e]);
64
+ n.includes(e) ? x(n.filter((t) => t !== e)) : x([...n, e]);
65
65
  }, _ = (e, t) => {
66
- t.stopPropagation(), x(s.filter((b) => b !== e));
66
+ t.stopPropagation(), x(n.filter((p) => p !== e));
67
67
  }, G = (e) => {
68
68
  C || (X(e), e || w(""));
69
69
  };
70
- r.useEffect(() => {
70
+ a.useEffect(() => {
71
71
  f && (o == null || o(""));
72
72
  }, [f]);
73
73
  const V = (e) => {
74
74
  w(e.target.value), o == null || o(e.target.value);
75
75
  }, ee = j.slice(0, R), B = j.length - R, E = (e) => {
76
- const t = s.includes(e.value);
77
- return /* @__PURE__ */ n(
76
+ const t = n.includes(e.value);
77
+ return /* @__PURE__ */ s(
78
78
  "button",
79
79
  {
80
80
  type: "button",
@@ -82,32 +82,33 @@ const fe = r.forwardRef(({
82
82
  "aria-selected": t,
83
83
  disabled: e.disabled,
84
84
  onClick: () => I(e.value),
85
- className: u(
85
+ className: m(
86
86
  "flex w-full items-center gap-2 rounded-sm px-2 py-1.5 text-sm",
87
- "hover:bg-accent hover:text-accent-foreground",
88
- "focus:bg-accent focus:text-accent-foreground focus:outline-none",
87
+ "aria-selected:bg-secondary aria-selected:text-secondary-foreground aria-selected:font-medium",
88
+ "not-aria-selected:hover:bg-accent not-aria-selected:hover:text-accent-foreground",
89
+ "focus:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-inset",
89
90
  "transition-colors duration-100",
90
91
  e.disabled && "pointer-events-none opacity-50"
91
92
  ),
92
93
  children: [
93
- /* @__PURE__ */ a(
94
+ /* @__PURE__ */ r(
94
95
  $,
95
96
  {
96
- className: u(
97
+ className: m(
97
98
  "h-4 w-4 shrink-0 transition-opacity duration-100",
98
99
  t ? "opacity-100" : "opacity-0"
99
100
  )
100
101
  }
101
102
  ),
102
- /* @__PURE__ */ a("span", { className: "flex-1 text-left truncate", children: e.label }),
103
+ /* @__PURE__ */ r("span", { className: "flex-1 text-left truncate", children: e.label }),
103
104
  e.badge
104
105
  ]
105
106
  },
106
107
  e.value
107
108
  );
108
109
  };
109
- return /* @__PURE__ */ n(ce, { open: f, onOpenChange: G, children: [
110
- /* @__PURE__ */ a(de, { asChild: !0, children: /* @__PURE__ */ n(
110
+ return /* @__PURE__ */ s(ce, { open: f, onOpenChange: G, children: [
111
+ /* @__PURE__ */ r(de, { asChild: !0, children: /* @__PURE__ */ s(
111
112
  oe,
112
113
  {
113
114
  ref: q,
@@ -118,21 +119,21 @@ const fe = r.forwardRef(({
118
119
  "aria-label": S,
119
120
  "aria-labelledby": U,
120
121
  disabled: C,
121
- className: u(
122
+ className: m(
122
123
  "w-full min-h-10 h-auto justify-between font-normal px-3 py-2",
123
- !s.length && "text-muted-foreground",
124
+ !n.length && "text-muted-foreground",
124
125
  O
125
126
  ),
126
127
  children: [
127
- /* @__PURE__ */ a("div", { className: "flex flex-wrap items-center gap-1 flex-1 min-w-0", children: s.length === 0 ? /* @__PURE__ */ a("span", { className: "truncate text-sm", children: k ? "Carregando..." : F }) : /* @__PURE__ */ n(te, { children: [
128
- ee.map((e) => /* @__PURE__ */ n(
128
+ /* @__PURE__ */ r("div", { className: "flex flex-wrap items-center gap-1 flex-1 min-w-0", children: n.length === 0 ? /* @__PURE__ */ r("span", { className: "truncate text-sm", children: k ? "Carregando..." : F }) : /* @__PURE__ */ s(te, { children: [
129
+ ee.map((e) => /* @__PURE__ */ s(
129
130
  A,
130
131
  {
131
132
  variant: "secondary",
132
133
  className: "rounded-sm h-5 gap-0.5 pr-1 font-normal max-w-[160px]",
133
134
  children: [
134
- /* @__PURE__ */ a("span", { className: "truncate text-xs", children: e.label }),
135
- /* @__PURE__ */ a(
135
+ /* @__PURE__ */ r("span", { className: "truncate text-xs", children: e.label }),
136
+ /* @__PURE__ */ r(
136
137
  "span",
137
138
  {
138
139
  role: "button",
@@ -142,14 +143,14 @@ const fe = r.forwardRef(({
142
143
  onMouseDown: (t) => t.preventDefault(),
143
144
  onClick: (t) => _(e.value, t),
144
145
  onKeyDown: ie,
145
- children: /* @__PURE__ */ a(ae, { className: "h-3 w-3" })
146
+ children: /* @__PURE__ */ r(re, { className: "h-3 w-3" })
146
147
  }
147
148
  )
148
149
  ]
149
150
  },
150
151
  e.value
151
152
  )),
152
- B > 0 && /* @__PURE__ */ n(
153
+ B > 0 && /* @__PURE__ */ s(
153
154
  A,
154
155
  {
155
156
  variant: "secondary",
@@ -161,12 +162,12 @@ const fe = r.forwardRef(({
161
162
  }
162
163
  )
163
164
  ] }) }),
164
- /* @__PURE__ */ a(re, { className: "ml-2 h-4 w-4 shrink-0 opacity-50" })
165
+ /* @__PURE__ */ r(ae, { className: "ml-2 h-4 w-4 shrink-0 opacity-50" })
165
166
  ]
166
167
  }
167
168
  ) }),
168
- /* @__PURE__ */ n(
169
- me,
169
+ /* @__PURE__ */ s(
170
+ ue,
170
171
  {
171
172
  className: "p-0 overflow-hidden",
172
173
  style: {
@@ -179,10 +180,10 @@ const fe = r.forwardRef(({
179
180
  },
180
181
  onWheel: (e) => e.stopPropagation(),
181
182
  children: [
182
- /* @__PURE__ */ n("div", { className: "flex items-center border-b px-3", children: [
183
- /* @__PURE__ */ a(ne, { className: "mr-2 h-4 w-4 shrink-0 opacity-50" }),
184
- /* @__PURE__ */ a(
185
- ue,
183
+ /* @__PURE__ */ s("div", { className: "flex items-center border-b px-3", children: [
184
+ /* @__PURE__ */ r(se, { className: "mr-2 h-4 w-4 shrink-0 opacity-50" }),
185
+ /* @__PURE__ */ r(
186
+ me,
186
187
  {
187
188
  ref: D,
188
189
  placeholder: H,
@@ -192,53 +193,54 @@ const fe = r.forwardRef(({
192
193
  }
193
194
  )
194
195
  ] }),
195
- Y && /* @__PURE__ */ n(
196
+ Y && /* @__PURE__ */ s(
196
197
  "button",
197
198
  {
198
199
  type: "button",
199
200
  onClick: Z,
200
201
  disabled: h,
201
- className: u(
202
+ className: m(
202
203
  "flex w-full items-center gap-2 border-b px-3 py-2 text-sm text-primary",
203
- "hover:bg-accent transition-colors duration-100",
204
+ // hover neutro: roxo sobre accent (gray-600) no escuro dá 4,4:1
205
+ "hover:bg-accent hover:text-accent-foreground transition-colors duration-100",
204
206
  "disabled:opacity-50 disabled:pointer-events-none"
205
207
  ),
206
208
  children: [
207
- h ? /* @__PURE__ */ a(W, { className: "h-4 w-4 shrink-0 animate-spin" }) : /* @__PURE__ */ a(se, { className: "h-4 w-4 shrink-0" }),
208
- /* @__PURE__ */ a("span", { className: "truncate", children: h ? "Criando..." : (g == null ? void 0 : g(m)) ?? `Criar "${m}"` })
209
+ h ? /* @__PURE__ */ r(W, { className: "h-4 w-4 shrink-0 animate-spin" }) : /* @__PURE__ */ r(ne, { className: "h-4 w-4 shrink-0" }),
210
+ /* @__PURE__ */ r("span", { className: "truncate", children: h ? "Criando..." : (g == null ? void 0 : g(u)) ?? `Criar "${u}"` })
209
211
  ]
210
212
  }
211
213
  ),
212
- /* @__PURE__ */ a("div", { ref: z, className: "max-h-70 overflow-y-auto [&::-webkit-scrollbar]:w-2.5 [&::-webkit-scrollbar-track]:bg-transparent [&::-webkit-scrollbar-thumb]:rounded-full [&::-webkit-scrollbar-thumb]:bg-primary/30 [&::-webkit-scrollbar-thumb:hover]:bg-primary/50", children: /* @__PURE__ */ a("div", { className: "p-1", role: "listbox", "aria-multiselectable": !0, children: k ? /* @__PURE__ */ n("div", { className: "flex items-center justify-center gap-2 py-6 text-sm text-muted-foreground", children: [
213
- /* @__PURE__ */ a(W, { className: "h-4 w-4 animate-spin" }),
214
+ /* @__PURE__ */ r("div", { ref: z, className: "max-h-70 overflow-y-auto [&::-webkit-scrollbar]:w-2.5 [&::-webkit-scrollbar-track]:bg-transparent [&::-webkit-scrollbar-thumb]:rounded-full [&::-webkit-scrollbar-thumb]:bg-primary/30 [&::-webkit-scrollbar-thumb:hover]:bg-primary/50", children: /* @__PURE__ */ r("div", { className: "p-1", role: "listbox", "aria-multiselectable": !0, children: k ? /* @__PURE__ */ s("div", { className: "flex items-center justify-center gap-2 py-6 text-sm text-muted-foreground", children: [
215
+ /* @__PURE__ */ r(W, { className: "h-4 w-4 animate-spin" }),
214
216
  "Carregando..."
215
- ] }) : J ? l ? d == null ? void 0 : d.map((e) => /* @__PURE__ */ n("div", { children: [
216
- e.value ? /* @__PURE__ */ n(
217
+ ] }) : J ? l ? d == null ? void 0 : d.map((e) => /* @__PURE__ */ s("div", { children: [
218
+ e.value ? /* @__PURE__ */ s(
217
219
  "button",
218
220
  {
219
221
  type: "button",
220
222
  onClick: () => I(e.value),
221
- className: u(
223
+ className: m(
222
224
  "flex w-full items-center gap-2 rounded-sm px-2 py-1.5",
223
225
  "hover:bg-accent hover:text-accent-foreground transition-colors duration-100",
224
- s.includes(e.value) && "text-foreground"
226
+ n.includes(e.value) && "text-foreground"
225
227
  ),
226
228
  children: [
227
- /* @__PURE__ */ a(
229
+ /* @__PURE__ */ r(
228
230
  $,
229
231
  {
230
- className: u(
232
+ className: m(
231
233
  "h-4 w-4 shrink-0 transition-opacity duration-100",
232
- s.includes(e.value) ? "opacity-100" : "opacity-0"
234
+ n.includes(e.value) ? "opacity-100" : "opacity-0"
233
235
  )
234
236
  }
235
237
  ),
236
- /* @__PURE__ */ a("span", { className: "text-xs font-semibold uppercase tracking-wide", children: e.label })
238
+ /* @__PURE__ */ r("span", { className: "text-xs font-semibold uppercase tracking-wide", children: e.label })
237
239
  ]
238
240
  }
239
- ) : /* @__PURE__ */ a("div", { className: "px-2 py-1.5 text-xs font-semibold text-muted-foreground uppercase tracking-wide", children: e.label }),
241
+ ) : /* @__PURE__ */ r("div", { className: "px-2 py-1.5 text-xs font-semibold text-muted-foreground uppercase tracking-wide", children: e.label }),
240
242
  e.options.map(E)
241
- ] }, e.label)) : L.map(E) : /* @__PURE__ */ a("div", { className: "py-6 text-center text-sm text-muted-foreground", children: K }) }) })
243
+ ] }, e.label)) : L.map(E) : /* @__PURE__ */ r("div", { className: "py-6 text-center text-sm text-muted-foreground", children: K }) }) })
242
244
  ]
243
245
  }
244
246
  )
@@ -1 +1 @@
1
- {"version":3,"file":"multi-select.js","sources":["../../../../src/components/ui/forms/multi-select.tsx"],"sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\nimport { Check, ChevronsUpDown, X, Search, Loader2, Plus } from \"lucide-react\";\nimport { cn, mergeRefs, pressableKeyDown } from \"../utils\";\nimport { Button } from \"../primitives/button\";\nimport { Badge } from \"../primitives/badge\";\nimport { Popover, PopoverContent, PopoverTrigger } from \"../overlays/popover\";\nimport { Input } from \"./input\";\n\nexport interface MultiSelectOption {\n value: string;\n label: string;\n disabled?: boolean;\n /** Slot para renderização customizada à direita do label — ex: <Badge>Externo</Badge> */\n badge?: React.ReactNode;\n}\n\nexport interface MultiSelectGroup {\n label: string;\n options: MultiSelectOption[];\n /** Quando presente, o header do grupo torna-se clicável e seleciona/deseleciona o grupo */\n value?: string;\n}\n\nexport interface MultiSelectProps {\n /** Valores atualmente selecionados */\n value: string[];\n /** Callback disparado ao alterar a seleção */\n onValueChange: (values: string[]) => void;\n\n /**\n * Opções em lista plana.\n * Use `options` OU `groups` — nunca os dois ao mesmo tempo.\n */\n options?: MultiSelectOption[];\n /**\n * Opções agrupadas hierarquicamente.\n * Use `options` OU `groups` — nunca os dois ao mesmo tempo.\n */\n groups?: MultiSelectGroup[];\n\n placeholder?: string;\n searchPlaceholder?: string;\n emptyMessage?: string;\n\n /** Rótulo acessível do gatilho quando não há `<Label>` associado */\n \"aria-label\"?: string;\n \"aria-labelledby\"?: string;\n\n disabled?: boolean;\n /** Exibe estado de carregamento — substitui a lista por spinner */\n loading?: boolean;\n\n /**\n * Número máximo de chips visíveis no trigger antes de exibir \"+N\".\n * @default 2\n */\n maxVisibleChips?: number;\n\n /**\n * Callback de busca assíncrona — chamado a cada keystroke e ao abrir o dropdown.\n * Quando presente, a filtragem local é desativada (o caller controla `options`/`groups`).\n */\n onSearch?: (query: string) => void;\n\n /**\n * Habilita criação de uma nova opção diretamente no dropdown.\n * Chamado quando o usuário clica em \"Criar '{busca}'\" — o caller é responsável por\n * persistir a opção (ex: chamada de API), atualizar `options`/`value` com o resultado\n * e sinalizar falhas ao usuário (ex: toast). Rejeitar a promise preserva o termo\n * buscado no campo, permitindo corrigir e tentar novamente.\n * Exibido apenas quando não há opção com label idêntico ao termo buscado.\n */\n onCreateOption?: (inputValue: string) => void | Promise<void>;\n /** Customiza o label do botão de criação. @default (query) => `Criar \"${query}\"` */\n createOptionLabel?: (query: string) => string;\n\n className?: string;\n}\n\n/**\n * MultiSelect — Seleção múltipla com chips, busca, grupos hierárquicos e slots de badge por opção.\n *\n * @example\n * ```tsx\n * // Lista plana\n * <MultiSelect\n * value={selectedSquads}\n * onValueChange={setSelectedSquads}\n * options={squads.map(s => ({ value: String(s.id), label: s.name }))}\n * placeholder=\"Selecione os squads\"\n * />\n *\n * // Com badge por opção (ex: funcionários externos)\n * <MultiSelect\n * value={selectedEmployees}\n * onValueChange={setSelectedEmployees}\n * options={employees.map(e => ({\n * value: String(e.id),\n * label: e.name,\n * badge: e.isExternalUser\n * ? <Badge variant=\"secondary\" className=\"text-xs\">Externo</Badge>\n * : undefined,\n * }))}\n * />\n *\n * // Lista hierárquica (grupos de clientes)\n * <MultiSelect\n * value={selectedClients}\n * onValueChange={setSelectedClients}\n * groups={customerGroups.map(g => ({\n * label: g.name,\n * options: g.children.map(c => ({ value: String(c.id), label: c.name })),\n * }))}\n * />\n * ```\n */\nexport const MultiSelect = React.forwardRef<\n React.ElementRef<typeof Button>,\n MultiSelectProps\n>(({\n value,\n onValueChange,\n options,\n groups,\n placeholder = \"Selecione...\",\n searchPlaceholder = \"Buscar...\",\n emptyMessage = \"Nenhum resultado encontrado\",\n disabled = false,\n loading = false,\n maxVisibleChips = 2,\n onSearch,\n onCreateOption,\n createOptionLabel,\n className,\n \"aria-label\": ariaLabel,\n \"aria-labelledby\": ariaLabelledby,\n}, ref) => {\n const [open, setOpen] = React.useState(false);\n const [search, setSearch] = React.useState(\"\");\n const [isCreating, setIsCreating] = React.useState(false);\n const triggerRef = React.useRef<HTMLButtonElement>(null);\n const searchInputRef = React.useRef<HTMLInputElement>(null);\n const mergedTriggerRef = React.useMemo(() => mergeRefs(triggerRef, ref), [ref]);\n\n // Callback ref: chamado imediatamente ao montar o elemento (sem timing issue do useEffect).\n // Para a propagação nativa do wheel antes de chegar ao document, onde o\n // react-remove-scroll do Sheet chama preventDefault() em eventos de Portal.\n const listCallbackRef = React.useCallback((el: HTMLDivElement | null) => {\n if (!el) return;\n el.addEventListener(\"wheel\", (e) => e.stopPropagation(), { passive: true });\n }, []);\n\n const allOptions = React.useMemo((): MultiSelectOption[] => {\n if (options) return options;\n if (groups) {\n const groupHeaders: MultiSelectOption[] = groups\n .filter((g) => g.value != null)\n .map((g) => ({ value: g.value!, label: g.label }));\n return [...groupHeaders, ...groups.flatMap((g) => g.options)];\n }\n return [];\n }, [options, groups]);\n\n const isAsyncSearch = !!onSearch;\n\n const filteredOptions = React.useMemo(() => {\n if (!options) return [];\n if (isAsyncSearch) return options;\n const term = search.toLowerCase().trim();\n if (!term) return options;\n return options.filter(\n (o) =>\n o.label.toLowerCase().includes(term) ||\n o.value.toLowerCase().includes(term)\n );\n }, [options, search, isAsyncSearch]);\n\n const filteredGroups = React.useMemo(() => {\n if (!groups) return undefined;\n if (isAsyncSearch) return groups;\n const term = search.toLowerCase().trim();\n if (!term) return groups;\n return groups\n .map((g) => ({\n ...g,\n options: g.options.filter(\n (o) =>\n o.label.toLowerCase().includes(term) ||\n o.value.toLowerCase().includes(term)\n ),\n }))\n .filter((g) => g.options.length > 0);\n }, [groups, search, isAsyncSearch]);\n\n const selectedOptions = React.useMemo(\n () => allOptions.filter((o) => value.includes(o.value)),\n [allOptions, value]\n );\n\n const hasResults = groups\n ? (filteredGroups?.some((g) => g.options.length > 0) ?? false)\n : filteredOptions.length > 0;\n\n const trimmedSearch = search.trim();\n const hasExactMatch = allOptions.some(\n (o) => o.label.trim().toLowerCase() === trimmedSearch.toLowerCase()\n );\n const canCreate = !!onCreateOption && trimmedSearch.length > 0 && !hasExactMatch;\n\n const handleCreate = async () => {\n if (!onCreateOption || isCreating || !trimmedSearch) return;\n setIsCreating(true);\n try {\n await onCreateOption(trimmedSearch);\n setSearch(\"\");\n } catch {\n // Falha na criação: mantém o termo buscado para o usuário corrigir e tentar\n // novamente. O caller é responsável por sinalizar o erro (ex: toast).\n } finally {\n setIsCreating(false);\n }\n };\n\n const handleToggle = (optionValue: string) => {\n if (value.includes(optionValue)) {\n onValueChange(value.filter((v) => v !== optionValue));\n } else {\n onValueChange([...value, optionValue]);\n }\n };\n\n const handleRemoveChip = (optionValue: string, e: React.MouseEvent) => {\n e.stopPropagation();\n onValueChange(value.filter((v) => v !== optionValue));\n };\n\n const handleOpenChange = (next: boolean) => {\n if (disabled) return;\n setOpen(next);\n if (!next) setSearch(\"\");\n };\n\n React.useEffect(() => {\n if (open) onSearch?.(\"\");\n }, [open]);\n\n const handleSearchChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n setSearch(e.target.value);\n onSearch?.(e.target.value);\n };\n\n const visibleChips = selectedOptions.slice(0, maxVisibleChips);\n const overflowCount = selectedOptions.length - maxVisibleChips;\n\n const renderOption = (option: MultiSelectOption) => {\n const selected = value.includes(option.value);\n return (\n <button\n key={option.value}\n type=\"button\"\n role=\"option\"\n aria-selected={selected}\n disabled={option.disabled}\n onClick={() => handleToggle(option.value)}\n className={cn(\n \"flex w-full items-center gap-2 rounded-sm px-2 py-1.5 text-sm\",\n \"hover:bg-accent hover:text-accent-foreground\",\n \"focus:bg-accent focus:text-accent-foreground focus:outline-none\",\n \"transition-colors duration-100\",\n option.disabled && \"pointer-events-none opacity-50\"\n )}\n >\n <Check\n className={cn(\n \"h-4 w-4 shrink-0 transition-opacity duration-100\",\n selected ? \"opacity-100\" : \"opacity-0\"\n )}\n />\n <span className=\"flex-1 text-left truncate\">{option.label}</span>\n {option.badge}\n </button>\n );\n };\n\n return (\n <Popover open={open} onOpenChange={handleOpenChange}>\n <PopoverTrigger asChild>\n <Button\n ref={mergedTriggerRef}\n type=\"button\"\n variant=\"outline\"\n role=\"combobox\"\n aria-expanded={open}\n aria-label={ariaLabel}\n aria-labelledby={ariaLabelledby}\n disabled={disabled}\n className={cn(\n \"w-full min-h-10 h-auto justify-between font-normal px-3 py-2\",\n !value.length && \"text-muted-foreground\",\n className\n )}\n >\n <div className=\"flex flex-wrap items-center gap-1 flex-1 min-w-0\">\n {value.length === 0 ? (\n <span className=\"truncate text-sm\">\n {loading ? \"Carregando...\" : placeholder}\n </span>\n ) : (\n <>\n {visibleChips.map((opt) => (\n <Badge\n key={opt.value}\n variant=\"secondary\"\n className=\"rounded-sm h-5 gap-0.5 pr-1 font-normal max-w-[160px]\"\n >\n <span className=\"truncate text-xs\">{opt.label}</span>\n <span\n role=\"button\"\n tabIndex={0}\n aria-label={`Remover ${opt.label}`}\n className=\"inline-flex items-center justify-center rounded-sm hover:bg-muted/80 cursor-pointer shrink-0 outline-none focus-visible:ring-2 focus-visible:ring-ring/60\"\n onMouseDown={(e) => e.preventDefault()}\n onClick={(e) => handleRemoveChip(opt.value, e)}\n onKeyDown={pressableKeyDown}\n >\n <X className=\"h-3 w-3\" />\n </span>\n </Badge>\n ))}\n {overflowCount > 0 && (\n <Badge\n variant=\"secondary\"\n className=\"rounded-sm h-5 px-1.5 font-normal text-xs shrink-0\"\n >\n +{overflowCount}\n </Badge>\n )}\n </>\n )}\n </div>\n <ChevronsUpDown className=\"ml-2 h-4 w-4 shrink-0 opacity-50\" />\n </Button>\n </PopoverTrigger>\n\n <PopoverContent\n className=\"p-0 overflow-hidden\"\n style={{\n width: triggerRef.current?.offsetWidth\n ? `${triggerRef.current.offsetWidth}px`\n : \"auto\",\n }}\n align=\"start\"\n onOpenAutoFocus={(e) => {\n // O Radix suprime o autofocus padrão quando este Popover está aninhado em um\n // Dialog/Sheet (o focus-trap do pai disputa o foco com o do Popover). Focamos\n // o input manualmente via ref assim que o conteúdo transiciona para visível.\n e.preventDefault();\n searchInputRef.current?.focus();\n }}\n onWheel={(e) => e.stopPropagation()}\n >\n {/* Busca */}\n <div className=\"flex items-center border-b px-3\">\n <Search className=\"mr-2 h-4 w-4 shrink-0 opacity-50\" />\n <Input\n ref={searchInputRef}\n placeholder={searchPlaceholder}\n value={search}\n onChange={handleSearchChange}\n className=\"h-10 border-0 focus-visible:ring-0 focus-visible:ring-offset-0 px-0\"\n />\n </div>\n\n {/* Criar nova opção */}\n {canCreate && (\n <button\n type=\"button\"\n onClick={handleCreate}\n disabled={isCreating}\n className={cn(\n \"flex w-full items-center gap-2 border-b px-3 py-2 text-sm text-primary\",\n \"hover:bg-accent transition-colors duration-100\",\n \"disabled:opacity-50 disabled:pointer-events-none\"\n )}\n >\n {isCreating ? (\n <Loader2 className=\"h-4 w-4 shrink-0 animate-spin\" />\n ) : (\n <Plus className=\"h-4 w-4 shrink-0\" />\n )}\n <span className=\"truncate\">\n {isCreating\n ? \"Criando...\"\n : (createOptionLabel?.(trimmedSearch) ?? `Criar \"${trimmedSearch}\"`)}\n </span>\n </button>\n )}\n\n {/* Lista */}\n <div ref={listCallbackRef} className=\"max-h-70 overflow-y-auto [&::-webkit-scrollbar]:w-2.5 [&::-webkit-scrollbar-track]:bg-transparent [&::-webkit-scrollbar-thumb]:rounded-full [&::-webkit-scrollbar-thumb]:bg-primary/30 [&::-webkit-scrollbar-thumb:hover]:bg-primary/50\">\n <div className=\"p-1\" role=\"listbox\" aria-multiselectable>\n {loading ? (\n <div className=\"flex items-center justify-center gap-2 py-6 text-sm text-muted-foreground\">\n <Loader2 className=\"h-4 w-4 animate-spin\" />\n Carregando...\n </div>\n ) : !hasResults ? (\n <div className=\"py-6 text-center text-sm text-muted-foreground\">\n {emptyMessage}\n </div>\n ) : groups ? (\n filteredGroups?.map((group) => (\n <div key={group.label}>\n {group.value ? (\n <button\n type=\"button\"\n onClick={() => handleToggle(group.value!)}\n className={cn(\n \"flex w-full items-center gap-2 rounded-sm px-2 py-1.5\",\n \"hover:bg-accent hover:text-accent-foreground transition-colors duration-100\",\n value.includes(group.value) && \"text-foreground\"\n )}\n >\n <Check\n className={cn(\n \"h-4 w-4 shrink-0 transition-opacity duration-100\",\n value.includes(group.value) ? \"opacity-100\" : \"opacity-0\"\n )}\n />\n <span className=\"text-xs font-semibold uppercase tracking-wide\">\n {group.label}\n </span>\n </button>\n ) : (\n <div className=\"px-2 py-1.5 text-xs font-semibold text-muted-foreground uppercase tracking-wide\">\n {group.label}\n </div>\n )}\n {group.options.map(renderOption)}\n </div>\n ))\n ) : (\n filteredOptions.map(renderOption)\n )}\n </div>\n </div>\n </PopoverContent>\n </Popover>\n );\n});\nMultiSelect.displayName = \"MultiSelect\";\n\nexport default MultiSelect;\n"],"names":["MultiSelect","React","value","onValueChange","options","groups","placeholder","searchPlaceholder","emptyMessage","disabled","loading","maxVisibleChips","onSearch","onCreateOption","createOptionLabel","className","ariaLabel","ariaLabelledby","ref","open","setOpen","search","setSearch","isCreating","setIsCreating","triggerRef","searchInputRef","mergedTriggerRef","mergeRefs","listCallbackRef","el","e","allOptions","g","isAsyncSearch","filteredOptions","term","o","filteredGroups","selectedOptions","hasResults","trimmedSearch","hasExactMatch","canCreate","handleCreate","handleToggle","optionValue","v","handleRemoveChip","handleOpenChange","next","handleSearchChange","visibleChips","overflowCount","renderOption","option","selected","jsxs","cn","jsx","Check","Popover","PopoverTrigger","Button","Fragment","opt","Badge","pressableKeyDown","X","ChevronsUpDown","PopoverContent","_a","Search","Input","Loader2","Plus","group"],"mappings":"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"}
1
+ {"version":3,"file":"multi-select.js","sources":["../../../../src/components/ui/forms/multi-select.tsx"],"sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\nimport { Check, ChevronsUpDown, X, Search, Loader2, Plus } from \"lucide-react\";\nimport { cn, mergeRefs, pressableKeyDown } from \"../utils\";\nimport { Button } from \"../primitives/button\";\nimport { Badge } from \"../primitives/badge\";\nimport { Popover, PopoverContent, PopoverTrigger } from \"../overlays/popover\";\nimport { Input } from \"./input\";\n\nexport interface MultiSelectOption {\n value: string;\n label: string;\n disabled?: boolean;\n /** Slot para renderização customizada à direita do label — ex: <Badge>Externo</Badge> */\n badge?: React.ReactNode;\n}\n\nexport interface MultiSelectGroup {\n label: string;\n options: MultiSelectOption[];\n /** Quando presente, o header do grupo torna-se clicável e seleciona/deseleciona o grupo */\n value?: string;\n}\n\nexport interface MultiSelectProps {\n /** Valores atualmente selecionados */\n value: string[];\n /** Callback disparado ao alterar a seleção */\n onValueChange: (values: string[]) => void;\n\n /**\n * Opções em lista plana.\n * Use `options` OU `groups` — nunca os dois ao mesmo tempo.\n */\n options?: MultiSelectOption[];\n /**\n * Opções agrupadas hierarquicamente.\n * Use `options` OU `groups` — nunca os dois ao mesmo tempo.\n */\n groups?: MultiSelectGroup[];\n\n placeholder?: string;\n searchPlaceholder?: string;\n emptyMessage?: string;\n\n /** Rótulo acessível do gatilho quando não há `<Label>` associado */\n \"aria-label\"?: string;\n \"aria-labelledby\"?: string;\n\n disabled?: boolean;\n /** Exibe estado de carregamento — substitui a lista por spinner */\n loading?: boolean;\n\n /**\n * Número máximo de chips visíveis no trigger antes de exibir \"+N\".\n * @default 2\n */\n maxVisibleChips?: number;\n\n /**\n * Callback de busca assíncrona — chamado a cada keystroke e ao abrir o dropdown.\n * Quando presente, a filtragem local é desativada (o caller controla `options`/`groups`).\n */\n onSearch?: (query: string) => void;\n\n /**\n * Habilita criação de uma nova opção diretamente no dropdown.\n * Chamado quando o usuário clica em \"Criar '{busca}'\" — o caller é responsável por\n * persistir a opção (ex: chamada de API), atualizar `options`/`value` com o resultado\n * e sinalizar falhas ao usuário (ex: toast). Rejeitar a promise preserva o termo\n * buscado no campo, permitindo corrigir e tentar novamente.\n * Exibido apenas quando não há opção com label idêntico ao termo buscado.\n */\n onCreateOption?: (inputValue: string) => void | Promise<void>;\n /** Customiza o label do botão de criação. @default (query) => `Criar \"${query}\"` */\n createOptionLabel?: (query: string) => string;\n\n className?: string;\n}\n\n/**\n * MultiSelect — Seleção múltipla com chips, busca, grupos hierárquicos e slots de badge por opção.\n *\n * @example\n * ```tsx\n * // Lista plana\n * <MultiSelect\n * value={selectedSquads}\n * onValueChange={setSelectedSquads}\n * options={squads.map(s => ({ value: String(s.id), label: s.name }))}\n * placeholder=\"Selecione os squads\"\n * />\n *\n * // Com badge por opção (ex: funcionários externos)\n * <MultiSelect\n * value={selectedEmployees}\n * onValueChange={setSelectedEmployees}\n * options={employees.map(e => ({\n * value: String(e.id),\n * label: e.name,\n * badge: e.isExternalUser\n * ? <Badge variant=\"secondary\" className=\"text-xs\">Externo</Badge>\n * : undefined,\n * }))}\n * />\n *\n * // Lista hierárquica (grupos de clientes)\n * <MultiSelect\n * value={selectedClients}\n * onValueChange={setSelectedClients}\n * groups={customerGroups.map(g => ({\n * label: g.name,\n * options: g.children.map(c => ({ value: String(c.id), label: c.name })),\n * }))}\n * />\n * ```\n */\nexport const MultiSelect = React.forwardRef<\n React.ElementRef<typeof Button>,\n MultiSelectProps\n>(({\n value,\n onValueChange,\n options,\n groups,\n placeholder = \"Selecione...\",\n searchPlaceholder = \"Buscar...\",\n emptyMessage = \"Nenhum resultado encontrado\",\n disabled = false,\n loading = false,\n maxVisibleChips = 2,\n onSearch,\n onCreateOption,\n createOptionLabel,\n className,\n \"aria-label\": ariaLabel,\n \"aria-labelledby\": ariaLabelledby,\n}, ref) => {\n const [open, setOpen] = React.useState(false);\n const [search, setSearch] = React.useState(\"\");\n const [isCreating, setIsCreating] = React.useState(false);\n const triggerRef = React.useRef<HTMLButtonElement>(null);\n const searchInputRef = React.useRef<HTMLInputElement>(null);\n const mergedTriggerRef = React.useMemo(() => mergeRefs(triggerRef, ref), [ref]);\n\n // Callback ref: chamado imediatamente ao montar o elemento (sem timing issue do useEffect).\n // Para a propagação nativa do wheel antes de chegar ao document, onde o\n // react-remove-scroll do Sheet chama preventDefault() em eventos de Portal.\n const listCallbackRef = React.useCallback((el: HTMLDivElement | null) => {\n if (!el) return;\n el.addEventListener(\"wheel\", (e) => e.stopPropagation(), { passive: true });\n }, []);\n\n const allOptions = React.useMemo((): MultiSelectOption[] => {\n if (options) return options;\n if (groups) {\n const groupHeaders: MultiSelectOption[] = groups\n .filter((g) => g.value != null)\n .map((g) => ({ value: g.value!, label: g.label }));\n return [...groupHeaders, ...groups.flatMap((g) => g.options)];\n }\n return [];\n }, [options, groups]);\n\n const isAsyncSearch = !!onSearch;\n\n const filteredOptions = React.useMemo(() => {\n if (!options) return [];\n if (isAsyncSearch) return options;\n const term = search.toLowerCase().trim();\n if (!term) return options;\n return options.filter(\n (o) =>\n o.label.toLowerCase().includes(term) ||\n o.value.toLowerCase().includes(term)\n );\n }, [options, search, isAsyncSearch]);\n\n const filteredGroups = React.useMemo(() => {\n if (!groups) return undefined;\n if (isAsyncSearch) return groups;\n const term = search.toLowerCase().trim();\n if (!term) return groups;\n return groups\n .map((g) => ({\n ...g,\n options: g.options.filter(\n (o) =>\n o.label.toLowerCase().includes(term) ||\n o.value.toLowerCase().includes(term)\n ),\n }))\n .filter((g) => g.options.length > 0);\n }, [groups, search, isAsyncSearch]);\n\n const selectedOptions = React.useMemo(\n () => allOptions.filter((o) => value.includes(o.value)),\n [allOptions, value]\n );\n\n const hasResults = groups\n ? (filteredGroups?.some((g) => g.options.length > 0) ?? false)\n : filteredOptions.length > 0;\n\n const trimmedSearch = search.trim();\n const hasExactMatch = allOptions.some(\n (o) => o.label.trim().toLowerCase() === trimmedSearch.toLowerCase()\n );\n const canCreate = !!onCreateOption && trimmedSearch.length > 0 && !hasExactMatch;\n\n const handleCreate = async () => {\n if (!onCreateOption || isCreating || !trimmedSearch) return;\n setIsCreating(true);\n try {\n await onCreateOption(trimmedSearch);\n setSearch(\"\");\n } catch {\n // Falha na criação: mantém o termo buscado para o usuário corrigir e tentar\n // novamente. O caller é responsável por sinalizar o erro (ex: toast).\n } finally {\n setIsCreating(false);\n }\n };\n\n const handleToggle = (optionValue: string) => {\n if (value.includes(optionValue)) {\n onValueChange(value.filter((v) => v !== optionValue));\n } else {\n onValueChange([...value, optionValue]);\n }\n };\n\n const handleRemoveChip = (optionValue: string, e: React.MouseEvent) => {\n e.stopPropagation();\n onValueChange(value.filter((v) => v !== optionValue));\n };\n\n const handleOpenChange = (next: boolean) => {\n if (disabled) return;\n setOpen(next);\n if (!next) setSearch(\"\");\n };\n\n React.useEffect(() => {\n if (open) onSearch?.(\"\");\n }, [open]);\n\n const handleSearchChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n setSearch(e.target.value);\n onSearch?.(e.target.value);\n };\n\n const visibleChips = selectedOptions.slice(0, maxVisibleChips);\n const overflowCount = selectedOptions.length - maxVisibleChips;\n\n const renderOption = (option: MultiSelectOption) => {\n const selected = value.includes(option.value);\n return (\n <button\n key={option.value}\n type=\"button\"\n role=\"option\"\n aria-selected={selected}\n disabled={option.disabled}\n onClick={() => handleToggle(option.value)}\n className={cn(\n \"flex w-full items-center gap-2 rounded-sm px-2 py-1.5 text-sm\",\n \"aria-selected:bg-secondary aria-selected:text-secondary-foreground aria-selected:font-medium\",\n \"not-aria-selected:hover:bg-accent not-aria-selected:hover:text-accent-foreground\",\n \"focus:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-inset\",\n \"transition-colors duration-100\",\n option.disabled && \"pointer-events-none opacity-50\"\n )}\n >\n <Check\n className={cn(\n \"h-4 w-4 shrink-0 transition-opacity duration-100\",\n selected ? \"opacity-100\" : \"opacity-0\"\n )}\n />\n <span className=\"flex-1 text-left truncate\">{option.label}</span>\n {option.badge}\n </button>\n );\n };\n\n return (\n <Popover open={open} onOpenChange={handleOpenChange}>\n <PopoverTrigger asChild>\n <Button\n ref={mergedTriggerRef}\n type=\"button\"\n variant=\"outline\"\n role=\"combobox\"\n aria-expanded={open}\n aria-label={ariaLabel}\n aria-labelledby={ariaLabelledby}\n disabled={disabled}\n className={cn(\n \"w-full min-h-10 h-auto justify-between font-normal px-3 py-2\",\n !value.length && \"text-muted-foreground\",\n className\n )}\n >\n <div className=\"flex flex-wrap items-center gap-1 flex-1 min-w-0\">\n {value.length === 0 ? (\n <span className=\"truncate text-sm\">\n {loading ? \"Carregando...\" : placeholder}\n </span>\n ) : (\n <>\n {visibleChips.map((opt) => (\n <Badge\n key={opt.value}\n variant=\"secondary\"\n className=\"rounded-sm h-5 gap-0.5 pr-1 font-normal max-w-[160px]\"\n >\n <span className=\"truncate text-xs\">{opt.label}</span>\n <span\n role=\"button\"\n tabIndex={0}\n aria-label={`Remover ${opt.label}`}\n className=\"inline-flex items-center justify-center rounded-sm hover:bg-muted/80 cursor-pointer shrink-0 outline-none focus-visible:ring-2 focus-visible:ring-ring/60\"\n onMouseDown={(e) => e.preventDefault()}\n onClick={(e) => handleRemoveChip(opt.value, e)}\n onKeyDown={pressableKeyDown}\n >\n <X className=\"h-3 w-3\" />\n </span>\n </Badge>\n ))}\n {overflowCount > 0 && (\n <Badge\n variant=\"secondary\"\n className=\"rounded-sm h-5 px-1.5 font-normal text-xs shrink-0\"\n >\n +{overflowCount}\n </Badge>\n )}\n </>\n )}\n </div>\n <ChevronsUpDown className=\"ml-2 h-4 w-4 shrink-0 opacity-50\" />\n </Button>\n </PopoverTrigger>\n\n <PopoverContent\n className=\"p-0 overflow-hidden\"\n style={{\n width: triggerRef.current?.offsetWidth\n ? `${triggerRef.current.offsetWidth}px`\n : \"auto\",\n }}\n align=\"start\"\n onOpenAutoFocus={(e) => {\n // O Radix suprime o autofocus padrão quando este Popover está aninhado em um\n // Dialog/Sheet (o focus-trap do pai disputa o foco com o do Popover). Focamos\n // o input manualmente via ref assim que o conteúdo transiciona para visível.\n e.preventDefault();\n searchInputRef.current?.focus();\n }}\n onWheel={(e) => e.stopPropagation()}\n >\n {/* Busca */}\n <div className=\"flex items-center border-b px-3\">\n <Search className=\"mr-2 h-4 w-4 shrink-0 opacity-50\" />\n <Input\n ref={searchInputRef}\n placeholder={searchPlaceholder}\n value={search}\n onChange={handleSearchChange}\n className=\"h-10 border-0 focus-visible:ring-0 focus-visible:ring-offset-0 px-0\"\n />\n </div>\n\n {/* Criar nova opção */}\n {canCreate && (\n <button\n type=\"button\"\n onClick={handleCreate}\n disabled={isCreating}\n className={cn(\n \"flex w-full items-center gap-2 border-b px-3 py-2 text-sm text-primary\",\n // hover neutro: roxo sobre accent (gray-600) no escuro dá 4,4:1\n \"hover:bg-accent hover:text-accent-foreground transition-colors duration-100\",\n \"disabled:opacity-50 disabled:pointer-events-none\"\n )}\n >\n {isCreating ? (\n <Loader2 className=\"h-4 w-4 shrink-0 animate-spin\" />\n ) : (\n <Plus className=\"h-4 w-4 shrink-0\" />\n )}\n <span className=\"truncate\">\n {isCreating\n ? \"Criando...\"\n : (createOptionLabel?.(trimmedSearch) ?? `Criar \"${trimmedSearch}\"`)}\n </span>\n </button>\n )}\n\n {/* Lista */}\n <div ref={listCallbackRef} className=\"max-h-70 overflow-y-auto [&::-webkit-scrollbar]:w-2.5 [&::-webkit-scrollbar-track]:bg-transparent [&::-webkit-scrollbar-thumb]:rounded-full [&::-webkit-scrollbar-thumb]:bg-primary/30 [&::-webkit-scrollbar-thumb:hover]:bg-primary/50\">\n <div className=\"p-1\" role=\"listbox\" aria-multiselectable>\n {loading ? (\n <div className=\"flex items-center justify-center gap-2 py-6 text-sm text-muted-foreground\">\n <Loader2 className=\"h-4 w-4 animate-spin\" />\n Carregando...\n </div>\n ) : !hasResults ? (\n <div className=\"py-6 text-center text-sm text-muted-foreground\">\n {emptyMessage}\n </div>\n ) : groups ? (\n filteredGroups?.map((group) => (\n <div key={group.label}>\n {group.value ? (\n <button\n type=\"button\"\n onClick={() => handleToggle(group.value!)}\n className={cn(\n \"flex w-full items-center gap-2 rounded-sm px-2 py-1.5\",\n \"hover:bg-accent hover:text-accent-foreground transition-colors duration-100\",\n value.includes(group.value) && \"text-foreground\"\n )}\n >\n <Check\n className={cn(\n \"h-4 w-4 shrink-0 transition-opacity duration-100\",\n value.includes(group.value) ? \"opacity-100\" : \"opacity-0\"\n )}\n />\n <span className=\"text-xs font-semibold uppercase tracking-wide\">\n {group.label}\n </span>\n </button>\n ) : (\n <div className=\"px-2 py-1.5 text-xs font-semibold text-muted-foreground uppercase tracking-wide\">\n {group.label}\n </div>\n )}\n {group.options.map(renderOption)}\n </div>\n ))\n ) : (\n filteredOptions.map(renderOption)\n )}\n </div>\n </div>\n </PopoverContent>\n </Popover>\n );\n});\nMultiSelect.displayName = \"MultiSelect\";\n\nexport default MultiSelect;\n"],"names":["MultiSelect","React","value","onValueChange","options","groups","placeholder","searchPlaceholder","emptyMessage","disabled","loading","maxVisibleChips","onSearch","onCreateOption","createOptionLabel","className","ariaLabel","ariaLabelledby","ref","open","setOpen","search","setSearch","isCreating","setIsCreating","triggerRef","searchInputRef","mergedTriggerRef","mergeRefs","listCallbackRef","el","e","allOptions","g","isAsyncSearch","filteredOptions","term","o","filteredGroups","selectedOptions","hasResults","trimmedSearch","hasExactMatch","canCreate","handleCreate","handleToggle","optionValue","v","handleRemoveChip","handleOpenChange","next","handleSearchChange","visibleChips","overflowCount","renderOption","option","selected","jsxs","cn","jsx","Check","Popover","PopoverTrigger","Button","Fragment","opt","Badge","pressableKeyDown","X","ChevronsUpDown","PopoverContent","_a","Search","Input","Loader2","Plus","group"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- "use client";"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const o=require("react/jsx-runtime"),u=require("react"),m=require("@radix-ui/react-radio-group"),s=require("../utils.cjs");function d(e){const r=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(e){for(const t in e)if(t!=="default"){const i=Object.getOwnPropertyDescriptor(e,t);Object.defineProperty(r,t,i.get?i:{enumerable:!0,get:()=>e[t]})}}return r.default=e,Object.freeze(r)}const c=d(u),a=d(m),n=c.forwardRef(({className:e,...r},t)=>o.jsx(a.Root,{ref:t,"data-slot":"radio-group",className:s.cn("grid gap-3",e),...r}));n.displayName=a.Root.displayName;const l=c.forwardRef(({className:e,...r},t)=>o.jsx(a.Item,{ref:t,"data-slot":"radio-group-item",className:s.cn("peer h-5 w-5 shrink-0 rounded-full border border-gray-300 bg-white shadow-sm transition-all hover:shadow-md focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring/40 disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:border-primary data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground",e),...r,children:o.jsx(a.Indicator,{"data-slot":"radio-group-indicator",className:"flex items-center justify-center",children:o.jsx("div",{className:"h-2 w-2 rounded-full bg-white"})})}));l.displayName=a.Item.displayName;exports.RadioGroup=n;exports.RadioGroupItem=l;
1
+ "use client";"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const a=require("react/jsx-runtime"),l=require("react"),m=require("@radix-ui/react-radio-group"),s=require("../utils.cjs");function d(e){const t=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(e){for(const r in e)if(r!=="default"){const i=Object.getOwnPropertyDescriptor(e,r);Object.defineProperty(t,r,i.get?i:{enumerable:!0,get:()=>e[r]})}}return t.default=e,Object.freeze(t)}const n=d(l),o=d(m),c=n.forwardRef(({className:e,...t},r)=>a.jsx(o.Root,{ref:r,"data-slot":"radio-group",className:s.cn("grid gap-3",e),...t}));c.displayName=o.Root.displayName;const u=n.forwardRef(({className:e,...t},r)=>a.jsx(o.Item,{ref:r,"data-slot":"radio-group-item",className:s.cn("peer h-5 w-5 shrink-0 rounded-full border border-input bg-background shadow-sm transition-all hover:shadow-md focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring/40 disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:border-primary data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground",e),...t,children:a.jsx(o.Indicator,{"data-slot":"radio-group-indicator",className:"flex items-center justify-center",children:a.jsx("div",{className:"h-2 w-2 rounded-full bg-primary-foreground"})})}));u.displayName=o.Item.displayName;exports.RadioGroup=c;exports.RadioGroupItem=u;
2
2
  //# sourceMappingURL=radio-group.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"radio-group.cjs","sources":["../../../../src/components/ui/forms/radio-group.tsx"],"sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\nimport * as RadioGroupPrimitive from \"@radix-ui/react-radio-group\";\n\nimport { cn } from \"../utils\";\n\nconst RadioGroup = React.forwardRef<\n React.ElementRef<typeof RadioGroupPrimitive.Root>,\n React.ComponentPropsWithoutRef<typeof RadioGroupPrimitive.Root>\n>(({ className, ...props }, ref) => (\n <RadioGroupPrimitive.Root\n ref={ref}\n data-slot=\"radio-group\"\n className={cn(\"grid gap-3\", className)}\n {...props}\n />\n));\nRadioGroup.displayName = RadioGroupPrimitive.Root.displayName;\n\nconst RadioGroupItem = React.forwardRef<\n React.ElementRef<typeof RadioGroupPrimitive.Item>,\n React.ComponentPropsWithoutRef<typeof RadioGroupPrimitive.Item>\n>(({ className, ...props }, ref) => (\n <RadioGroupPrimitive.Item\n ref={ref}\n data-slot=\"radio-group-item\"\n className={cn(\n \"peer h-5 w-5 shrink-0 rounded-full border border-gray-300 bg-white shadow-sm transition-all hover:shadow-md focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring/40 disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:border-primary data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground\",\n className,\n )}\n {...props}\n >\n <RadioGroupPrimitive.Indicator\n data-slot=\"radio-group-indicator\"\n className=\"flex items-center justify-center\"\n >\n <div className=\"h-2 w-2 rounded-full bg-white\" />\n </RadioGroupPrimitive.Indicator>\n </RadioGroupPrimitive.Item>\n));\nRadioGroupItem.displayName = RadioGroupPrimitive.Item.displayName;\n\nexport { RadioGroup, RadioGroupItem };\n"],"names":["RadioGroup","React","className","props","ref","jsx","RadioGroupPrimitive","cn","RadioGroupItem"],"mappings":"yfAOMA,EAAaC,EAAM,WAGvB,CAAC,CAAE,UAAAC,EAAW,GAAGC,CAAA,EAASC,IAC1BC,EAAAA,IAACC,EAAoB,KAApB,CACC,IAAAF,EACA,YAAU,cACV,UAAWG,EAAAA,GAAG,aAAcL,CAAS,EACpC,GAAGC,CAAA,CACN,CACD,EACDH,EAAW,YAAcM,EAAoB,KAAK,YAElD,MAAME,EAAiBP,EAAM,WAG3B,CAAC,CAAE,UAAAC,EAAW,GAAGC,CAAA,EAASC,IAC1BC,EAAAA,IAACC,EAAoB,KAApB,CACC,IAAAF,EACA,YAAU,mBACV,UAAWG,EAAAA,GACT,0VACAL,CAAA,EAED,GAAGC,EAEJ,SAAAE,EAAAA,IAACC,EAAoB,UAApB,CACC,YAAU,wBACV,UAAU,mCAEV,SAAAD,EAAAA,IAAC,MAAA,CAAI,UAAU,+BAAA,CAAgC,CAAA,CAAA,CACjD,CACF,CACD,EACDG,EAAe,YAAcF,EAAoB,KAAK"}
1
+ {"version":3,"file":"radio-group.cjs","sources":["../../../../src/components/ui/forms/radio-group.tsx"],"sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\nimport * as RadioGroupPrimitive from \"@radix-ui/react-radio-group\";\n\nimport { cn } from \"../utils\";\n\nconst RadioGroup = React.forwardRef<\n React.ElementRef<typeof RadioGroupPrimitive.Root>,\n React.ComponentPropsWithoutRef<typeof RadioGroupPrimitive.Root>\n>(({ className, ...props }, ref) => (\n <RadioGroupPrimitive.Root\n ref={ref}\n data-slot=\"radio-group\"\n className={cn(\"grid gap-3\", className)}\n {...props}\n />\n));\nRadioGroup.displayName = RadioGroupPrimitive.Root.displayName;\n\nconst RadioGroupItem = React.forwardRef<\n React.ElementRef<typeof RadioGroupPrimitive.Item>,\n React.ComponentPropsWithoutRef<typeof RadioGroupPrimitive.Item>\n>(({ className, ...props }, ref) => (\n <RadioGroupPrimitive.Item\n ref={ref}\n data-slot=\"radio-group-item\"\n className={cn(\n \"peer h-5 w-5 shrink-0 rounded-full border border-input bg-background shadow-sm transition-all hover:shadow-md focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring/40 disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:border-primary data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground\",\n className,\n )}\n {...props}\n >\n <RadioGroupPrimitive.Indicator\n data-slot=\"radio-group-indicator\"\n className=\"flex items-center justify-center\"\n >\n <div className=\"h-2 w-2 rounded-full bg-primary-foreground\" />\n </RadioGroupPrimitive.Indicator>\n </RadioGroupPrimitive.Item>\n));\nRadioGroupItem.displayName = RadioGroupPrimitive.Item.displayName;\n\nexport { RadioGroup, RadioGroupItem };\n"],"names":["RadioGroup","React","className","props","ref","jsx","RadioGroupPrimitive","cn","RadioGroupItem"],"mappings":"yfAOMA,EAAaC,EAAM,WAGvB,CAAC,CAAE,UAAAC,EAAW,GAAGC,CAAA,EAASC,IAC1BC,EAAAA,IAACC,EAAoB,KAApB,CACC,IAAAF,EACA,YAAU,cACV,UAAWG,EAAAA,GAAG,aAAcL,CAAS,EACpC,GAAGC,CAAA,CACN,CACD,EACDH,EAAW,YAAcM,EAAoB,KAAK,YAElD,MAAME,EAAiBP,EAAM,WAG3B,CAAC,CAAE,UAAAC,EAAW,GAAGC,CAAA,EAASC,IAC1BC,EAAAA,IAACC,EAAoB,KAApB,CACC,IAAAF,EACA,YAAU,mBACV,UAAWG,EAAAA,GACT,4VACAL,CAAA,EAED,GAAGC,EAEJ,SAAAE,EAAAA,IAACC,EAAoB,UAApB,CACC,YAAU,wBACV,UAAU,mCAEV,SAAAD,EAAAA,IAAC,MAAA,CAAI,UAAU,4CAAA,CAA6C,CAAA,CAAA,CAC9D,CACF,CACD,EACDG,EAAe,YAAcF,EAAoB,KAAK"}