rl-core-front 0.11.0 → 0.11.2

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rl-core-front",
3
- "version": "0.11.0",
3
+ "version": "0.11.2",
4
4
  "description": "Telas e componentes Next.js do core: login com 2FA, usu\u00e1rios, RBAC, auditoria, logs e listagens com filtro din\u00e2mico",
5
5
  "author": "Rodrigo Liberti",
6
6
  "license": "MIT",
@@ -28,6 +28,13 @@ export interface ComboboxProps {
28
28
  value: string[];
29
29
  onChange: (ids: string[]) => void;
30
30
  multiple?: boolean;
31
+ /**
32
+ * Mostra o X que devolve o campo ao vazio.
33
+ *
34
+ * Só faz sentido onde o vazio é resposta válida: num campo obrigatório o X
35
+ * seria um atalho para o erro de validação. Por isso não vem ligado.
36
+ */
37
+ clearable?: boolean;
31
38
  placeholder?: string;
32
39
  searchPlaceholder?: string;
33
40
  emptyMessage?: string;
@@ -53,6 +60,7 @@ export function Combobox({
53
60
  value,
54
61
  onChange,
55
62
  multiple = false,
63
+ clearable = false,
56
64
  placeholder,
57
65
  searchPlaceholder,
58
66
  emptyMessage,
@@ -141,20 +149,51 @@ export function Combobox({
141
149
  ? selected.map((option) => (
142
150
  <Badge key={option.id} variant="secondary" className="gap-1">
143
151
  {option.name}
144
- <X
145
- className="h-3 w-3 cursor-pointer"
146
- onClick={(event) => {
147
- // Sem isto, tirar um selo abriria o menu junto.
152
+ <span
153
+ aria-label={`${t("common.remove")} ${option.name}`}
154
+ className="cursor-pointer"
155
+ /*
156
+ * Tirar um item é no `pointerdown`, não no `click`.
157
+ *
158
+ * O gatilho do Radix abre no `pointerdown`, e o menu
159
+ * aberto tira o `pointer-events` de tudo que está fora do
160
+ * painel — inclusive deste X, que mora no gatilho. O
161
+ * `click` chegava tarde: quando ele viria, o alvo já não
162
+ * recebia evento, e o item ficava marcado para sempre.
163
+ *
164
+ * `stopPropagation` no lugar do `onClick` de antes: aqui
165
+ * ele chega a tempo de o gatilho não ver o evento, e o
166
+ * menu não abre junto.
167
+ */
168
+ onPointerDown={(event) => {
169
+ event.preventDefault();
148
170
  event.stopPropagation();
149
171
  onChange(value.filter((id) => id !== option.id));
150
172
  }}
151
- />
173
+ >
174
+ <X className="h-3 w-3" />
175
+ </span>
152
176
  </Badge>
153
177
  ))
154
178
  : selected.map((option) => (
155
179
  <span key={option.id}>{option.name}</span>
156
180
  ))}
157
181
  </span>
182
+ {clearable && selected.length > 0 && !disabled && (
183
+ <span
184
+ aria-label={t("common.clear")}
185
+ className="shrink-0 opacity-60 hover:opacity-100"
186
+ // Mesmo motivo do X do chip: no `click` o gatilho já teria aberto
187
+ // o menu e tirado o ponteiro de quem está fora do painel.
188
+ onPointerDown={(event) => {
189
+ event.preventDefault();
190
+ event.stopPropagation();
191
+ onChange([]);
192
+ }}
193
+ >
194
+ <X className="h-4 w-4" />
195
+ </span>
196
+ )}
158
197
  <ChevronDown className="h-4 w-4 shrink-0 opacity-60" />
159
198
  </Button>
160
199
  </DropdownMenuTrigger>
@@ -57,8 +57,17 @@ const TableHead = React.forwardRef<
57
57
  >(({ className, ...props }, ref) => (
58
58
  <th
59
59
  ref={ref}
60
+ /*
61
+ * Sem `uppercase`: a caixa alta só pegava em metade dos cabeçalhos.
62
+ *
63
+ * A coluna que ordena desenha o rótulo dentro de um `<button>`, e o estilo
64
+ * do próprio navegador dá `text-transform: none` a botão — o Preflight do
65
+ * Tailwind herda fonte, peso e cor, mas não a caixa. O resultado era uma
66
+ * tabela com "Personagem" ao lado de "SELOS", conforme a coluna tivesse
67
+ * seta ou não. Um desenho só, e é o do texto como foi escrito.
68
+ */
60
69
  className={cn(
61
- "h-11 px-4 text-left align-middle text-xs font-semibold uppercase tracking-wide text-muted-foreground [&:has([role=checkbox])]:pr-0",
70
+ "h-11 px-4 text-left align-middle text-xs font-semibold text-muted-foreground [&:has([role=checkbox])]:pr-0",
62
71
  className,
63
72
  )}
64
73
  {...props}
@@ -200,6 +200,8 @@ export const en: Messages = {
200
200
  select: "Select…",
201
201
  search: "Search…",
202
202
  noResults: "Nothing found",
203
+ remove: "Remove",
204
+ clear: "Clear",
203
205
  no: "No",
204
206
  actions: "Actions",
205
207
  loading: "Loading...",
@@ -202,6 +202,8 @@ export const pt = {
202
202
  select: "Selecionar…",
203
203
  search: "Pesquisar…",
204
204
  noResults: "Nada encontrado",
205
+ remove: "Remover",
206
+ clear: "Limpar",
205
207
  no: "Não",
206
208
  actions: "Ações",
207
209
  loading: "Carregando...",