@assembleo/ui 0.1.0 → 0.2.0
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/dist/index.d.ts +60 -8
- package/dist/index.js +130 -27
- package/dist/theme.css +6 -0
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as react from 'react';
|
|
2
|
-
import { ComponentProps, HTMLAttributes, ReactNode, ButtonHTMLAttributes, ComponentPropsWithoutRef,
|
|
2
|
+
import { ComponentProps, HTMLAttributes, ReactNode, ButtonHTMLAttributes, ComponentPropsWithoutRef, TextareaHTMLAttributes, MouseEventHandler, InputHTMLAttributes } from 'react';
|
|
3
3
|
import * as class_variance_authority_types from 'class-variance-authority/types';
|
|
4
4
|
import { VariantProps, cx } from 'class-variance-authority';
|
|
5
5
|
import { Avatar as Avatar$1, Checkbox as Checkbox$1, Dialog as Dialog$1, Popover as Popover$1, RadioGroup as RadioGroup$1, Select as Select$1, Separator as Separator$1, Switch as Switch$1, Tabs as Tabs$1 } from 'radix-ui';
|
|
@@ -110,6 +110,44 @@ interface CheckboxProps extends Omit<ComponentProps<typeof Checkbox$1.Root>, 'cl
|
|
|
110
110
|
}
|
|
111
111
|
declare function Checkbox({ label, className, id, ...props }: CheckboxProps): react.JSX.Element;
|
|
112
112
|
|
|
113
|
+
type InputProps = ComponentProps<'input'>;
|
|
114
|
+
/**
|
|
115
|
+
* Os campos com máscara (CPF, WhatsApp, código) controlam `value` e `onChange` e
|
|
116
|
+
* fixam `type`, `inputMode` e `autoComplete`; o resto é do `Input`, `ref` incluído.
|
|
117
|
+
*/
|
|
118
|
+
type MaskedInputProps = Omit<InputProps, 'value' | 'onChange' | 'type' | 'inputMode' | 'autoComplete'> & {
|
|
119
|
+
value: string;
|
|
120
|
+
/** Recebe a string já mascarada. */
|
|
121
|
+
onChange: (value: string) => void;
|
|
122
|
+
};
|
|
123
|
+
declare function Input({ className, id, type, ...props }: InputProps): react.JSX.Element;
|
|
124
|
+
|
|
125
|
+
type CodeInputProps = Omit<MaskedInputProps, 'maxLength'> & {
|
|
126
|
+
/** Chamado quando o último dígito entra — por digitação ou por colagem. */
|
|
127
|
+
onComplete?: (code: string) => void;
|
|
128
|
+
/** Quantidade de dígitos do código. */
|
|
129
|
+
length?: number;
|
|
130
|
+
};
|
|
131
|
+
/**
|
|
132
|
+
* Os dígitos do código, submetidos sozinhos.
|
|
133
|
+
*
|
|
134
|
+
* Um campo só, e não uma caixinha por dígito: colar é o caminho real. O botão do
|
|
135
|
+
* template de autenticação da Meta copia o código para a área de transferência, e
|
|
136
|
+
* quem usa o app instalado como PWA volta do WhatsApp e cola. Caixinhas quebram a
|
|
137
|
+
* colagem em navegador e atrapalham leitor de tela para não ganhar nada.
|
|
138
|
+
*/
|
|
139
|
+
declare function CodeInput({ value, onChange, onComplete, length, className, ...props }: CodeInputProps): react.JSX.Element;
|
|
140
|
+
|
|
141
|
+
/** `000.000.000-00` enquanto se digita; para nos onze dígitos. */
|
|
142
|
+
declare function formatCpf(input: string): string;
|
|
143
|
+
/**
|
|
144
|
+
* Controle de CPF: só máscara. Não valida o dígito verificador, não se marca
|
|
145
|
+
* inválido e não anuncia nada — um CPF incompleto ainda não é um CPF errado.
|
|
146
|
+
* Quem usa valida, no envio ou no `onBlur` (repassado ao `<input>`, assim como o
|
|
147
|
+
* `ref`, para focar o campo), e entrega o erro ao `Field`, que o anuncia.
|
|
148
|
+
*/
|
|
149
|
+
declare function CpfInput({ value, onChange, ...props }: MaskedInputProps): react.JSX.Element;
|
|
150
|
+
|
|
113
151
|
/**
|
|
114
152
|
* O modal de confirmação: uma pergunta, uma decisão. Radix cuida do portal,
|
|
115
153
|
* do foco preso e do Escape; aqui entram só a pele e a composição.
|
|
@@ -215,11 +253,6 @@ interface IconButtonProps extends Omit<ButtonHTMLAttributes<HTMLButtonElement>,
|
|
|
215
253
|
}
|
|
216
254
|
declare function IconButton({ label, variant, size, className, type, children, ...props }: IconButtonProps): react.JSX.Element;
|
|
217
255
|
|
|
218
|
-
interface InputProps extends Omit<InputHTMLAttributes<HTMLInputElement>, 'className'> {
|
|
219
|
-
className?: string;
|
|
220
|
-
}
|
|
221
|
-
declare function Input({ className, id, type, ...props }: InputProps): react.JSX.Element;
|
|
222
|
-
|
|
223
256
|
interface TextareaProps extends Omit<TextareaHTMLAttributes<HTMLTextAreaElement>, 'className'> {
|
|
224
257
|
className?: string;
|
|
225
258
|
}
|
|
@@ -483,13 +516,21 @@ interface TabsContentProps extends Omit<ComponentPropsWithoutRef<typeof Tabs$1.C
|
|
|
483
516
|
declare function TabsContent({ className, children, ...props }: TabsContentProps): react.JSX.Element;
|
|
484
517
|
|
|
485
518
|
type ToastVariant = 'default' | 'success' | 'danger';
|
|
519
|
+
interface ToastAction {
|
|
520
|
+
label: string;
|
|
521
|
+
onClick: () => void;
|
|
522
|
+
}
|
|
486
523
|
interface ToastOptions {
|
|
487
524
|
title: string;
|
|
488
525
|
description?: string;
|
|
489
526
|
variant?: ToastVariant;
|
|
527
|
+
/** Botão do aviso. Presente, o aviso vira acionável. */
|
|
528
|
+
action?: ToastAction;
|
|
529
|
+
/** Quanto o aviso fica na tela; `null` o mantém até o usuário fechar. Ausente, 5 s. */
|
|
530
|
+
durationMs?: number | null;
|
|
490
531
|
}
|
|
491
532
|
interface ToastContextValue {
|
|
492
|
-
/** Dispara um aviso
|
|
533
|
+
/** Dispara um aviso; some sozinho em 5 segundos, salvo `durationMs`. */
|
|
493
534
|
toast: (options: ToastOptions) => void;
|
|
494
535
|
}
|
|
495
536
|
/**
|
|
@@ -533,6 +574,17 @@ interface TooltipProps {
|
|
|
533
574
|
*/
|
|
534
575
|
declare function Tooltip({ content, side, className, children }: TooltipProps): react.JSX.Element;
|
|
535
576
|
|
|
577
|
+
/**
|
|
578
|
+
* O número como o brasileiro escreve, enquanto ele digita.
|
|
579
|
+
*
|
|
580
|
+
* A máscara é do campo e a validação é de quem o usa: o momento de dizer "número
|
|
581
|
+
* inválido" é uma decisão da tela — no envio, e não a cada tecla, porque um número
|
|
582
|
+
* incompleto ainda não é um número errado.
|
|
583
|
+
*/
|
|
584
|
+
declare function formatWhatsapp(input: string): string;
|
|
585
|
+
/** Controle de WhatsApp: vive dentro de um `Field`, que dá rótulo, dica e erro. */
|
|
586
|
+
declare function WhatsappInput({ value, onChange, ...props }: MaskedInputProps): react.JSX.Element;
|
|
587
|
+
|
|
536
588
|
/**
|
|
537
589
|
* O crachá — como um associado aparece na listagem.
|
|
538
590
|
*
|
|
@@ -673,4 +725,4 @@ interface ThemeToggleProps {
|
|
|
673
725
|
*/
|
|
674
726
|
declare function ThemeToggle({ width, className }: ThemeToggleProps): react.JSX.Element;
|
|
675
727
|
|
|
676
|
-
export { Avatar, AvatarGroup, Badge, Banner, Button, Card, Checkbox, Cracha, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, DialogTrigger, EmptyState, Field, IconButton, Input, List, ListItem, Livreto, Popover, PopoverContent, PopoverTrigger, Predio, Progress, RadioGroup, RadioGroupItem, SearchField, SegmentedControl, type SegmentedControlOption, Select, SelectItem, Separator, Sheet, SheetContent, SheetDescription, SheetHeader, SheetTitle, SheetTrigger, Skeleton, Spinner, Switch, Tabs, TabsContent, TabsList, TabsTrigger, Textarea, type Theme, ThemeProvider, ThemeToggle, type ToastOptions, ToastProvider, type ToastVariant, Tooltip, VisuallyHidden, cn, initTheme, useFieldContext, useTheme, useToast };
|
|
728
|
+
export { Avatar, AvatarGroup, Badge, Banner, Button, Card, Checkbox, CodeInput, CpfInput, Cracha, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, DialogTrigger, EmptyState, Field, IconButton, Input, List, ListItem, Livreto, Popover, PopoverContent, PopoverTrigger, Predio, Progress, RadioGroup, RadioGroupItem, SearchField, SegmentedControl, type SegmentedControlOption, Select, SelectItem, Separator, Sheet, SheetContent, SheetDescription, SheetHeader, SheetTitle, SheetTrigger, Skeleton, Spinner, Switch, Tabs, TabsContent, TabsList, TabsTrigger, Textarea, type Theme, ThemeProvider, ThemeToggle, type ToastAction, type ToastOptions, ToastProvider, type ToastVariant, Tooltip, VisuallyHidden, WhatsappInput, cn, formatCpf, formatWhatsapp, initTheme, useFieldContext, useTheme, useToast };
|
package/dist/index.js
CHANGED
|
@@ -483,6 +483,90 @@ function Checkbox({ label, className, id, ...props }) {
|
|
|
483
483
|
/* @__PURE__ */ jsx("span", { className: "text-body text-text", children: label })
|
|
484
484
|
] });
|
|
485
485
|
}
|
|
486
|
+
|
|
487
|
+
// src/lib/digitos.ts
|
|
488
|
+
function digitos(input, max) {
|
|
489
|
+
const apenasDigitos = input.replace(/\D/g, "");
|
|
490
|
+
return max === void 0 ? apenasDigitos : apenasDigitos.slice(0, max);
|
|
491
|
+
}
|
|
492
|
+
var fieldControlClasses = [
|
|
493
|
+
"w-full rounded-control squircle",
|
|
494
|
+
"bg-surface-sunken text-text text-body",
|
|
495
|
+
"placeholder:text-text-muted",
|
|
496
|
+
"border border-transparent",
|
|
497
|
+
"transition-[border-color,box-shadow] duration-(--motion-quick) ease-(--ease-out-soft)",
|
|
498
|
+
"outline-none focus-visible:outline-none",
|
|
499
|
+
"focus:border-accent focus:ring-4 focus:ring-accent/15",
|
|
500
|
+
"aria-invalid:border-danger aria-invalid:ring-4 aria-invalid:ring-danger/15",
|
|
501
|
+
"disabled:pointer-events-none disabled:opacity-50"
|
|
502
|
+
].join(" ");
|
|
503
|
+
function Input({ className, id, type, ...props }) {
|
|
504
|
+
const field = useFieldContext();
|
|
505
|
+
return /* @__PURE__ */ jsx(
|
|
506
|
+
"input",
|
|
507
|
+
{
|
|
508
|
+
id: id ?? field?.controlId,
|
|
509
|
+
type: type ?? "text",
|
|
510
|
+
"aria-invalid": field?.invalid || void 0,
|
|
511
|
+
"aria-describedby": field ? [field.errorId, field.hintId].filter(Boolean).join(" ") || void 0 : void 0,
|
|
512
|
+
className: cn(fieldControlClasses, "min-h-touch px-4", className),
|
|
513
|
+
...props
|
|
514
|
+
}
|
|
515
|
+
);
|
|
516
|
+
}
|
|
517
|
+
function CodeInput({
|
|
518
|
+
value,
|
|
519
|
+
onChange,
|
|
520
|
+
onComplete,
|
|
521
|
+
length = 6,
|
|
522
|
+
className,
|
|
523
|
+
...props
|
|
524
|
+
}) {
|
|
525
|
+
return /* @__PURE__ */ jsx(
|
|
526
|
+
Input,
|
|
527
|
+
{
|
|
528
|
+
...props,
|
|
529
|
+
type: "text",
|
|
530
|
+
inputMode: "numeric",
|
|
531
|
+
autoComplete: "one-time-code",
|
|
532
|
+
value,
|
|
533
|
+
className: cn("text-center font-mono text-title-2 tracking-codigo", className),
|
|
534
|
+
onChange: (event) => {
|
|
535
|
+
const codigo = digitos(event.target.value, length);
|
|
536
|
+
onChange(codigo);
|
|
537
|
+
if (codigo.length === length && codigo !== value) {
|
|
538
|
+
onComplete?.(codigo);
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
);
|
|
543
|
+
}
|
|
544
|
+
function formatCpf(input) {
|
|
545
|
+
const numeros = digitos(input, 11);
|
|
546
|
+
if (numeros.length <= 3) {
|
|
547
|
+
return numeros;
|
|
548
|
+
}
|
|
549
|
+
if (numeros.length <= 6) {
|
|
550
|
+
return `${numeros.slice(0, 3)}.${numeros.slice(3)}`;
|
|
551
|
+
}
|
|
552
|
+
if (numeros.length <= 9) {
|
|
553
|
+
return `${numeros.slice(0, 3)}.${numeros.slice(3, 6)}.${numeros.slice(6)}`;
|
|
554
|
+
}
|
|
555
|
+
return `${numeros.slice(0, 3)}.${numeros.slice(3, 6)}.${numeros.slice(6, 9)}-${numeros.slice(9)}`;
|
|
556
|
+
}
|
|
557
|
+
function CpfInput({ value, onChange, ...props }) {
|
|
558
|
+
return /* @__PURE__ */ jsx(
|
|
559
|
+
Input,
|
|
560
|
+
{
|
|
561
|
+
...props,
|
|
562
|
+
type: "text",
|
|
563
|
+
inputMode: "numeric",
|
|
564
|
+
autoComplete: "off",
|
|
565
|
+
value,
|
|
566
|
+
onChange: (event) => onChange(formatCpf(event.target.value))
|
|
567
|
+
}
|
|
568
|
+
);
|
|
569
|
+
}
|
|
486
570
|
var Dialog = Dialog$1.Root;
|
|
487
571
|
function DialogTrigger({ asChild = true, ...props }) {
|
|
488
572
|
return /* @__PURE__ */ jsx(Dialog$1.Trigger, { asChild, ...props });
|
|
@@ -638,31 +722,6 @@ function IconButton({
|
|
|
638
722
|
)
|
|
639
723
|
);
|
|
640
724
|
}
|
|
641
|
-
var fieldControlClasses = [
|
|
642
|
-
"w-full rounded-control squircle",
|
|
643
|
-
"bg-surface-sunken text-text text-body",
|
|
644
|
-
"placeholder:text-text-muted",
|
|
645
|
-
"border border-transparent",
|
|
646
|
-
"transition-[border-color,box-shadow] duration-(--motion-quick) ease-(--ease-out-soft)",
|
|
647
|
-
"outline-none focus-visible:outline-none",
|
|
648
|
-
"focus:border-accent focus:ring-4 focus:ring-accent/15",
|
|
649
|
-
"aria-invalid:border-danger aria-invalid:ring-4 aria-invalid:ring-danger/15",
|
|
650
|
-
"disabled:pointer-events-none disabled:opacity-50"
|
|
651
|
-
].join(" ");
|
|
652
|
-
function Input({ className, id, type, ...props }) {
|
|
653
|
-
const field = useFieldContext();
|
|
654
|
-
return /* @__PURE__ */ jsx(
|
|
655
|
-
"input",
|
|
656
|
-
{
|
|
657
|
-
id: id ?? field?.controlId,
|
|
658
|
-
type: type ?? "text",
|
|
659
|
-
"aria-invalid": field?.invalid || void 0,
|
|
660
|
-
"aria-describedby": field ? [field.errorId, field.hintId].filter(Boolean).join(" ") || void 0 : void 0,
|
|
661
|
-
className: cn(fieldControlClasses, "min-h-touch px-4", className),
|
|
662
|
-
...props
|
|
663
|
-
}
|
|
664
|
-
);
|
|
665
|
-
}
|
|
666
725
|
function Textarea({ className, id, rows, ...props }) {
|
|
667
726
|
const field = useFieldContext();
|
|
668
727
|
return /* @__PURE__ */ jsx(
|
|
@@ -1215,6 +1274,7 @@ function ToastCard({ toast, onClose }) {
|
|
|
1215
1274
|
return /* @__PURE__ */ jsxs(
|
|
1216
1275
|
Toast.Root,
|
|
1217
1276
|
{
|
|
1277
|
+
duration: toast.durationMs === null ? Number.POSITIVE_INFINITY : toast.durationMs,
|
|
1218
1278
|
onOpenChange: (open) => {
|
|
1219
1279
|
if (!open) onClose();
|
|
1220
1280
|
},
|
|
@@ -1227,10 +1287,27 @@ function ToastCard({ toast, onClose }) {
|
|
|
1227
1287
|
),
|
|
1228
1288
|
children: [
|
|
1229
1289
|
visual ? /* @__PURE__ */ jsx(visual.icon, { "aria-hidden": "true", className: cn("mt-0.5 size-5 shrink-0", visual.tint) }) : null,
|
|
1230
|
-
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-0.5", children: [
|
|
1290
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-1 flex-col gap-0.5", children: [
|
|
1231
1291
|
/* @__PURE__ */ jsx(Toast.Title, { className: "text-subhead font-semibold", children: toast.title }),
|
|
1232
1292
|
toast.description ? /* @__PURE__ */ jsx(Toast.Description, { className: "text-footnote text-text-secondary", children: toast.description }) : null
|
|
1233
1293
|
] }),
|
|
1294
|
+
toast.action ? (
|
|
1295
|
+
// `altText` é o que o leitor de tela anuncia como alternativa ao aviso, e o
|
|
1296
|
+
// que o Radix exige para aceitar um aviso persistente com botão.
|
|
1297
|
+
/* @__PURE__ */ jsx(
|
|
1298
|
+
Toast.Action,
|
|
1299
|
+
{
|
|
1300
|
+
altText: toast.action.label,
|
|
1301
|
+
onClick: toast.action.onClick,
|
|
1302
|
+
className: cn(
|
|
1303
|
+
"inline-flex min-h-touch shrink-0 items-center self-center rounded-control-sm px-3",
|
|
1304
|
+
"text-subhead font-semibold text-accent",
|
|
1305
|
+
"transition-colors duration-(--motion-quick) ease-(--ease-out-soft) hover:bg-accent/10"
|
|
1306
|
+
),
|
|
1307
|
+
children: toast.action.label
|
|
1308
|
+
}
|
|
1309
|
+
)
|
|
1310
|
+
) : null,
|
|
1234
1311
|
/* @__PURE__ */ jsx(
|
|
1235
1312
|
Toast.Close,
|
|
1236
1313
|
{
|
|
@@ -1301,6 +1378,32 @@ function Tooltip({ content, side, className, children }) {
|
|
|
1301
1378
|
] }) })
|
|
1302
1379
|
);
|
|
1303
1380
|
}
|
|
1381
|
+
function formatWhatsapp(input) {
|
|
1382
|
+
const numeros = digitos(input, 11);
|
|
1383
|
+
if (numeros.length <= 2) {
|
|
1384
|
+
return numeros;
|
|
1385
|
+
}
|
|
1386
|
+
if (numeros.length <= 6) {
|
|
1387
|
+
return `(${numeros.slice(0, 2)}) ${numeros.slice(2)}`;
|
|
1388
|
+
}
|
|
1389
|
+
if (numeros.length <= 10) {
|
|
1390
|
+
return `(${numeros.slice(0, 2)}) ${numeros.slice(2, 6)}-${numeros.slice(6)}`;
|
|
1391
|
+
}
|
|
1392
|
+
return `(${numeros.slice(0, 2)}) ${numeros.slice(2, 7)}-${numeros.slice(7)}`;
|
|
1393
|
+
}
|
|
1394
|
+
function WhatsappInput({ value, onChange, ...props }) {
|
|
1395
|
+
return /* @__PURE__ */ jsx(
|
|
1396
|
+
Input,
|
|
1397
|
+
{
|
|
1398
|
+
...props,
|
|
1399
|
+
type: "tel",
|
|
1400
|
+
inputMode: "numeric",
|
|
1401
|
+
autoComplete: "tel",
|
|
1402
|
+
value,
|
|
1403
|
+
onChange: (event) => onChange(formatWhatsapp(event.target.value))
|
|
1404
|
+
}
|
|
1405
|
+
);
|
|
1406
|
+
}
|
|
1304
1407
|
var band = {
|
|
1305
1408
|
terracota: "bg-terracota-soft",
|
|
1306
1409
|
jardim: "bg-jardim-soft",
|
|
@@ -1591,4 +1694,4 @@ function ThemeToggle({ width, className }) {
|
|
|
1591
1694
|
);
|
|
1592
1695
|
}
|
|
1593
1696
|
|
|
1594
|
-
export { Avatar, AvatarGroup, Badge, Banner, Button, Card, Checkbox, Cracha, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, DialogTrigger, EmptyState, Field, IconButton, Input, List, ListItem, Livreto, Popover, PopoverContent, PopoverTrigger, Predio, Progress, RadioGroup, RadioGroupItem, SearchField, SegmentedControl, Select, SelectItem, Separator, Sheet, SheetContent, SheetDescription, SheetHeader, SheetTitle, SheetTrigger, Skeleton, Spinner, Switch, Tabs, TabsContent, TabsList, TabsTrigger, Textarea, ThemeProvider, ThemeToggle, ToastProvider, Tooltip, VisuallyHidden, cn, initTheme, useFieldContext, useTheme, useToast };
|
|
1697
|
+
export { Avatar, AvatarGroup, Badge, Banner, Button, Card, Checkbox, CodeInput, CpfInput, Cracha, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, DialogTrigger, EmptyState, Field, IconButton, Input, List, ListItem, Livreto, Popover, PopoverContent, PopoverTrigger, Predio, Progress, RadioGroup, RadioGroupItem, SearchField, SegmentedControl, Select, SelectItem, Separator, Sheet, SheetContent, SheetDescription, SheetHeader, SheetTitle, SheetTrigger, Skeleton, Spinner, Switch, Tabs, TabsContent, TabsList, TabsTrigger, Textarea, ThemeProvider, ThemeToggle, ToastProvider, Tooltip, VisuallyHidden, WhatsappInput, cn, formatCpf, formatWhatsapp, initTheme, useFieldContext, useTheme, useToast };
|
package/dist/theme.css
CHANGED
|
@@ -325,6 +325,12 @@
|
|
|
325
325
|
--text-caption: 0.75rem;
|
|
326
326
|
--text-caption--line-height: 1.34;
|
|
327
327
|
|
|
328
|
+
/*
|
|
329
|
+
* Seis dígitos num campo só precisam respirar para serem conferidos de relance
|
|
330
|
+
* contra o que chegou no WhatsApp. Espaçamento, não cor: sem par no escuro.
|
|
331
|
+
*/
|
|
332
|
+
--tracking-codigo: 0.5em;
|
|
333
|
+
|
|
328
334
|
/*
|
|
329
335
|
* Raios generosos — a assinatura de forma do Assembleo. `control` para o que
|
|
330
336
|
* se aperta, `surface` para o que contém, `expressive` para a camada lúdica.
|