rl-core-front 0.14.2 → 0.14.4

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.14.2",
3
+ "version": "0.14.4",
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",
@@ -4,22 +4,79 @@ import * as React from "react";
4
4
 
5
5
  import { cn } from "#core/lib/utils";
6
6
 
7
- const Input = React.forwardRef<
8
- HTMLInputElement,
9
- React.InputHTMLAttributes<HTMLInputElement>
10
- >(({ className, type, ...props }, ref) => {
11
- return (
12
- <input
13
- type={type}
14
- className={cn(
15
- "flex h-10 w-full rounded-md border border-input bg-transparent px-3 py-2 text-sm shadow-sm transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:ring-offset-background disabled:cursor-not-allowed disabled:opacity-50",
16
- className,
17
- )}
18
- ref={ref}
19
- {...props}
20
- />
21
- );
22
- });
7
+ /**
8
+ * O `prefix` sai do tipo base de propósito: o React o declara como `string`
9
+ * porque existe um `prefix` de RDFa em todo elemento HTML — atributo que
10
+ * ninguém escreve num `<input>`, e cujo tipo impediria passar um ícone aqui.
11
+ */
12
+ export interface InputProps
13
+ extends Omit<React.InputHTMLAttributes<HTMLInputElement>, "prefix"> {
14
+ /**
15
+ * Marca fixa colada à esquerda do campo `R$`, `@`, `https://`.
16
+ *
17
+ * Dentro da borda, e não num rótulo acima: a unidade é do valor, e lida
18
+ * longe dele ela vira decoração que some quando o formulário fica cheio. É
19
+ * também o que evita quem digita repetir a marca no próprio texto.
20
+ */
21
+ prefix?: React.ReactNode;
22
+ /** Mesma ideia à direita — `%`, `kg`, `/mês`. */
23
+ suffix?: React.ReactNode;
24
+ }
25
+
26
+ /** A marca não é campo: não recebe clique nem foco, e o cursor vai para o input. */
27
+ const Affix = ({
28
+ children,
29
+ className,
30
+ }: {
31
+ children: React.ReactNode;
32
+ className?: string;
33
+ }): React.JSX.Element => (
34
+ <span
35
+ aria-hidden
36
+ className={cn(
37
+ "pointer-events-none absolute inset-y-0 flex items-center text-sm text-muted-foreground",
38
+ className,
39
+ )}
40
+ >
41
+ {children}
42
+ </span>
43
+ );
44
+
45
+ const Input = React.forwardRef<HTMLInputElement, InputProps>(
46
+ ({ className, type, prefix, suffix, ...props }, ref) => {
47
+ const campo = (
48
+ <input
49
+ type={type}
50
+ className={cn(
51
+ "flex h-10 w-full rounded-md border border-input bg-transparent px-3 py-2 text-sm shadow-sm transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:ring-offset-background disabled:cursor-not-allowed disabled:opacity-50",
52
+ // Abre espaço para a marca em vez de deixar o texto passar por baixo
53
+ // dela. Largura fixa e não `w-auto`: a marca é curta por definição, e
54
+ // medir a real exigiria ler o DOM a cada render.
55
+ prefix && "pl-10",
56
+ suffix && "pr-10",
57
+ className,
58
+ )}
59
+ ref={ref}
60
+ {...props}
61
+ />
62
+ );
63
+
64
+ // Sem marca o `<input>` volta a ser o elemento raiz: envolver todo campo
65
+ // do produto num `div` mudaria a largura de quem já usa `Input` dentro de
66
+ // um flex, e a maioria não tem marca nenhuma.
67
+ if (!prefix && !suffix) {
68
+ return campo;
69
+ }
70
+
71
+ return (
72
+ <div className="relative w-full">
73
+ {prefix && <Affix className="left-3">{prefix}</Affix>}
74
+ {campo}
75
+ {suffix && <Affix className="right-3">{suffix}</Affix>}
76
+ </div>
77
+ );
78
+ },
79
+ );
23
80
  Input.displayName = "Input";
24
81
 
25
82
  export { Input };
@@ -49,6 +49,19 @@ export interface UseConfirmResult {
49
49
  options: ConfirmedActionOptions,
50
50
  action: () => Promise<unknown>,
51
51
  ) => Promise<boolean>;
52
+ /**
53
+ * O caso mais comum, com os textos prontos: `Excluir “Cartão Inter”?` mais o
54
+ * aviso de que não há volta, o botão vermelho e o rótulo "Excluir".
55
+ *
56
+ * Existe para a tela não repetir cinco campos a cada lixeira — era o que
57
+ * fazia cada projeto embrulhar o `confirm` num hook próprio e acabar com
58
+ * duas perguntas de excluir diferentes no mesmo produto.
59
+ *
60
+ * O texto **não** menciona recuperação, mesmo onde a exclusão é lógica:
61
+ * lixeira por baixo é rede de segurança do dado, não promessa ao usuário, e
62
+ * prometer desfazer convida ao clique sem cuidado.
63
+ */
64
+ confirmDelete: (name: string, note?: string) => Promise<boolean>;
52
65
  /** Enquanto a ação confirmada roda — para travar a tabela que ela muda. */
53
66
  acting: boolean;
54
67
  /** Renderize no final da tela — é o modal em si. */
@@ -86,6 +99,18 @@ export function useConfirm(): UseConfirmResult {
86
99
  [pending],
87
100
  );
88
101
 
102
+ const confirmDelete = useCallback(
103
+ (name: string, note?: string): Promise<boolean> =>
104
+ confirm({
105
+ title: t("common.deleteTitle", { name }),
106
+ description: t("common.deleteWarning"),
107
+ note,
108
+ confirmLabel: t("common.delete"),
109
+ destructive: true,
110
+ }),
111
+ [confirm, t],
112
+ );
113
+
89
114
  const confirmAndRun = useCallback(
90
115
  async (
91
116
  options: ConfirmedActionOptions,
@@ -127,5 +152,5 @@ export function useConfirm(): UseConfirmResult {
127
152
  />
128
153
  );
129
154
 
130
- return { confirm, confirmAndRun, acting, confirmDialog };
155
+ return { confirm, confirmDelete, confirmAndRun, acting, confirmDialog };
131
156
  }
@@ -195,6 +195,9 @@ export const en: Messages = {
195
195
  cancel: "Cancel",
196
196
  edit: "Edit",
197
197
  delete: "Delete",
198
+ deleteTitle: "Delete “{name}”?",
199
+ deleteWarning:
200
+ "This action cannot be undone. The record leaves the lists and stops appearing in the system.",
198
201
  create: "Create",
199
202
  confirm: "Confirm",
200
203
  send: "Send",
@@ -197,6 +197,9 @@ export const pt = {
197
197
  cancel: "Cancelar",
198
198
  edit: "Editar",
199
199
  delete: "Excluir",
200
+ deleteTitle: "Excluir “{name}”?",
201
+ deleteWarning:
202
+ "Esta ação não pode ser desfeita. O registro sai das listas e deixa de aparecer no sistema.",
200
203
  create: "Criar",
201
204
  confirm: "Confirmar",
202
205
  send: "Enviar",