@greatapps/common 1.1.752 → 1.1.753

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/components/ui/form/ComboboxField.tsx"],"sourcesContent":["'use client';\n\nimport { useState, useMemo } from 'react';\nimport { useTranslations } from 'next-intl';\nimport { IconCheck, IconChevronDown, IconSearch } from '@tabler/icons-react';\nimport { Popover, PopoverContent, PopoverTrigger } from '../overlay/Popover';\nimport { cn } from '../../../infra/utils/clsx';\n\nexport type ComboboxOption = {\n value: string;\n label: string;\n displayValue?: string;\n};\n\ninterface ComboboxFieldProps {\n options: ComboboxOption[];\n label?: string;\n placeholder?: string;\n searchPlaceholder?: string;\n emptyMessage?: string;\n value?: string;\n onChange?: (value: string) => void;\n disabled?: boolean;\n icon?: React.ReactNode;\n className?: string;\n containerClassName?: string;\n}\n\nexport function ComboboxField({\n options,\n label,\n placeholder,\n searchPlaceholder,\n emptyMessage,\n value,\n onChange,\n disabled = false,\n icon,\n className,\n containerClassName,\n}: ComboboxFieldProps) {\n const translate = useTranslations();\n const resolvedPlaceholder = placeholder ?? translate('common.forms.combobox.placeholder');\n const resolvedSearchPlaceholder = searchPlaceholder ?? translate('common.forms.combobox.searchPlaceholder');\n const resolvedEmptyMessage = emptyMessage ?? translate('common.forms.combobox.emptyMessage');\n const [open, setOpen] = useState(false);\n const [search, setSearch] = useState('');\n\n const selectedOption = useMemo(\n () => options.find((o) => o.value === value),\n [options, value]\n );\n\n const filteredOptions = useMemo(() => {\n const q = search.trim().toLowerCase();\n if (!q) return options;\n return options.filter((o) => o.label.toLowerCase().includes(q));\n }, [options, search]);\n\n const handleSelect = (optionValue: string) => {\n onChange?.(optionValue);\n setOpen(false);\n setSearch('');\n };\n\n return (\n <div className={cn('flex flex-col gap-1.5', containerClassName)}>\n {label && (\n <div className=\"flex items-center gap-1 paragraph-xsmall-semibold\">\n <span className=\"text-gray-600\">{label}</span>\n </div>\n )}\n\n {/* `modal` é obrigatório para o combobox funcionar dentro de Dialog modal\n * (ex.: Preferências): sem ele, o FocusScope do Dialog rouba o foco no\n * pointerdown da opção (o conteúdo do Popover é portalado pra fora do Dialog)\n * e o Popover fecha antes do click — a opção nunca é selecionada. Com `modal`,\n * o Popover entra na pilha de focus scopes do Radix e pausa o do Dialog. */}\n <Popover\n modal\n open={open}\n onOpenChange={(v) => {\n if (!disabled) {\n setOpen(v);\n if (!v) setSearch('');\n }\n }}\n >\n <PopoverTrigger asChild>\n <button\n type=\"button\"\n disabled={disabled}\n className={cn(\n 'paragraph-small-medium w-full h-10 text-gray-950 px-4 transition-colors',\n 'flex items-center justify-between gap-2 rounded-md border bg-transparent',\n 'border-gray-200 hover:border-gray-400 focus:border-gray-950 focus:outline-none',\n disabled ? 'cursor-not-allowed opacity-50' : 'cursor-pointer',\n className\n )}\n >\n <span className={cn('truncate text-left', !selectedOption && 'text-gray-400')}>\n {selectedOption\n ? (selectedOption.displayValue ?? selectedOption.label)\n : resolvedPlaceholder}\n </span>\n {icon ?? (\n <IconChevronDown\n className={cn(\n 'size-4 opacity-50 shrink-0 transition-all duration-200',\n open && 'rotate-180 opacity-100 text-gray-950'\n )}\n />\n )}\n </button>\n </PopoverTrigger>\n\n <PopoverContent\n className=\"p-0 overflow-hidden rounded-md border shadow-md\"\n align=\"start\"\n sideOffset={4}\n style={{ width: 'var(--radix-popover-trigger-width)' }}\n onWheel={(e) => e.stopPropagation()}\n >\n <div className=\"flex items-center gap-2 border-b border-gray-100 px-3 h-9\">\n <IconSearch className=\"size-4 shrink-0 opacity-50 text-gray-500\" />\n <input\n autoFocus\n placeholder={resolvedSearchPlaceholder}\n value={search}\n onChange={(e) => setSearch(e.target.value)}\n className=\"flex h-full w-full bg-transparent text-sm outline-none placeholder:text-gray-400 paragraph-small-medium text-gray-950\"\n />\n </div>\n\n <div className=\"overflow-y-auto max-h-[280px] p-1\">\n {filteredOptions.length === 0 ? (\n <p className=\"py-6 text-center paragraph-small-medium text-gray-500\">{resolvedEmptyMessage}</p>\n ) : (\n filteredOptions.map((option) => {\n const isSelected = value === option.value;\n return (\n <div\n key={option.value}\n className={cn(\n 'flex items-center gap-2 rounded-sm px-2 h-9 cursor-pointer select-none',\n 'paragraph-small-medium text-gray-950',\n 'hover:bg-gray-100',\n isSelected && 'bg-gray-50'\n )}\n onClick={() => handleSelect(option.value)}\n >\n <span className=\"flex-1 truncate\">{option.label}</span>\n {isSelected && <IconCheck className=\"size-4 shrink-0 text-pages-600\" />}\n </div>\n );\n })\n )}\n </div>\n </PopoverContent>\n </Popover>\n </div>\n );\n}\n\nexport default ComboboxField;\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../../../src/components/ui/form/ComboboxField.tsx"],"sourcesContent":["'use client';\n\nimport { useState, useMemo } from 'react';\nimport { useTranslations } from 'next-intl';\nimport { IconCheck, IconChevronDown, IconSearch } from '@tabler/icons-react';\nimport { Popover, PopoverContent, PopoverTrigger } from '../overlay/Popover';\nimport { cn } from '../../../infra/utils/clsx';\n\nexport type ComboboxOption = {\n value: string;\n label: string;\n displayValue?: string;\n};\n\ninterface ComboboxFieldProps {\n options: ComboboxOption[];\n label?: string;\n placeholder?: string;\n searchPlaceholder?: string;\n emptyMessage?: string;\n value?: string;\n onChange?: (value: string) => void;\n disabled?: boolean;\n icon?: React.ReactNode;\n className?: string;\n containerClassName?: string;\n}\n\nexport function ComboboxField({\n options,\n label,\n placeholder,\n searchPlaceholder,\n emptyMessage,\n value,\n onChange,\n disabled = false,\n icon,\n className,\n containerClassName,\n}: ComboboxFieldProps) {\n const translate = useTranslations();\n const resolvedPlaceholder = placeholder ?? translate('common.forms.combobox.placeholder');\n const resolvedSearchPlaceholder = searchPlaceholder ?? translate('common.forms.combobox.searchPlaceholder');\n const resolvedEmptyMessage = emptyMessage ?? translate('common.forms.combobox.emptyMessage');\n const [open, setOpen] = useState(false);\n const [search, setSearch] = useState('');\n\n const selectedOption = useMemo(\n () => options.find((o) => o.value === value),\n [options, value]\n );\n\n const filteredOptions = useMemo(() => {\n const q = search.trim().toLowerCase();\n if (!q) return options;\n return options.filter((o) => o.label.toLowerCase().includes(q));\n }, [options, search]);\n\n const handleSelect = (optionValue: string) => {\n onChange?.(optionValue);\n setOpen(false);\n setSearch('');\n };\n\n return (\n <div className={cn('flex flex-col gap-1.5', containerClassName)}>\n {label && (\n <div className=\"flex items-center gap-1 paragraph-xsmall-semibold\">\n <span className=\"text-gray-600\">{label}</span>\n </div>\n )}\n\n {/* `modal` é obrigatório para o combobox funcionar dentro de Dialog modal\n * (ex.: Preferências): sem ele, o FocusScope do Dialog rouba o foco no\n * pointerdown da opção (o conteúdo do Popover é portalado pra fora do Dialog)\n * e o Popover fecha antes do click — a opção nunca é selecionada. Com `modal`,\n * o Popover entra na pilha de focus scopes do Radix e pausa o do Dialog.\n *\n * ⚠️ Essa pilha é um singleton POR INSTÂNCIA de @radix-ui/react-focus-scope:\n * react-dialog e react-popover precisam resolver para a MESMA versão dele\n * (manter os dois pins do package.json na mesma linha de release). Com duas\n * cópias, o trap do Dialog não é pausado e rouba o foco do input de busca a\n * cada clique — impossível digitar. */}\n <Popover\n modal\n open={open}\n onOpenChange={(v) => {\n if (!disabled) {\n setOpen(v);\n if (!v) setSearch('');\n }\n }}\n >\n <PopoverTrigger asChild>\n <button\n type=\"button\"\n disabled={disabled}\n className={cn(\n 'paragraph-small-medium w-full h-10 text-gray-950 px-4 transition-colors',\n 'flex items-center justify-between gap-2 rounded-md border bg-transparent',\n 'border-gray-200 hover:border-gray-400 focus:border-gray-950 focus:outline-none',\n disabled ? 'cursor-not-allowed opacity-50' : 'cursor-pointer',\n className\n )}\n >\n <span className={cn('truncate text-left', !selectedOption && 'text-gray-400')}>\n {selectedOption\n ? (selectedOption.displayValue ?? selectedOption.label)\n : resolvedPlaceholder}\n </span>\n {icon ?? (\n <IconChevronDown\n className={cn(\n 'size-4 opacity-50 shrink-0 transition-all duration-200',\n open && 'rotate-180 opacity-100 text-gray-950'\n )}\n />\n )}\n </button>\n </PopoverTrigger>\n\n <PopoverContent\n className=\"p-0 overflow-hidden rounded-md border shadow-md\"\n align=\"start\"\n sideOffset={4}\n style={{ width: 'var(--radix-popover-trigger-width)' }}\n onWheel={(e) => e.stopPropagation()}\n >\n <div className=\"flex items-center gap-2 border-b border-gray-100 px-3 h-9\">\n <IconSearch className=\"size-4 shrink-0 opacity-50 text-gray-500\" />\n <input\n autoFocus\n placeholder={resolvedSearchPlaceholder}\n value={search}\n onChange={(e) => setSearch(e.target.value)}\n className=\"flex h-full w-full bg-transparent text-sm outline-none placeholder:text-gray-400 paragraph-small-medium text-gray-950\"\n />\n </div>\n\n <div className=\"overflow-y-auto max-h-[280px] p-1\">\n {filteredOptions.length === 0 ? (\n <p className=\"py-6 text-center paragraph-small-medium text-gray-500\">{resolvedEmptyMessage}</p>\n ) : (\n filteredOptions.map((option) => {\n const isSelected = value === option.value;\n return (\n <div\n key={option.value}\n className={cn(\n 'flex items-center gap-2 rounded-sm px-2 h-9 cursor-pointer select-none',\n 'paragraph-small-medium text-gray-950',\n 'hover:bg-gray-100',\n isSelected && 'bg-gray-50'\n )}\n onClick={() => handleSelect(option.value)}\n >\n <span className=\"flex-1 truncate\">{option.label}</span>\n {isSelected && <IconCheck className=\"size-4 shrink-0 text-pages-600\" />}\n </div>\n );\n })\n )}\n </div>\n </PopoverContent>\n </Popover>\n </div>\n );\n}\n\nexport default ComboboxField;\n"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@greatapps/common",
3
- "version": "1.1.752",
3
+ "version": "1.1.753",
4
4
  "description": "Shared library for GreatApps frontend applications",
5
5
  "main": "./dist/index.mjs",
6
6
  "types": "./src/index.ts",
@@ -61,7 +61,7 @@
61
61
  "@greatapps/jwt": "1.0.12",
62
62
  "@radix-ui/react-accordion": "1.2.12",
63
63
  "@radix-ui/react-checkbox": "1.3.3",
64
- "@radix-ui/react-dialog": "1.1.23",
64
+ "@radix-ui/react-dialog": "1.1.15",
65
65
  "@radix-ui/react-popover": "1.1.15",
66
66
  "@radix-ui/react-progress": "1.1.8",
67
67
  "@radix-ui/react-radio-group": "1.3.8",
@@ -75,7 +75,13 @@ export function ComboboxField({
75
75
  * (ex.: Preferências): sem ele, o FocusScope do Dialog rouba o foco no
76
76
  * pointerdown da opção (o conteúdo do Popover é portalado pra fora do Dialog)
77
77
  * e o Popover fecha antes do click — a opção nunca é selecionada. Com `modal`,
78
- * o Popover entra na pilha de focus scopes do Radix e pausa o do Dialog. */}
78
+ * o Popover entra na pilha de focus scopes do Radix e pausa o do Dialog.
79
+ *
80
+ * ⚠️ Essa pilha é um singleton POR INSTÂNCIA de @radix-ui/react-focus-scope:
81
+ * react-dialog e react-popover precisam resolver para a MESMA versão dele
82
+ * (manter os dois pins do package.json na mesma linha de release). Com duas
83
+ * cópias, o trap do Dialog não é pausado e rouba o foco do input de busca a
84
+ * cada clique — impossível digitar. */}
79
85
  <Popover
80
86
  modal
81
87
  open={open}