forlogic-core 1.8.14 → 1.8.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +272 -200
- package/dist/README.md +272 -200
- package/dist/index.esm.js +1 -1
- package/dist/index.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1923,30 +1923,9 @@ KR1 50% dos indicadores de empreendimento e áreas de negócio atingindo a meta
|
|
|
1923
1923
|
|
|
1924
1924
|
O `forlogic-core` suporta enriquecimento automático de **múltiplos campos de ID de usuário** com dados do Qualiex (nome, email, username).
|
|
1925
1925
|
|
|
1926
|
-
#### **
|
|
1926
|
+
#### **Como Funciona**
|
|
1927
1927
|
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
```typescript
|
|
1931
|
-
import { setQualiexConfig } from 'forlogic-core';
|
|
1932
|
-
|
|
1933
|
-
// Configuração básica (usa localStorage como fallback)
|
|
1934
|
-
setQualiexConfig({
|
|
1935
|
-
enableUserEnrichment: true,
|
|
1936
|
-
enableUsersApi: true,
|
|
1937
|
-
});
|
|
1938
|
-
|
|
1939
|
-
// Configuração avançada (recomendado)
|
|
1940
|
-
setQualiexConfig({
|
|
1941
|
-
enableUserEnrichment: true,
|
|
1942
|
-
enableUsersApi: true,
|
|
1943
|
-
getAccessToken: () => localStorage.getItem('qualiex_access_token'),
|
|
1944
|
-
getCompanyId: () => localStorage.getItem('selectedUnitId'),
|
|
1945
|
-
userNameFieldSuffix: '_name', // default
|
|
1946
|
-
userEmailFieldSuffix: '_email', // default
|
|
1947
|
-
userUsernameFieldSuffix: '_username', // default
|
|
1948
|
-
});
|
|
1949
|
-
```
|
|
1928
|
+
O enriquecimento é **explícito e controlado por serviço**, não requer configuração global. Você decide quando enriquecer ativando `enableQualiexEnrichment` nos serviços.
|
|
1950
1929
|
|
|
1951
1930
|
#### **Uso Básico: Lista de Campos de ID**
|
|
1952
1931
|
|
|
@@ -2059,21 +2038,61 @@ const { service } = createSimpleService({
|
|
|
2059
2038
|
✅ **Type-safe**: TypeScript valida configurações
|
|
2060
2039
|
✅ **Retrocompatível**: Projetos antigos continuam funcionando
|
|
2061
2040
|
|
|
2041
|
+
#### **Hook useQualiexUsers - Controle Explícito**
|
|
2042
|
+
|
|
2043
|
+
Para buscar usuários do Qualiex em componentes, use `enabled: true` explicitamente:
|
|
2044
|
+
|
|
2045
|
+
```typescript
|
|
2046
|
+
import { useQualiexUsers } from 'forlogic-core';
|
|
2047
|
+
|
|
2048
|
+
// ✅ CORRETO: Busca ativa quando enabled=true
|
|
2049
|
+
const { data: users = [] } = useQualiexUsers({ enabled: true });
|
|
2050
|
+
|
|
2051
|
+
// ✅ CORRETO: Busca sob demanda com refetch
|
|
2052
|
+
const { data: users = [], refetch } = useQualiexUsers({ enabled: false });
|
|
2053
|
+
// Depois, quando necessário:
|
|
2054
|
+
await refetch();
|
|
2055
|
+
```
|
|
2056
|
+
|
|
2057
|
+
**Exemplo: Importação de Qualiex**
|
|
2058
|
+
|
|
2059
|
+
```typescript
|
|
2060
|
+
function ImportQualiexButton() {
|
|
2061
|
+
// Não busca automaticamente
|
|
2062
|
+
const { data: qualiexUsers = [], refetch, isLoading } = useQualiexUsers({
|
|
2063
|
+
enabled: false
|
|
2064
|
+
});
|
|
2065
|
+
|
|
2066
|
+
const handleImport = async () => {
|
|
2067
|
+
// Busca apenas quando usuário clica
|
|
2068
|
+
const { data } = await refetch();
|
|
2069
|
+
// Processar data...
|
|
2070
|
+
};
|
|
2071
|
+
|
|
2072
|
+
return <Button onClick={handleImport}>Importar do Qualiex</Button>;
|
|
2073
|
+
}
|
|
2074
|
+
```
|
|
2075
|
+
|
|
2062
2076
|
#### **Boas Práticas**
|
|
2063
2077
|
|
|
2064
|
-
✅ **BOM**:
|
|
2078
|
+
✅ **BOM**: Ativar enrichment apenas onde necessário
|
|
2065
2079
|
|
|
2066
2080
|
```typescript
|
|
2067
|
-
|
|
2068
|
-
|
|
2069
|
-
|
|
2070
|
-
|
|
2071
|
-
|
|
2072
|
-
},
|
|
2073
|
-
getCompanyId: () => myAppStore.getSelectedCompanyId(),
|
|
2081
|
+
const { service } = createSimpleService({
|
|
2082
|
+
tableName: 'processes',
|
|
2083
|
+
entityName: 'Processo',
|
|
2084
|
+
enableQualiexEnrichment: true, // Enriquece dados de usuário
|
|
2085
|
+
userIdFields: ['created_by_id', 'owner_id'],
|
|
2074
2086
|
});
|
|
2075
2087
|
```
|
|
2076
2088
|
|
|
2089
|
+
✅ **BOM**: Usar `enabled: true` apenas quando precisar dos dados
|
|
2090
|
+
|
|
2091
|
+
```typescript
|
|
2092
|
+
// Em um componente que mostra lista de usuários
|
|
2093
|
+
const { data: users } = useQualiexUsers({ enabled: true });
|
|
2094
|
+
```
|
|
2095
|
+
|
|
2077
2096
|
❌ **EVITAR**: Múltiplos campos apontando para o mesmo campo de saída
|
|
2078
2097
|
|
|
2079
2098
|
```typescript
|
|
@@ -5459,78 +5478,131 @@ fetch(url, { headers: { 'un-alias': 'true' } }); // ✅
|
|
|
5459
5478
|
|
|
5460
5479
|
---
|
|
5461
5480
|
|
|
5462
|
-
## 🔍
|
|
5481
|
+
## 🔍 COMPONENTE DE SELEÇÃO: SelectSearch
|
|
5463
5482
|
|
|
5464
|
-
### **
|
|
5483
|
+
### **SelectSearch** - Componente Unificado de Seleção
|
|
5465
5484
|
|
|
5466
|
-
|
|
5467
|
-
|------------|----------------|------|-----------------|
|
|
5468
|
-
| **SelectSearch** | Seleção versátil (única OU múltipla) | Configurável | Mais flexível, ideal para formulários dinâmicos |
|
|
5469
|
-
| **MultiSelect** | Seleção múltipla apenas | Múltiplo (default) | Otimizado para badges, limite de badges exibidos |
|
|
5470
|
-
| **EntitySelect** | Seleção única de entidades | Único | Mais simples, ideal para foreign keys |
|
|
5485
|
+
Componente versátil que suporta **seleção única** ou **múltipla** com busca inteligente, normalização de acentos e funciona perfeitamente dentro de Dialogs.
|
|
5471
5486
|
|
|
5472
|
-
|
|
5487
|
+
⚠️ **IMPORTANTE**: `MultiSelect` e `EntitySelect` estão obsoletos. Use `SelectSearch` para todos os casos de seleção.
|
|
5488
|
+
|
|
5489
|
+
---
|
|
5490
|
+
|
|
5491
|
+
### **Props Principais**
|
|
5492
|
+
|
|
5493
|
+
```typescript
|
|
5494
|
+
interface SelectSearchProps<T> {
|
|
5495
|
+
options: T[]; // Lista de opções
|
|
5496
|
+
value?: string | string[]; // Valor(es) selecionado(s)
|
|
5497
|
+
onChange: (value: string | string[] | undefined) => void; // Callback de mudança
|
|
5498
|
+
|
|
5499
|
+
// Labels e placeholder
|
|
5500
|
+
placeholder?: string; // Ex: "Selecione..."
|
|
5501
|
+
emptyMessage?: string; // Ex: "Nenhum item encontrado"
|
|
5502
|
+
|
|
5503
|
+
// Configuração de modo
|
|
5504
|
+
multiple?: boolean; // false (padrão) = seleção única, true = múltipla
|
|
5505
|
+
|
|
5506
|
+
// Funções de mapeamento (default: { value: 'id', label: 'name' })
|
|
5507
|
+
getOptionValue?: (option: T) => string;
|
|
5508
|
+
getOptionLabel?: (option: T) => string;
|
|
5509
|
+
|
|
5510
|
+
// Ordenação
|
|
5511
|
+
sortOptions?: boolean; // true (padrão) = ordena por label
|
|
5512
|
+
|
|
5513
|
+
// Uso em Dialog (CRÍTICO!)
|
|
5514
|
+
popoverContainer?: HTMLElement | null; // Necessário para funcionar dentro de Dialog
|
|
5515
|
+
|
|
5516
|
+
// Estados
|
|
5517
|
+
isLoading?: boolean; // Mostra skeleton
|
|
5518
|
+
error?: string; // Mostra mensagem de erro
|
|
5519
|
+
disabled?: boolean; // Desabilita o componente
|
|
5520
|
+
}
|
|
5521
|
+
```
|
|
5473
5522
|
|
|
5474
|
-
|
|
5475
|
-
- ✅ Precisa alternar entre modo único e múltiplo dinamicamente
|
|
5476
|
-
- ✅ Formulários onde o modo pode mudar com base em lógica
|
|
5477
|
-
- ✅ Situações onde você quer um único componente para ambos os casos
|
|
5523
|
+
---
|
|
5478
5524
|
|
|
5479
|
-
**Exemplo
|
|
5525
|
+
### **Exemplo 1: Seleção Única**
|
|
5480
5526
|
|
|
5481
5527
|
```typescript
|
|
5482
5528
|
import { SelectSearch } from 'forlogic-core';
|
|
5483
5529
|
|
|
5484
|
-
|
|
5485
|
-
const [
|
|
5530
|
+
function MyForm() {
|
|
5531
|
+
const [language, setLanguage] = useState<string>();
|
|
5486
5532
|
|
|
5487
|
-
|
|
5488
|
-
|
|
5489
|
-
|
|
5490
|
-
|
|
5491
|
-
|
|
5492
|
-
|
|
5493
|
-
|
|
5533
|
+
return (
|
|
5534
|
+
<SelectSearch
|
|
5535
|
+
options={[
|
|
5536
|
+
{ id: 'pt', name: 'Português' },
|
|
5537
|
+
{ id: 'en', name: 'English' },
|
|
5538
|
+
{ id: 'es', name: 'Español' }
|
|
5539
|
+
]}
|
|
5540
|
+
value={language}
|
|
5541
|
+
onChange={setLanguage}
|
|
5542
|
+
placeholder="Selecione um idioma"
|
|
5543
|
+
getOptionValue={(opt) => opt.id}
|
|
5544
|
+
getOptionLabel={(opt) => opt.name}
|
|
5545
|
+
/>
|
|
5546
|
+
);
|
|
5547
|
+
}
|
|
5548
|
+
```
|
|
5494
5549
|
|
|
5495
|
-
|
|
5496
|
-
const [selectedTags, setSelectedTags] = useState<string[]>([]);
|
|
5550
|
+
---
|
|
5497
5551
|
|
|
5498
|
-
|
|
5499
|
-
|
|
5500
|
-
|
|
5501
|
-
|
|
5502
|
-
|
|
5503
|
-
|
|
5504
|
-
|
|
5505
|
-
|
|
5506
|
-
|
|
5552
|
+
### **Exemplo 2: Seleção Múltipla**
|
|
5553
|
+
|
|
5554
|
+
```typescript
|
|
5555
|
+
import { SelectSearch } from 'forlogic-core';
|
|
5556
|
+
|
|
5557
|
+
function MyForm() {
|
|
5558
|
+
const [tags, setTags] = useState<string[]>([]);
|
|
5559
|
+
|
|
5560
|
+
return (
|
|
5561
|
+
<SelectSearch
|
|
5562
|
+
multiple
|
|
5563
|
+
options={[
|
|
5564
|
+
{ id: '1', name: 'React' },
|
|
5565
|
+
{ id: '2', name: 'TypeScript' },
|
|
5566
|
+
{ id: '3', name: 'Tailwind' }
|
|
5567
|
+
]}
|
|
5568
|
+
value={tags}
|
|
5569
|
+
onChange={(value) => setTags(value as string[])}
|
|
5570
|
+
placeholder="Selecione tecnologias"
|
|
5571
|
+
getOptionValue={(opt) => opt.id}
|
|
5572
|
+
getOptionLabel={(opt) => opt.name}
|
|
5573
|
+
/>
|
|
5574
|
+
);
|
|
5575
|
+
}
|
|
5507
5576
|
```
|
|
5508
5577
|
|
|
5509
|
-
|
|
5578
|
+
---
|
|
5579
|
+
|
|
5580
|
+
### **Exemplo 3: Dentro de Dialog** ⚠️ **CRÍTICO**
|
|
5581
|
+
|
|
5582
|
+
Para funcionar corretamente dentro de um Dialog, você **DEVE** passar o `popoverContainer`:
|
|
5510
5583
|
|
|
5511
5584
|
```typescript
|
|
5512
|
-
import { Dialog, DialogContent
|
|
5585
|
+
import { SelectSearch, Dialog, DialogContent } from 'forlogic-core';
|
|
5513
5586
|
|
|
5514
|
-
function
|
|
5515
|
-
const [
|
|
5516
|
-
const [
|
|
5587
|
+
function MyDialog() {
|
|
5588
|
+
const [open, setOpen] = useState(false);
|
|
5589
|
+
const [category, setCategory] = useState<string>();
|
|
5590
|
+
const dialogContentRef = useRef<HTMLDivElement>(null);
|
|
5517
5591
|
|
|
5518
5592
|
return (
|
|
5519
|
-
<Dialog>
|
|
5520
|
-
<
|
|
5521
|
-
|
|
5522
|
-
|
|
5523
|
-
|
|
5524
|
-
<
|
|
5525
|
-
|
|
5526
|
-
</DialogHeader>
|
|
5527
|
-
<div className="mt-4 max-h-[60vh] overflow-auto pr-1">
|
|
5593
|
+
<Dialog open={open} onOpenChange={setOpen}>
|
|
5594
|
+
<DialogContent
|
|
5595
|
+
ref={dialogContentRef}
|
|
5596
|
+
className="overflow-visible" // ⚠️ IMPORTANTE: overflow-visible no DialogContent
|
|
5597
|
+
>
|
|
5598
|
+
<div className="space-y-4 overflow-auto max-h-[60vh]">
|
|
5599
|
+
{/* ⚠️ CRÍTICO: Passar popoverContainer */}
|
|
5528
5600
|
<SelectSearch
|
|
5529
|
-
options={
|
|
5530
|
-
value={
|
|
5531
|
-
onChange={
|
|
5532
|
-
placeholder="Selecione
|
|
5533
|
-
popoverContainer={dialogContentRef}
|
|
5601
|
+
options={categories}
|
|
5602
|
+
value={category}
|
|
5603
|
+
onChange={setCategory}
|
|
5604
|
+
placeholder="Selecione categoria"
|
|
5605
|
+
popoverContainer={dialogContentRef.current}
|
|
5534
5606
|
/>
|
|
5535
5607
|
</div>
|
|
5536
5608
|
</DialogContent>
|
|
@@ -5539,156 +5611,156 @@ function MyComponent() {
|
|
|
5539
5611
|
}
|
|
5540
5612
|
```
|
|
5541
5613
|
|
|
5542
|
-
|
|
5614
|
+
---
|
|
5543
5615
|
|
|
5544
|
-
|
|
5545
|
-
interface SelectSearchProps<T> {
|
|
5546
|
-
multiple?: boolean; // Modo: false = único, true = múltiplo
|
|
5547
|
-
options: T[]; // Array de itens
|
|
5548
|
-
value?: string | string[]; // Valor(es) selecionado(s)
|
|
5549
|
-
onChange?: (value: string | string[]) => void;
|
|
5550
|
-
getOptionValue?: (option: T) => string;
|
|
5551
|
-
getOptionLabel?: (option: T) => string;
|
|
5552
|
-
placeholder?: string;
|
|
5553
|
-
label?: string;
|
|
5554
|
-
disabled?: boolean;
|
|
5555
|
-
required?: boolean;
|
|
5556
|
-
isLoading?: boolean;
|
|
5557
|
-
error?: string | boolean;
|
|
5558
|
-
sortOptions?: boolean; // Default: true
|
|
5559
|
-
maxDisplayedBadges?: number; // Limite de badges (modo múltiplo)
|
|
5560
|
-
popoverContainer?: HTMLElement | null; // ✅ Essencial para Dialog
|
|
5561
|
-
}
|
|
5562
|
-
```
|
|
5616
|
+
### **⚠️ IMPORTANTE: Uso em Dialog**
|
|
5563
5617
|
|
|
5564
|
-
|
|
5618
|
+
**Configuração Correta:**
|
|
5619
|
+
```tsx
|
|
5620
|
+
// 1. Ref no DialogContent
|
|
5621
|
+
const dialogContentRef = useRef<HTMLDivElement>(null);
|
|
5565
5622
|
|
|
5566
|
-
|
|
5567
|
-
|
|
5568
|
-
|
|
5569
|
-
|
|
5623
|
+
// 2. overflow-visible no DialogContent
|
|
5624
|
+
<DialogContent ref={dialogContentRef} className="overflow-visible">
|
|
5625
|
+
|
|
5626
|
+
// 3. Div interna com overflow-auto
|
|
5627
|
+
<div className="overflow-auto max-h-[60vh]">
|
|
5628
|
+
|
|
5629
|
+
// 4. Passar popoverContainer
|
|
5630
|
+
<SelectSearch
|
|
5631
|
+
{...props}
|
|
5632
|
+
popoverContainer={dialogContentRef.current}
|
|
5633
|
+
/>
|
|
5634
|
+
</div>
|
|
5635
|
+
</DialogContent>
|
|
5636
|
+
```
|
|
5570
5637
|
|
|
5571
|
-
|
|
5638
|
+
**❌ Configurações Incorretas Comuns:**
|
|
5572
5639
|
|
|
5573
|
-
```
|
|
5574
|
-
|
|
5640
|
+
```tsx
|
|
5641
|
+
// ❌ ERRADO: Sem popoverContainer
|
|
5642
|
+
<SelectSearch options={data} value={value} onChange={onChange} />
|
|
5575
5643
|
|
|
5576
|
-
|
|
5644
|
+
// ❌ ERRADO: overflow-hidden no DialogContent
|
|
5645
|
+
<DialogContent className="overflow-hidden">
|
|
5577
5646
|
|
|
5578
|
-
|
|
5579
|
-
|
|
5580
|
-
|
|
5581
|
-
|
|
5582
|
-
getOptionValue={(opt) => opt.id}
|
|
5583
|
-
getOptionLabel={(opt) => opt.name}
|
|
5584
|
-
placeholder="Selecione frameworks..."
|
|
5585
|
-
label="Frameworks"
|
|
5586
|
-
maxDisplayedBadges={3} // Exibe: [Badge 1] [Badge 2] [Badge 3] [+5]
|
|
5587
|
-
/>
|
|
5647
|
+
// ❌ ERRADO: Sem div interna com scroll
|
|
5648
|
+
<DialogContent className="overflow-visible">
|
|
5649
|
+
<SelectSearch {...props} />
|
|
5650
|
+
</DialogContent>
|
|
5588
5651
|
```
|
|
5589
5652
|
|
|
5590
|
-
|
|
5591
|
-
|
|
5592
|
-
```typescript
|
|
5593
|
-
// ⚠️ Use SelectSearch ou EntitySelect para modo único
|
|
5594
|
-
<MultiSelect
|
|
5595
|
-
multiple={false} // Funciona, mas SelectSearch é mais apropriado
|
|
5596
|
-
options={options}
|
|
5597
|
-
value={selected}
|
|
5598
|
-
onChange={setSelected}
|
|
5599
|
-
/>
|
|
5600
|
-
```
|
|
5653
|
+
---
|
|
5601
5654
|
|
|
5602
|
-
### **
|
|
5655
|
+
### **Características Avançadas**
|
|
5603
5656
|
|
|
5604
|
-
**
|
|
5605
|
-
-
|
|
5606
|
-
-
|
|
5607
|
-
-
|
|
5657
|
+
#### **Busca Inteligente**
|
|
5658
|
+
- **Case-insensitive**: `react` encontra `React`
|
|
5659
|
+
- **Accent-insensitive**: `frances` encontra `Français`
|
|
5660
|
+
- **Busca em qualquer parte**: `script` encontra `TypeScript`
|
|
5608
5661
|
|
|
5609
|
-
**
|
|
5662
|
+
#### **Badges Interativos (modo múltiplo)**
|
|
5663
|
+
- Exibe badges com `×` para remover itens
|
|
5664
|
+
- Limite de 3 badges exibidos, com `+N` para excedentes
|
|
5665
|
+
- Click em `+N` expande para mostrar todos
|
|
5610
5666
|
|
|
5667
|
+
#### **Estados**
|
|
5611
5668
|
```typescript
|
|
5612
|
-
|
|
5669
|
+
// Loading
|
|
5670
|
+
<SelectSearch isLoading options={[]} />
|
|
5613
5671
|
|
|
5614
|
-
|
|
5672
|
+
// Erro
|
|
5673
|
+
<SelectSearch error="Falha ao carregar opções" options={[]} />
|
|
5615
5674
|
|
|
5616
|
-
|
|
5617
|
-
|
|
5618
|
-
value={selectedFramework}
|
|
5619
|
-
onChange={setSelectedFramework}
|
|
5620
|
-
getItemValue={(opt) => opt.id}
|
|
5621
|
-
getItemLabel={(opt) => opt.name}
|
|
5622
|
-
placeholder="Selecione um framework..."
|
|
5623
|
-
searchPlaceholder="Buscar framework..."
|
|
5624
|
-
/>
|
|
5675
|
+
// Desabilitado
|
|
5676
|
+
<SelectSearch disabled options={data} />
|
|
5625
5677
|
```
|
|
5626
5678
|
|
|
5627
|
-
|
|
5628
|
-
|
|
5629
|
-
| Prop | SelectSearch | MultiSelect | EntitySelect |
|
|
5630
|
-
|------|--------------|-------------|--------------|
|
|
5631
|
-
| `multiple` | ✅ Configurável | ✅ Default true | ❌ Sempre único |
|
|
5632
|
-
| `maxDisplayedBadges` | ✅ Modo múltiplo | ✅ | ❌ |
|
|
5633
|
-
| `popoverContainer` | ✅ | ✅ | ❌ |
|
|
5634
|
-
| `items` vs `options` | `options` | `options` | `items` |
|
|
5635
|
-
| Complexidade | Média | Média | Baixa |
|
|
5679
|
+
---
|
|
5636
5680
|
|
|
5637
|
-
### **
|
|
5681
|
+
### **Uso em BaseForm**
|
|
5638
5682
|
|
|
5639
|
-
|
|
5640
|
-
|
|
5641
|
-
- Estiver dentro de Dialog e precisar de scroll
|
|
5642
|
-
- Quiser um componente versátil para diversos casos
|
|
5683
|
+
```typescript
|
|
5684
|
+
import { BaseForm, SelectSearch } from 'forlogic-core';
|
|
5643
5685
|
|
|
5644
|
-
|
|
5645
|
-
|
|
5646
|
-
|
|
5647
|
-
|
|
5686
|
+
const fields = [
|
|
5687
|
+
{
|
|
5688
|
+
name: 'language',
|
|
5689
|
+
label: 'Idioma',
|
|
5690
|
+
type: 'custom' as const,
|
|
5691
|
+
component: ({ field }: any) => (
|
|
5692
|
+
<SelectSearch
|
|
5693
|
+
options={languages}
|
|
5694
|
+
value={field.value}
|
|
5695
|
+
onChange={field.onChange}
|
|
5696
|
+
placeholder="Selecione um idioma"
|
|
5697
|
+
/>
|
|
5698
|
+
),
|
|
5699
|
+
validation: z.string().min(1, 'Idioma obrigatório')
|
|
5700
|
+
},
|
|
5701
|
+
{
|
|
5702
|
+
name: 'tags',
|
|
5703
|
+
label: 'Tags',
|
|
5704
|
+
type: 'custom' as const,
|
|
5705
|
+
component: ({ field }: any) => (
|
|
5706
|
+
<SelectSearch
|
|
5707
|
+
multiple
|
|
5708
|
+
options={allTags}
|
|
5709
|
+
value={field.value}
|
|
5710
|
+
onChange={field.onChange}
|
|
5711
|
+
placeholder="Selecione tags"
|
|
5712
|
+
/>
|
|
5713
|
+
),
|
|
5714
|
+
validation: z.array(z.string()).min(1, 'Selecione ao menos uma tag')
|
|
5715
|
+
}
|
|
5716
|
+
];
|
|
5717
|
+
```
|
|
5648
5718
|
|
|
5649
|
-
|
|
5650
|
-
- Seleção única simples for suficiente
|
|
5651
|
-
- Não precisar de Dialog ou scroll especial
|
|
5652
|
-
- Quiser o componente mais leve e focado
|
|
5719
|
+
---
|
|
5653
5720
|
|
|
5654
|
-
###
|
|
5721
|
+
### **Migração de MultiSelect e EntitySelect (DEPRECATED)**
|
|
5655
5722
|
|
|
5656
|
-
|
|
5723
|
+
⚠️ **Estes componentes estão obsoletos. Use `SelectSearch` para todos os casos de seleção.**
|
|
5657
5724
|
|
|
5658
|
-
|
|
5725
|
+
**Migração de MultiSelect:**
|
|
5659
5726
|
|
|
5660
5727
|
```typescript
|
|
5661
|
-
//
|
|
5662
|
-
|
|
5728
|
+
// ❌ ANTIGO: MultiSelect
|
|
5729
|
+
<MultiSelect
|
|
5730
|
+
options={data}
|
|
5731
|
+
value={selected}
|
|
5732
|
+
onChange={setSelected}
|
|
5733
|
+
/>
|
|
5663
5734
|
|
|
5664
|
-
//
|
|
5665
|
-
<
|
|
5666
|
-
|
|
5667
|
-
{
|
|
5668
|
-
|
|
5669
|
-
|
|
5670
|
-
|
|
5671
|
-
<SelectSearch
|
|
5672
|
-
options={options}
|
|
5673
|
-
value={selected}
|
|
5674
|
-
onChange={setSelected}
|
|
5675
|
-
popoverContainer={dialogContentRef} {/* ✅ CRÍTICO */}
|
|
5676
|
-
/>
|
|
5677
|
-
</div>
|
|
5678
|
-
</DialogContent>
|
|
5735
|
+
// ✅ NOVO: SelectSearch
|
|
5736
|
+
<SelectSearch
|
|
5737
|
+
multiple
|
|
5738
|
+
options={data}
|
|
5739
|
+
value={selected}
|
|
5740
|
+
onChange={setSelected}
|
|
5741
|
+
/>
|
|
5679
5742
|
```
|
|
5680
5743
|
|
|
5681
|
-
|
|
5744
|
+
**Migração de EntitySelect:**
|
|
5682
5745
|
|
|
5683
5746
|
```typescript
|
|
5684
|
-
// ❌
|
|
5685
|
-
<
|
|
5686
|
-
|
|
5687
|
-
|
|
5688
|
-
|
|
5747
|
+
// ❌ ANTIGO: EntitySelect
|
|
5748
|
+
<EntitySelect
|
|
5749
|
+
items={data}
|
|
5750
|
+
value={selected}
|
|
5751
|
+
onChange={setSelected}
|
|
5752
|
+
getItemValue={(item) => item.id}
|
|
5753
|
+
getItemLabel={(item) => item.name}
|
|
5754
|
+
/>
|
|
5689
5755
|
|
|
5690
|
-
//
|
|
5691
|
-
<SelectSearch
|
|
5756
|
+
// ✅ NOVO: SelectSearch
|
|
5757
|
+
<SelectSearch
|
|
5758
|
+
options={data}
|
|
5759
|
+
value={selected}
|
|
5760
|
+
onChange={setSelected}
|
|
5761
|
+
getOptionValue={(item) => item.id}
|
|
5762
|
+
getOptionLabel={(item) => item.name}
|
|
5763
|
+
/>
|
|
5692
5764
|
```
|
|
5693
5765
|
|
|
5694
5766
|
---
|