@proef/common-ui 2.6.1 → 2.6.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.
@@ -23,7 +23,7 @@ function FormField({ label, required, hint, marks, markSlots, aside, end, wide,
23
23
  "label",
24
24
  {
25
25
  htmlFor: id,
26
- className: "m-0 text-xs leading-[18px] font-medium whitespace-nowrap text-muted-foreground @max-form-md:whitespace-normal",
26
+ className: "m-0 text-xs leading-[18px] font-medium text-muted-foreground",
27
27
  children: [
28
28
  label,
29
29
  required && /* @__PURE__ */ jsx("span", { "aria-hidden": true, className: "ml-0.5 text-destructive", children: "*" })
@@ -1 +1 @@
1
- {"version":3,"file":"FormField.js","sources":["../../../../../../src/v1/components/forms/FormField/FormField.tsx"],"sourcesContent":["import React, { useId } from 'react'\r\nimport { FieldContext } from '../../../primitives/forms/field'\r\nimport { useFormGrid } from '../FormGrid/FormGrid'\r\n\r\nexport interface FormFieldProps {\r\n label: string\r\n /** Asterisco vermelho na etiqueta; o campo lá dentro fica `required`. */\r\n required?: boolean\r\n /** Texto pequeno por baixo da etiqueta. */\r\n hint?: string\r\n /**\r\n * Marcas antes da etiqueta, a dizer de onde veio o valor (ex: lido do QR,\r\n * identificado pela IA). Usar [FieldMark](#fieldmark).\r\n */\r\n marks?: React.ReactNode\r\n /**\r\n * Lugares reservados para marcas, mesmo sem nenhuma. Assim a etiqueta não\r\n * salta quando uma marca aparece depois (ex: ao ler o QR).\r\n */\r\n markSlots?: number\r\n /** Algo junto à etiqueta, depois das marcas (ex: o valor máximo permitido). */\r\n aside?: React.ReactNode\r\n /** Depois do campo, na mesma linha (ex: cadeado, ícone de informação). */\r\n end?: React.ReactNode\r\n /** Ocupa a linha toda (ex: observações, anexo). */\r\n wide?: boolean\r\n /** Etiqueta alinhada ao topo em vez de ao meio (campos altos, como o [TextArea](?path=/docs/v1-primitives-forms-textarea--docs)). */\r\n alignTop?: boolean\r\n /** O campo: [TextInput](?path=/docs/v1-primitives-forms-textinput--docs), [SelectInput](?path=/docs/v1-primitives-forms-selectinput--docs), [TextArea](?path=/docs/v1-primitives-forms-textarea--docs), [LookupInput](?path=/docs/v1-primitives-forms-lookupinput--docs) ou outro. */\r\n children: React.ReactNode\r\n}\r\n\r\nconst MARK = 17\r\nconst MARK_GAP = 4\r\n\r\n/**\r\n * Uma linha do formulário: etiqueta e campo. Vai dentro de um\r\n * [FormGrid](?path=/docs/v1-components-forms-formgrid--docs).\r\n *\r\n * Liga a etiqueta ao campo (clicar na etiqueta foca o campo) e passa-lhe o\r\n * `required`, se o campo for [TextInput](?path=/docs/v1-primitives-forms-textinput--docs), [SelectInput](?path=/docs/v1-primitives-forms-selectinput--docs), [TextArea](?path=/docs/v1-primitives-forms-textarea--docs) ou [LookupInput](?path=/docs/v1-primitives-forms-lookupinput--docs).\r\n */\r\nexport default function FormField({ label, required, hint, marks, markSlots, aside, end, wide, alignTop, children }: FormFieldProps) {\r\n const id = useId()\r\n const { columns } = useFormGrid()\r\n const marksCount = React.Children.count(marks)\r\n const slots = Math.max(markSlots ?? 0, marksCount)\r\n // Em 2 colunas, o campo largo começa sempre numa linha nova: depois de um campo\r\n // de meia linha, a etiqueta caía na 3.ª coluna e o campo descia para a linha seguinte.\r\n const wideRow = wide && columns === 2\r\n\r\n return (\r\n <FieldContext.Provider value={{ id, required }}>\r\n <div\r\n className={`flex flex-col items-end pr-3 text-right @max-form-sm:items-start @max-form-sm:pr-0 @max-form-sm:pt-0 @max-form-sm:text-left ${wideRow ? 'col-start-1' : ''} ${alignTop ? 'self-start pt-[7px]' : ''}`}\r\n >\r\n {/* As marcas ficam fora do <label>, para não entrarem no nome do campo lido pelos leitores de ecrã. */}\r\n <div className=\"flex items-center justify-end @max-form-sm:justify-start\">\r\n {slots > 0 && (\r\n <span className=\"mr-[5px] inline-flex flex-none items-center justify-end gap-1\" style={{ width: slots * MARK + (slots - 1) * MARK_GAP }}>\r\n {marks}\r\n </span>\r\n )}\r\n {aside && <span className=\"mr-1.5 flex-none\">{aside}</span>}\r\n <label\r\n htmlFor={id}\r\n className=\"m-0 text-xs leading-[18px] font-medium whitespace-nowrap text-muted-foreground @max-form-md:whitespace-normal\"\r\n >\r\n {label}\r\n {required && (\r\n <span aria-hidden className=\"ml-0.5 text-destructive\">\r\n *\r\n </span>\r\n )}\r\n </label>\r\n </div>\r\n {hint && <span className=\"text-micro text-muted-foreground\">{hint}</span>}\r\n </div>\r\n <div className={`min-w-0 ${wideRow ? 'col-span-3 @max-form-sm:col-span-1' : ''} ${end ? 'flex items-center gap-1.5' : ''}`}>\r\n {children}\r\n {end}\r\n </div>\r\n </FieldContext.Provider>\r\n )\r\n}\r\n\r\nexport interface FieldMarkProps {\r\n /** De onde veio o valor (ex: \"Lido do QR Code\"). Mostrado ao passar o rato e lido pelos leitores de ecrã. */\r\n title: string\r\n /** O ícone, a 11 px (ex: `<QrCodeIcon size={11} />`). */\r\n icon: React.ReactNode\r\n}\r\n\r\n/** Marca pequena antes da etiqueta de um FormField, a dizer de onde veio o valor. */\r\nexport function FieldMark({ title, icon }: FieldMarkProps) {\r\n return (\r\n <span\r\n role=\"img\"\r\n aria-label={title}\r\n title={title}\r\n className=\"inline-flex h-[17px] w-[17px] flex-none cursor-help items-center justify-center rounded-[5px] border border-primary/20 bg-primary/5 text-primary\"\r\n >\r\n {icon}\r\n </span>\r\n )\r\n}\r\n"],"names":[],"mappings":";;;;AAgCA,MAAM,OAAO;AACb,MAAM,WAAW;AASjB,SAAwB,UAAU,EAAE,OAAO,UAAU,MAAM,OAAO,WAAW,OAAO,KAAK,MAAM,UAAU,SAAA,GAA4B;AACnI,QAAM,KAAK,MAAA;AACX,QAAM,EAAE,QAAA,IAAY,YAAA;AACpB,QAAM,aAAa,MAAM,SAAS,MAAM,KAAK;AAC7C,QAAM,QAAQ,KAAK,IAAI,aAAa,GAAG,UAAU;AAGjD,QAAM,UAAU,QAAQ,YAAY;AAEpC,SACE,qBAAC,aAAa,UAAb,EAAsB,OAAO,EAAE,IAAI,YAClC,UAAA;AAAA,IAAA;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,WAAW,+HAA+H,UAAU,gBAAgB,EAAE,IAAI,WAAW,wBAAwB,EAAE;AAAA,QAG/M,UAAA;AAAA,UAAA,qBAAC,OAAA,EAAI,WAAU,4DACZ,UAAA;AAAA,YAAA,QAAQ,KACP,oBAAC,QAAA,EAAK,WAAU,iEAAgE,OAAO,EAAE,OAAO,QAAQ,QAAQ,QAAQ,KAAK,YAC1H,UAAA,OACH;AAAA,YAED,SAAS,oBAAC,QAAA,EAAK,WAAU,oBAAoB,UAAA,OAAM;AAAA,YACpD;AAAA,cAAC;AAAA,cAAA;AAAA,gBACC,SAAS;AAAA,gBACT,WAAU;AAAA,gBAET,UAAA;AAAA,kBAAA;AAAA,kBACA,YACC,oBAAC,QAAA,EAAK,eAAW,MAAC,WAAU,2BAA0B,UAAA,IAAA,CAEtD;AAAA,gBAAA;AAAA,cAAA;AAAA,YAAA;AAAA,UAEJ,GACF;AAAA,UACC,QAAQ,oBAAC,QAAA,EAAK,WAAU,oCAAoC,UAAA,KAAA,CAAK;AAAA,QAAA;AAAA,MAAA;AAAA,IAAA;AAAA,IAEpE,qBAAC,OAAA,EAAI,WAAW,WAAW,UAAU,uCAAuC,EAAE,IAAI,MAAM,8BAA8B,EAAE,IACrH,UAAA;AAAA,MAAA;AAAA,MACA;AAAA,IAAA,EAAA,CACH;AAAA,EAAA,GACF;AAEJ;AAUO,SAAS,UAAU,EAAE,OAAO,QAAwB;AACzD,SACE;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,MAAK;AAAA,MACL,cAAY;AAAA,MACZ;AAAA,MACA,WAAU;AAAA,MAET,UAAA;AAAA,IAAA;AAAA,EAAA;AAGP;"}
1
+ {"version":3,"file":"FormField.js","sources":["../../../../../../src/v1/components/forms/FormField/FormField.tsx"],"sourcesContent":["import React, { useId } from 'react'\r\nimport { FieldContext } from '../../../primitives/forms/field'\r\nimport { useFormGrid } from '../FormGrid/FormGrid'\r\n\r\nexport interface FormFieldProps {\r\n label: string\r\n /** Asterisco vermelho na etiqueta; o campo lá dentro fica `required`. */\r\n required?: boolean\r\n /** Texto pequeno por baixo da etiqueta. */\r\n hint?: string\r\n /**\r\n * Marcas antes da etiqueta, a dizer de onde veio o valor (ex: lido do QR,\r\n * identificado pela IA). Usar [FieldMark](#fieldmark).\r\n */\r\n marks?: React.ReactNode\r\n /**\r\n * Lugares reservados para marcas, mesmo sem nenhuma. Assim a etiqueta não\r\n * salta quando uma marca aparece depois (ex: ao ler o QR).\r\n */\r\n markSlots?: number\r\n /** Algo junto à etiqueta, depois das marcas (ex: o valor máximo permitido). */\r\n aside?: React.ReactNode\r\n /** Depois do campo, na mesma linha (ex: cadeado, ícone de informação). */\r\n end?: React.ReactNode\r\n /** Ocupa a linha toda (ex: observações, anexo). */\r\n wide?: boolean\r\n /** Etiqueta alinhada ao topo em vez de ao meio (campos altos, como o [TextArea](?path=/docs/v1-primitives-forms-textarea--docs)). */\r\n alignTop?: boolean\r\n /** O campo: [TextInput](?path=/docs/v1-primitives-forms-textinput--docs), [SelectInput](?path=/docs/v1-primitives-forms-selectinput--docs), [TextArea](?path=/docs/v1-primitives-forms-textarea--docs), [LookupInput](?path=/docs/v1-primitives-forms-lookupinput--docs) ou outro. */\r\n children: React.ReactNode\r\n}\r\n\r\nconst MARK = 17\r\nconst MARK_GAP = 4\r\n\r\n/**\r\n * Uma linha do formulário: etiqueta e campo. Vai dentro de um\r\n * [FormGrid](?path=/docs/v1-components-forms-formgrid--docs).\r\n *\r\n * Liga a etiqueta ao campo (clicar na etiqueta foca o campo) e passa-lhe o\r\n * `required`, se o campo for [TextInput](?path=/docs/v1-primitives-forms-textinput--docs), [SelectInput](?path=/docs/v1-primitives-forms-selectinput--docs), [TextArea](?path=/docs/v1-primitives-forms-textarea--docs) ou [LookupInput](?path=/docs/v1-primitives-forms-lookupinput--docs).\r\n */\r\nexport default function FormField({ label, required, hint, marks, markSlots, aside, end, wide, alignTop, children }: FormFieldProps) {\r\n const id = useId()\r\n const { columns } = useFormGrid()\r\n const marksCount = React.Children.count(marks)\r\n const slots = Math.max(markSlots ?? 0, marksCount)\r\n // Em 2 colunas, o campo largo começa sempre numa linha nova: depois de um campo\r\n // de meia linha, a etiqueta caía na 3.ª coluna e o campo descia para a linha seguinte.\r\n const wideRow = wide && columns === 2\r\n\r\n return (\r\n <FieldContext.Provider value={{ id, required }}>\r\n <div\r\n className={`flex flex-col items-end pr-3 text-right @max-form-sm:items-start @max-form-sm:pr-0 @max-form-sm:pt-0 @max-form-sm:text-left ${wideRow ? 'col-start-1' : ''} ${alignTop ? 'self-start pt-[7px]' : ''}`}\r\n >\r\n {/* As marcas ficam fora do <label>, para não entrarem no nome do campo lido pelos leitores de ecrã. */}\r\n <div className=\"flex items-center justify-end @max-form-sm:justify-start\">\r\n {slots > 0 && (\r\n <span className=\"mr-[5px] inline-flex flex-none items-center justify-end gap-1\" style={{ width: slots * MARK + (slots - 1) * MARK_GAP }}>\r\n {marks}\r\n </span>\r\n )}\r\n {aside && <span className=\"mr-1.5 flex-none\">{aside}</span>}\r\n {/* A coluna das etiquetas tem largura fixa: uma etiqueta mais comprida passa para a\r\n linha seguinte em vez de sair pela esquerda (ex: \"Mensagem para o requisitante\"). */}\r\n <label\r\n htmlFor={id}\r\n className=\"m-0 text-xs leading-[18px] font-medium text-muted-foreground\"\r\n >\r\n {label}\r\n {required && (\r\n <span aria-hidden className=\"ml-0.5 text-destructive\">\r\n *\r\n </span>\r\n )}\r\n </label>\r\n </div>\r\n {hint && <span className=\"text-micro text-muted-foreground\">{hint}</span>}\r\n </div>\r\n <div className={`min-w-0 ${wideRow ? 'col-span-3 @max-form-sm:col-span-1' : ''} ${end ? 'flex items-center gap-1.5' : ''}`}>\r\n {children}\r\n {end}\r\n </div>\r\n </FieldContext.Provider>\r\n )\r\n}\r\n\r\nexport interface FieldMarkProps {\r\n /** De onde veio o valor (ex: \"Lido do QR Code\"). Mostrado ao passar o rato e lido pelos leitores de ecrã. */\r\n title: string\r\n /** O ícone, a 11 px (ex: `<QrCodeIcon size={11} />`). */\r\n icon: React.ReactNode\r\n}\r\n\r\n/** Marca pequena antes da etiqueta de um FormField, a dizer de onde veio o valor. */\r\nexport function FieldMark({ title, icon }: FieldMarkProps) {\r\n return (\r\n <span\r\n role=\"img\"\r\n aria-label={title}\r\n title={title}\r\n className=\"inline-flex h-[17px] w-[17px] flex-none cursor-help items-center justify-center rounded-[5px] border border-primary/20 bg-primary/5 text-primary\"\r\n >\r\n {icon}\r\n </span>\r\n )\r\n}\r\n"],"names":[],"mappings":";;;;AAgCA,MAAM,OAAO;AACb,MAAM,WAAW;AASjB,SAAwB,UAAU,EAAE,OAAO,UAAU,MAAM,OAAO,WAAW,OAAO,KAAK,MAAM,UAAU,SAAA,GAA4B;AACnI,QAAM,KAAK,MAAA;AACX,QAAM,EAAE,QAAA,IAAY,YAAA;AACpB,QAAM,aAAa,MAAM,SAAS,MAAM,KAAK;AAC7C,QAAM,QAAQ,KAAK,IAAI,aAAa,GAAG,UAAU;AAGjD,QAAM,UAAU,QAAQ,YAAY;AAEpC,SACE,qBAAC,aAAa,UAAb,EAAsB,OAAO,EAAE,IAAI,YAClC,UAAA;AAAA,IAAA;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,WAAW,+HAA+H,UAAU,gBAAgB,EAAE,IAAI,WAAW,wBAAwB,EAAE;AAAA,QAG/M,UAAA;AAAA,UAAA,qBAAC,OAAA,EAAI,WAAU,4DACZ,UAAA;AAAA,YAAA,QAAQ,KACP,oBAAC,QAAA,EAAK,WAAU,iEAAgE,OAAO,EAAE,OAAO,QAAQ,QAAQ,QAAQ,KAAK,YAC1H,UAAA,OACH;AAAA,YAED,SAAS,oBAAC,QAAA,EAAK,WAAU,oBAAoB,UAAA,OAAM;AAAA,YAGpD;AAAA,cAAC;AAAA,cAAA;AAAA,gBACC,SAAS;AAAA,gBACT,WAAU;AAAA,gBAET,UAAA;AAAA,kBAAA;AAAA,kBACA,YACC,oBAAC,QAAA,EAAK,eAAW,MAAC,WAAU,2BAA0B,UAAA,IAAA,CAEtD;AAAA,gBAAA;AAAA,cAAA;AAAA,YAAA;AAAA,UAEJ,GACF;AAAA,UACC,QAAQ,oBAAC,QAAA,EAAK,WAAU,oCAAoC,UAAA,KAAA,CAAK;AAAA,QAAA;AAAA,MAAA;AAAA,IAAA;AAAA,IAEpE,qBAAC,OAAA,EAAI,WAAW,WAAW,UAAU,uCAAuC,EAAE,IAAI,MAAM,8BAA8B,EAAE,IACrH,UAAA;AAAA,MAAA;AAAA,MACA;AAAA,IAAA,EAAA,CACH;AAAA,EAAA,GACF;AAEJ;AAUO,SAAS,UAAU,EAAE,OAAO,QAAwB;AACzD,SACE;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,MAAK;AAAA,MACL,cAAY;AAAA,MACZ;AAAA,MACA,WAAU;AAAA,MAET,UAAA;AAAA,IAAA;AAAA,EAAA;AAGP;"}
@@ -14,7 +14,8 @@ const SIZES = {
14
14
  md: "h-7 w-7 text-[10px]",
15
15
  lg: "h-8 w-8 text-[11px]"
16
16
  };
17
- const INITIALS = "rounded-full bg-gradient-to-br from-sky-400 to-sky-600 font-black text-white";
17
+ const INITIALS_COLORS = "bg-gradient-to-br from-avatar-from to-avatar-to text-avatar-fg";
18
+ const INITIALS = `rounded-full font-black ${INITIALS_COLORS}`;
18
19
  function Avatar({
19
20
  name,
20
21
  photo,
@@ -95,7 +96,7 @@ function Avatar({
95
96
  style: { position: "fixed", top: pos.top, left: pos.left, zIndex: 9999, width: 200 },
96
97
  className: "pointer-events-none overflow-hidden rounded-2xl border border-border bg-card shadow-2xl ring-4 ring-white dark:border-slate-700 dark:bg-slate-900 dark:ring-slate-800",
97
98
  children: [
98
- /* @__PURE__ */ jsx("div", { className: "h-48 w-48 overflow-hidden rounded-xl", children: large && !failed ? /* @__PURE__ */ jsx("img", { src: large, alt: name ?? "", className: "h-full w-full object-cover", onError: () => setFailed(true) }) : /* @__PURE__ */ jsx("div", { className: "flex h-full w-full items-center justify-center bg-gradient-to-br from-sky-400 to-sky-600 text-4xl font-black text-white", children: initials(name) }) }),
99
+ /* @__PURE__ */ jsx("div", { className: "h-48 w-48 overflow-hidden rounded-xl", children: large && !failed ? /* @__PURE__ */ jsx("img", { src: large, alt: name ?? "", className: "h-full w-full object-cover", onError: () => setFailed(true) }) : /* @__PURE__ */ jsx("div", { className: `flex h-full w-full items-center justify-center text-4xl font-black ${INITIALS_COLORS}`, children: initials(name) }) }),
99
100
  /* @__PURE__ */ jsxs("div", { className: "space-y-1 px-3 py-2.5", children: [
100
101
  name && /* @__PURE__ */ jsx("p", { className: "text-[12px] leading-tight font-black tracking-tight break-words text-foreground", children: name }),
101
102
  email && /* @__PURE__ */ jsx("p", { className: "truncate text-[10px] text-muted-foreground", children: email }),
@@ -1 +1 @@
1
- {"version":3,"file":"Avatar.js","sources":["../../../../../../src/v1/primitives/display/Avatar/Avatar.tsx"],"sourcesContent":["import React, { useEffect, useRef, useState } from 'react'\r\nimport { createPortal } from 'react-dom'\r\n\r\n/** Iniciais a partir do nome completo (primeira + última). Sem nome: \"?\". */\r\nexport function initials(fullName?: string | null): string {\r\n const parts = (fullName ?? '').trim().split(/\\s+/).filter(Boolean)\r\n if (parts.length === 0) return '?'\r\n const first = parts[0]!.charAt(0)\r\n const last = parts.length > 1 ? parts[parts.length - 1]!.charAt(0) : ''\r\n return (first + last).toUpperCase()\r\n}\r\n\r\n/** `none`: sem tamanho nem cores das iniciais — quem usa põe as classes (ex: o UserAvatar da Legacy). */\r\nexport type AvatarSize = 'sm' | 'md' | 'lg' | 'none'\r\n\r\nexport interface AvatarProps {\r\n name?: string | null\r\n /** URL da fotografia. Sem ela (ou se falhar) ficam as iniciais. */\r\n photo?: string | null\r\n /** Fotografia maior para o cartão (por omissão, a mesma). */\r\n photoLarge?: string | null\r\n email?: string | null\r\n company?: string | null\r\n department?: string | null\r\n jobTitle?: string | null\r\n /** `sm` 24px (tabelas e listas), `md` 28px, `lg` 32px (formulários, cabeçalhos). */\r\n size?: AvatarSize\r\n /** Cartão com a fotografia grande e os dados ao passar o rato (no toque, ao tocar). */\r\n card?: boolean\r\n className?: string\r\n}\r\n\r\nconst SIZES: Record<AvatarSize, string> = {\r\n none: '',\r\n sm: 'h-6 w-6 text-[9px]',\r\n md: 'h-7 w-7 text-[10px]',\r\n lg: 'h-8 w-8 text-[11px]',\r\n}\r\n\r\n// Iniciais (sem fotografia): o mesmo azul em todos os portais.\r\nconst INITIALS = 'rounded-full bg-gradient-to-br from-sky-400 to-sky-600 font-black text-white'\r\n\r\n/**\r\n * A fotografia de uma pessoa (ou as iniciais), redonda. Com `card`, mostra a\r\n * fotografia grande, o email, a empresa, o departamento e a função ao passar o rato;\r\n * no toque abre e fecha ao tocar, sem passar o toque à linha por baixo.\r\n *\r\n * Para uma pessoa com o nome ao lado (ex: numa tabela), usar o `Person`.\r\n */\r\nexport default function Avatar({\r\n name,\r\n photo,\r\n photoLarge,\r\n email,\r\n company,\r\n department,\r\n jobTitle,\r\n size = 'sm',\r\n card = true,\r\n className = '',\r\n}: AvatarProps) {\r\n const ref = useRef<HTMLSpanElement>(null)\r\n const [pos, setPos] = useState<{ top: number; left: number } | null>(null)\r\n const [pinned, setPinned] = useState(false)\r\n const [failed, setFailed] = useState(false)\r\n const pointer = useRef('mouse')\r\n const large = photoLarge ?? photo\r\n\r\n // Uma falha (ex: API em baixo) não pode marcar \"sem foto\" para sempre: em listas a\r\n // mesma instância passa a ser outra pessoa.\r\n useEffect(() => setFailed(false), [photo])\r\n\r\n const open = () => {\r\n if (!card || !ref.current) return\r\n const r = ref.current.getBoundingClientRect()\r\n const W = 200\r\n const H = email || company || jobTitle || department ? 280 : 196\r\n let left = r.right + 10\r\n let top = r.top + r.height / 2 - H / 2\r\n if (left + W > window.innerWidth - 8) left = r.left - W - 10\r\n if (top + H > window.innerHeight - 8) top = window.innerHeight - H - 8\r\n if (top < 8) top = 8\r\n setPos({ top, left })\r\n }\r\n const close = () => {\r\n setPos(null)\r\n setPinned(false)\r\n }\r\n\r\n // Aberto por toque: fecha ao tocar fora, ao deslocar ou ao redimensionar.\r\n useEffect(() => {\r\n if (!pinned) return\r\n const dismiss = (e: Event) => {\r\n if (e.type === 'pointerdown' && ref.current?.contains(e.target as Node)) return\r\n close()\r\n }\r\n document.addEventListener('pointerdown', dismiss)\r\n window.addEventListener('scroll', dismiss, true)\r\n window.addEventListener('resize', dismiss)\r\n return () => {\r\n document.removeEventListener('pointerdown', dismiss)\r\n window.removeEventListener('scroll', dismiss, true)\r\n window.removeEventListener('resize', dismiss)\r\n }\r\n }, [pinned])\r\n\r\n const showPhoto = !!photo && !failed\r\n\r\n return (\r\n <>\r\n <span\r\n ref={ref}\r\n className={`inline-flex shrink-0 items-center justify-center overflow-hidden ${SIZES[size]} ${showPhoto ? 'rounded-full' : size === 'none' ? '' : INITIALS} ${card ? 'cursor-pointer' : ''} ${className}`}\r\n onPointerEnter={(e) => e.pointerType === 'mouse' && open()}\r\n onPointerLeave={(e) => e.pointerType === 'mouse' && !pinned && close()}\r\n onPointerDown={(e) => {\r\n pointer.current = e.pointerType\r\n }}\r\n onClick={(e) => {\r\n if (!card || pointer.current === 'mouse') return\r\n e.preventDefault()\r\n e.stopPropagation()\r\n if (pinned) return close()\r\n open()\r\n setPinned(true)\r\n }}\r\n >\r\n {showPhoto ? (\r\n <img src={photo!} alt={name ?? ''} className=\"h-full w-full object-cover\" onError={() => setFailed(true)} />\r\n ) : (\r\n initials(name)\r\n )}\r\n </span>\r\n {pos &&\r\n createPortal(\r\n <div\r\n style={{ position: 'fixed', top: pos.top, left: pos.left, zIndex: 9999, width: 200 }}\r\n className=\"pointer-events-none overflow-hidden rounded-2xl border border-border bg-card shadow-2xl ring-4 ring-white dark:border-slate-700 dark:bg-slate-900 dark:ring-slate-800\"\r\n >\r\n <div className=\"h-48 w-48 overflow-hidden rounded-xl\">\r\n {large && !failed ? (\r\n <img src={large} alt={name ?? ''} className=\"h-full w-full object-cover\" onError={() => setFailed(true)} />\r\n ) : (\r\n <div className=\"flex h-full w-full items-center justify-center bg-gradient-to-br from-sky-400 to-sky-600 text-4xl font-black text-white\">\r\n {initials(name)}\r\n </div>\r\n )}\r\n </div>\r\n <div className=\"space-y-1 px-3 py-2.5\">\r\n {name && <p className=\"text-[12px] leading-tight font-black tracking-tight break-words text-foreground\">{name}</p>}\r\n {email && <p className=\"truncate text-[10px] text-muted-foreground\">{email}</p>}\r\n {(company || department || jobTitle) && (\r\n <div className=\"mt-1 space-y-0.5 border-t border-border pt-1 dark:border-slate-700\">\r\n {company && <p className=\"truncate text-[10px] font-semibold text-foreground\">{company}</p>}\r\n {department && <p className=\"truncate text-[10px] text-muted-foreground\">{department}</p>}\r\n {jobTitle && <p className=\"truncate text-[10px] text-muted-foreground italic\">{jobTitle}</p>}\r\n </div>\r\n )}\r\n </div>\r\n </div>,\r\n document.body,\r\n )}\r\n </>\r\n )\r\n}\r\n\r\nexport { Avatar }\r\n"],"names":[],"mappings":";;;AAIO,SAAS,SAAS,UAAkC;AACzD,QAAM,SAAS,YAAY,IAAI,OAAO,MAAM,KAAK,EAAE,OAAO,OAAO;AACjE,MAAI,MAAM,WAAW,EAAG,QAAO;AAC/B,QAAM,QAAQ,MAAM,CAAC,EAAG,OAAO,CAAC;AAChC,QAAM,OAAO,MAAM,SAAS,IAAI,MAAM,MAAM,SAAS,CAAC,EAAG,OAAO,CAAC,IAAI;AACrE,UAAQ,QAAQ,MAAM,YAAA;AACxB;AAsBA,MAAM,QAAoC;AAAA,EACxC,MAAM;AAAA,EACN,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AACN;AAGA,MAAM,WAAW;AASjB,SAAwB,OAAO;AAAA,EAC7B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,OAAO;AAAA,EACP,OAAO;AAAA,EACP,YAAY;AACd,GAAgB;AACd,QAAM,MAAM,OAAwB,IAAI;AACxC,QAAM,CAAC,KAAK,MAAM,IAAI,SAA+C,IAAI;AACzE,QAAM,CAAC,QAAQ,SAAS,IAAI,SAAS,KAAK;AAC1C,QAAM,CAAC,QAAQ,SAAS,IAAI,SAAS,KAAK;AAC1C,QAAM,UAAU,OAAO,OAAO;AAC9B,QAAM,QAAQ,cAAc;AAI5B,YAAU,MAAM,UAAU,KAAK,GAAG,CAAC,KAAK,CAAC;AAEzC,QAAM,OAAO,MAAM;AACjB,QAAI,CAAC,QAAQ,CAAC,IAAI,QAAS;AAC3B,UAAM,IAAI,IAAI,QAAQ,sBAAA;AACtB,UAAM,IAAI;AACV,UAAM,IAAI,SAAS,WAAW,YAAY,aAAa,MAAM;AAC7D,QAAI,OAAO,EAAE,QAAQ;AACrB,QAAI,MAAM,EAAE,MAAM,EAAE,SAAS,IAAI,IAAI;AACrC,QAAI,OAAO,IAAI,OAAO,aAAa,EAAG,QAAO,EAAE,OAAO,IAAI;AAC1D,QAAI,MAAM,IAAI,OAAO,cAAc,EAAG,OAAM,OAAO,cAAc,IAAI;AACrE,QAAI,MAAM,EAAG,OAAM;AACnB,WAAO,EAAE,KAAK,MAAM;AAAA,EACtB;AACA,QAAM,QAAQ,MAAM;AAClB,WAAO,IAAI;AACX,cAAU,KAAK;AAAA,EACjB;AAGA,YAAU,MAAM;AACd,QAAI,CAAC,OAAQ;AACb,UAAM,UAAU,CAAC,MAAa;AAC5B,UAAI,EAAE,SAAS,iBAAiB,IAAI,SAAS,SAAS,EAAE,MAAc,EAAG;AACzE,YAAA;AAAA,IACF;AACA,aAAS,iBAAiB,eAAe,OAAO;AAChD,WAAO,iBAAiB,UAAU,SAAS,IAAI;AAC/C,WAAO,iBAAiB,UAAU,OAAO;AACzC,WAAO,MAAM;AACX,eAAS,oBAAoB,eAAe,OAAO;AACnD,aAAO,oBAAoB,UAAU,SAAS,IAAI;AAClD,aAAO,oBAAoB,UAAU,OAAO;AAAA,IAC9C;AAAA,EACF,GAAG,CAAC,MAAM,CAAC;AAEX,QAAM,YAAY,CAAC,CAAC,SAAS,CAAC;AAE9B,SACE,qBAAA,UAAA,EACE,UAAA;AAAA,IAAA;AAAA,MAAC;AAAA,MAAA;AAAA,QACC;AAAA,QACA,WAAW,oEAAoE,MAAM,IAAI,CAAC,IAAI,YAAY,iBAAiB,SAAS,SAAS,KAAK,QAAQ,IAAI,OAAO,mBAAmB,EAAE,IAAI,SAAS;AAAA,QACvM,gBAAgB,CAAC,MAAM,EAAE,gBAAgB,WAAW,KAAA;AAAA,QACpD,gBAAgB,CAAC,MAAM,EAAE,gBAAgB,WAAW,CAAC,UAAU,MAAA;AAAA,QAC/D,eAAe,CAAC,MAAM;AACpB,kBAAQ,UAAU,EAAE;AAAA,QACtB;AAAA,QACA,SAAS,CAAC,MAAM;AACd,cAAI,CAAC,QAAQ,QAAQ,YAAY,QAAS;AAC1C,YAAE,eAAA;AACF,YAAE,gBAAA;AACF,cAAI,eAAe,MAAA;AACnB,eAAA;AACA,oBAAU,IAAI;AAAA,QAChB;AAAA,QAEC,sBACC,oBAAC,OAAA,EAAI,KAAK,OAAQ,KAAK,QAAQ,IAAI,WAAU,8BAA6B,SAAS,MAAM,UAAU,IAAI,EAAA,CAAG,IAE1G,SAAS,IAAI;AAAA,MAAA;AAAA,IAAA;AAAA,IAGhB,OACC;AAAA,MACE;AAAA,QAAC;AAAA,QAAA;AAAA,UACC,OAAO,EAAE,UAAU,SAAS,KAAK,IAAI,KAAK,MAAM,IAAI,MAAM,QAAQ,MAAM,OAAO,IAAA;AAAA,UAC/E,WAAU;AAAA,UAEV,UAAA;AAAA,YAAA,oBAAC,OAAA,EAAI,WAAU,wCACZ,UAAA,SAAS,CAAC,SACT,oBAAC,OAAA,EAAI,KAAK,OAAO,KAAK,QAAQ,IAAI,WAAU,8BAA6B,SAAS,MAAM,UAAU,IAAI,EAAA,CAAG,IAEzG,oBAAC,OAAA,EAAI,WAAU,2HACZ,UAAA,SAAS,IAAI,EAAA,CAChB,GAEJ;AAAA,YACA,qBAAC,OAAA,EAAI,WAAU,yBACZ,UAAA;AAAA,cAAA,QAAQ,oBAAC,KAAA,EAAE,WAAU,mFAAmF,UAAA,MAAK;AAAA,cAC7G,SAAS,oBAAC,KAAA,EAAE,WAAU,8CAA8C,UAAA,OAAM;AAAA,eACzE,WAAW,cAAc,aACzB,qBAAC,OAAA,EAAI,WAAU,sEACZ,UAAA;AAAA,gBAAA,WAAW,oBAAC,KAAA,EAAE,WAAU,sDAAsD,UAAA,SAAQ;AAAA,gBACtF,cAAc,oBAAC,KAAA,EAAE,WAAU,8CAA8C,UAAA,YAAW;AAAA,gBACpF,YAAY,oBAAC,KAAA,EAAE,WAAU,qDAAqD,UAAA,SAAA,CAAS;AAAA,cAAA,EAAA,CAC1F;AAAA,YAAA,EAAA,CAEJ;AAAA,UAAA;AAAA,QAAA;AAAA,MAAA;AAAA,MAEF,SAAS;AAAA,IAAA;AAAA,EACX,GACJ;AAEJ;"}
1
+ {"version":3,"file":"Avatar.js","sources":["../../../../../../src/v1/primitives/display/Avatar/Avatar.tsx"],"sourcesContent":["import React, { useEffect, useRef, useState } from 'react'\r\nimport { createPortal } from 'react-dom'\r\n\r\n/** Iniciais a partir do nome completo (primeira + última). Sem nome: \"?\". */\r\nexport function initials(fullName?: string | null): string {\r\n const parts = (fullName ?? '').trim().split(/\\s+/).filter(Boolean)\r\n if (parts.length === 0) return '?'\r\n const first = parts[0]!.charAt(0)\r\n const last = parts.length > 1 ? parts[parts.length - 1]!.charAt(0) : ''\r\n return (first + last).toUpperCase()\r\n}\r\n\r\n/** `none`: sem tamanho nem cores das iniciais — quem usa põe as classes (ex: o UserAvatar da Legacy). */\r\nexport type AvatarSize = 'sm' | 'md' | 'lg' | 'none'\r\n\r\nexport interface AvatarProps {\r\n name?: string | null\r\n /** URL da fotografia. Sem ela (ou se falhar) ficam as iniciais. */\r\n photo?: string | null\r\n /** Fotografia maior para o cartão (por omissão, a mesma). */\r\n photoLarge?: string | null\r\n email?: string | null\r\n company?: string | null\r\n department?: string | null\r\n jobTitle?: string | null\r\n /** `sm` 24px (tabelas e listas), `md` 28px, `lg` 32px (formulários, cabeçalhos). */\r\n size?: AvatarSize\r\n /** Cartão com a fotografia grande e os dados ao passar o rato (no toque, ao tocar). */\r\n card?: boolean\r\n className?: string\r\n}\r\n\r\nconst SIZES: Record<AvatarSize, string> = {\r\n none: '',\r\n sm: 'h-6 w-6 text-[9px]',\r\n md: 'h-7 w-7 text-[10px]',\r\n lg: 'h-8 w-8 text-[11px]',\r\n}\r\n\r\n// Iniciais (sem fotografia): as cores vêm dos tokens --color-avatar-* (azul por omissão;\r\n// um portal pode sobrepô-los no seu CSS).\r\nconst INITIALS_COLORS = 'bg-gradient-to-br from-avatar-from to-avatar-to text-avatar-fg'\r\nconst INITIALS = `rounded-full font-black ${INITIALS_COLORS}`\r\n\r\n/**\r\n * A fotografia de uma pessoa (ou as iniciais), redonda. Com `card`, mostra a\r\n * fotografia grande, o email, a empresa, o departamento e a função ao passar o rato;\r\n * no toque abre e fecha ao tocar, sem passar o toque à linha por baixo.\r\n *\r\n * Para uma pessoa com o nome ao lado (ex: numa tabela), usar o `Person`.\r\n */\r\nexport default function Avatar({\r\n name,\r\n photo,\r\n photoLarge,\r\n email,\r\n company,\r\n department,\r\n jobTitle,\r\n size = 'sm',\r\n card = true,\r\n className = '',\r\n}: AvatarProps) {\r\n const ref = useRef<HTMLSpanElement>(null)\r\n const [pos, setPos] = useState<{ top: number; left: number } | null>(null)\r\n const [pinned, setPinned] = useState(false)\r\n const [failed, setFailed] = useState(false)\r\n const pointer = useRef('mouse')\r\n const large = photoLarge ?? photo\r\n\r\n // Uma falha (ex: API em baixo) não pode marcar \"sem foto\" para sempre: em listas a\r\n // mesma instância passa a ser outra pessoa.\r\n useEffect(() => setFailed(false), [photo])\r\n\r\n const open = () => {\r\n if (!card || !ref.current) return\r\n const r = ref.current.getBoundingClientRect()\r\n const W = 200\r\n const H = email || company || jobTitle || department ? 280 : 196\r\n let left = r.right + 10\r\n let top = r.top + r.height / 2 - H / 2\r\n if (left + W > window.innerWidth - 8) left = r.left - W - 10\r\n if (top + H > window.innerHeight - 8) top = window.innerHeight - H - 8\r\n if (top < 8) top = 8\r\n setPos({ top, left })\r\n }\r\n const close = () => {\r\n setPos(null)\r\n setPinned(false)\r\n }\r\n\r\n // Aberto por toque: fecha ao tocar fora, ao deslocar ou ao redimensionar.\r\n useEffect(() => {\r\n if (!pinned) return\r\n const dismiss = (e: Event) => {\r\n if (e.type === 'pointerdown' && ref.current?.contains(e.target as Node)) return\r\n close()\r\n }\r\n document.addEventListener('pointerdown', dismiss)\r\n window.addEventListener('scroll', dismiss, true)\r\n window.addEventListener('resize', dismiss)\r\n return () => {\r\n document.removeEventListener('pointerdown', dismiss)\r\n window.removeEventListener('scroll', dismiss, true)\r\n window.removeEventListener('resize', dismiss)\r\n }\r\n }, [pinned])\r\n\r\n const showPhoto = !!photo && !failed\r\n\r\n return (\r\n <>\r\n <span\r\n ref={ref}\r\n className={`inline-flex shrink-0 items-center justify-center overflow-hidden ${SIZES[size]} ${showPhoto ? 'rounded-full' : size === 'none' ? '' : INITIALS} ${card ? 'cursor-pointer' : ''} ${className}`}\r\n onPointerEnter={(e) => e.pointerType === 'mouse' && open()}\r\n onPointerLeave={(e) => e.pointerType === 'mouse' && !pinned && close()}\r\n onPointerDown={(e) => {\r\n pointer.current = e.pointerType\r\n }}\r\n onClick={(e) => {\r\n if (!card || pointer.current === 'mouse') return\r\n e.preventDefault()\r\n e.stopPropagation()\r\n if (pinned) return close()\r\n open()\r\n setPinned(true)\r\n }}\r\n >\r\n {showPhoto ? (\r\n <img src={photo!} alt={name ?? ''} className=\"h-full w-full object-cover\" onError={() => setFailed(true)} />\r\n ) : (\r\n initials(name)\r\n )}\r\n </span>\r\n {pos &&\r\n createPortal(\r\n <div\r\n style={{ position: 'fixed', top: pos.top, left: pos.left, zIndex: 9999, width: 200 }}\r\n className=\"pointer-events-none overflow-hidden rounded-2xl border border-border bg-card shadow-2xl ring-4 ring-white dark:border-slate-700 dark:bg-slate-900 dark:ring-slate-800\"\r\n >\r\n <div className=\"h-48 w-48 overflow-hidden rounded-xl\">\r\n {large && !failed ? (\r\n <img src={large} alt={name ?? ''} className=\"h-full w-full object-cover\" onError={() => setFailed(true)} />\r\n ) : (\r\n <div className={`flex h-full w-full items-center justify-center text-4xl font-black ${INITIALS_COLORS}`}>\r\n {initials(name)}\r\n </div>\r\n )}\r\n </div>\r\n <div className=\"space-y-1 px-3 py-2.5\">\r\n {name && <p className=\"text-[12px] leading-tight font-black tracking-tight break-words text-foreground\">{name}</p>}\r\n {email && <p className=\"truncate text-[10px] text-muted-foreground\">{email}</p>}\r\n {(company || department || jobTitle) && (\r\n <div className=\"mt-1 space-y-0.5 border-t border-border pt-1 dark:border-slate-700\">\r\n {company && <p className=\"truncate text-[10px] font-semibold text-foreground\">{company}</p>}\r\n {department && <p className=\"truncate text-[10px] text-muted-foreground\">{department}</p>}\r\n {jobTitle && <p className=\"truncate text-[10px] text-muted-foreground italic\">{jobTitle}</p>}\r\n </div>\r\n )}\r\n </div>\r\n </div>,\r\n document.body,\r\n )}\r\n </>\r\n )\r\n}\r\n\r\nexport { Avatar }\r\n"],"names":[],"mappings":"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"}