rl-core-front 0.18.8 → 0.18.10

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.18.8",
3
+ "version": "0.18.10",
4
4
  "description": "Telas e componentes Next.js do core: login com 2FA, usuários, RBAC, auditoria, logs e listagens com filtro dinâmico",
5
5
  "author": "Rodrigo Liberti",
6
6
  "license": "MIT",
@@ -50,6 +50,18 @@ export interface ComboboxProps {
50
50
  onCreate?: (text: string) => void;
51
51
  /** Texto da linha de criação. Ausente, `Criar "{text}"`. */
52
52
  createLabel?: (text: string) => string;
53
+ /**
54
+ * No modo múltiplo, fecha sozinho depois de tantos milissegundos sem
55
+ * interação — contados a partir da última marcação.
56
+ *
57
+ * O painel múltiplo fica aberto de propósito para marcar vários de uma vez,
58
+ * mas quem marcou o que queria e parou de mexer está esperando ele sumir.
59
+ * Digitar, andar com as setas, mover o mouse sobre a lista ou marcar outro
60
+ * item reinicia a contagem; abrir e só olhar não a inicia. Tirar o mouse
61
+ * do painel depois de marcar fecha na hora — quem saiu já terminou.
62
+ * Ausente, o painel só fecha no clique fora ou no Esc.
63
+ */
64
+ idleCloseMs?: number;
53
65
  }
54
66
 
55
67
  /** Id da linha de criação na lista apontável — nenhuma opção real o usa. */
@@ -93,9 +105,37 @@ export function Combobox({
93
105
  creatable = false,
94
106
  onCreate,
95
107
  createLabel,
108
+ idleCloseMs,
96
109
  }: ComboboxProps): JSX.Element {
97
110
  const { t } = useI18n();
98
111
  const [open, setOpen] = useState(false);
112
+ /* O cronômetro do fechamento por inatividade; só corre depois de uma marcação. */
113
+ const ocioso = useRef<ReturnType<typeof setTimeout> | null>(null);
114
+
115
+ const pararContagem = (): void => {
116
+ if (ocioso.current) {
117
+ clearTimeout(ocioso.current);
118
+ ocioso.current = null;
119
+ }
120
+ };
121
+
122
+ /* Reinicia a contagem — se ela já estava correndo. Quem a inicia é o `alternar`. */
123
+ const registrarInteracao = (): void => {
124
+ if (!ocioso.current) {
125
+ return;
126
+ }
127
+
128
+ pararContagem();
129
+ ocioso.current = setTimeout(() => setOpen(false), idleCloseMs);
130
+ };
131
+
132
+ useEffect(() => {
133
+ if (!open) {
134
+ pararContagem();
135
+ }
136
+
137
+ return pararContagem;
138
+ }, [open]);
99
139
  const [search, setSearch] = useState("");
100
140
  /**
101
141
  * O item que o teclado aponta. Nulo é "o primeiro que a busca deixou".
@@ -172,6 +212,11 @@ export function Combobox({
172
212
  ? value.filter((atual) => atual !== id)
173
213
  : [...value, id],
174
214
  );
215
+
216
+ if (idleCloseMs) {
217
+ pararContagem();
218
+ ocioso.current = setTimeout(() => setOpen(false), idleCloseMs);
219
+ }
175
220
  };
176
221
 
177
222
  useEffect(() => {
@@ -298,6 +343,15 @@ export function Combobox({
298
343
  * compõe os handlers com o de fora primeiro, e desiste do seu quando o
299
344
  * evento já foi tratado: o `preventDefault` daqui é o que o desarma.
300
345
  */
346
+ onPointerMove={registrarInteracao}
347
+ // Saiu com o mouse depois de marcar: não há por que esperar a contagem.
348
+ onPointerLeave={() => {
349
+ if (ocioso.current) {
350
+ pararContagem();
351
+ setOpen(false);
352
+ }
353
+ }}
354
+ onKeyDownCapture={registrarInteracao}
301
355
  onKeyDown={(event) => {
302
356
  // Tecla nascida na busca já foi tratada lá.
303
357
  if (