@jcdecor/vue 0.1.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.
Files changed (107) hide show
  1. package/README.md +68 -0
  2. package/dist/brand/Brand.d.ts +83 -0
  3. package/dist/brand/index.d.ts +2 -0
  4. package/dist/brand/paths.d.ts +43 -0
  5. package/dist/brand-CeSffe5P.js +320 -0
  6. package/dist/brand-CeSffe5P.js.map +1 -0
  7. package/dist/brand.d.ts +1 -0
  8. package/dist/brand.js +2 -0
  9. package/dist/charts/ChartCard.d.ts +32 -0
  10. package/dist/charts/charts.d.ts +124 -0
  11. package/dist/charts/echartsTheme.d.ts +19 -0
  12. package/dist/charts/index.d.ts +8 -0
  13. package/dist/charts/palette.d.ts +59 -0
  14. package/dist/charts.d.ts +1 -0
  15. package/dist/charts.js +473 -0
  16. package/dist/charts.js.map +1 -0
  17. package/dist/chat/ChatComposer.d.ts +34 -0
  18. package/dist/chat/ChatLayout.d.ts +53 -0
  19. package/dist/chat/ChatMessage.d.ts +26 -0
  20. package/dist/chat/ChatThread.d.ts +36 -0
  21. package/dist/chat/ConversationList.d.ts +22 -0
  22. package/dist/chat/TypingIndicator.d.ts +8 -0
  23. package/dist/chat/index.d.ts +9 -0
  24. package/dist/chat/node.d.ts +12 -0
  25. package/dist/chat/types.d.ts +38 -0
  26. package/dist/chat/utils.d.ts +25 -0
  27. package/dist/chat.d.ts +1 -0
  28. package/dist/chat.js +661 -0
  29. package/dist/chat.js.map +1 -0
  30. package/dist/colors-DUSEhAuo.js +32 -0
  31. package/dist/colors-DUSEhAuo.js.map +1 -0
  32. package/dist/components/ContentCard/ContentCard.d.ts +8 -0
  33. package/dist/components/ContentCard/ContentCard.types.d.ts +34 -0
  34. package/dist/components/ContentCard/ContentCard.vue.d.ts +35 -0
  35. package/dist/components/ContentCard/index.d.ts +1 -0
  36. package/dist/components/CouponCode/CouponCode.d.ts +20 -0
  37. package/dist/components/CouponCode/index.d.ts +1 -0
  38. package/dist/components/DataTable/DataTable.d.ts +95 -0
  39. package/dist/components/DataTable/index.d.ts +1 -0
  40. package/dist/components/KpiCard/KpiCard.d.ts +12 -0
  41. package/dist/components/KpiCard/KpiCard.types.d.ts +44 -0
  42. package/dist/components/KpiCard/KpiCard.vars.d.ts +3 -0
  43. package/dist/components/KpiCard/KpiCard.vue.d.ts +42 -0
  44. package/dist/components/KpiCard/KpiGroup.d.ts +10 -0
  45. package/dist/components/KpiCard/index.d.ts +1 -0
  46. package/dist/components/PageHeader/PageHeader.d.ts +29 -0
  47. package/dist/components/PageHeader/index.d.ts +1 -0
  48. package/dist/components/PriceTag/PriceTag.d.ts +21 -0
  49. package/dist/components/PriceTag/index.d.ts +1 -0
  50. package/dist/components/ProductCard/ProductCard.d.ts +12 -0
  51. package/dist/components/ProductCard/ProductCard.types.d.ts +53 -0
  52. package/dist/components/ProductCard/ProductCard.vue.d.ts +45 -0
  53. package/dist/components/ProductCard/index.d.ts +1 -0
  54. package/dist/components/PromoBanner/PromoBanner.d.ts +12 -0
  55. package/dist/components/PromoBanner/PromoBanner.types.d.ts +50 -0
  56. package/dist/components/PromoBanner/PromoBanner.vars.d.ts +2 -0
  57. package/dist/components/PromoBanner/PromoBanner.vue.d.ts +41 -0
  58. package/dist/components/PromoBanner/index.d.ts +1 -0
  59. package/dist/components/Tag/Tag.d.ts +18 -0
  60. package/dist/components/Tag/index.d.ts +1 -0
  61. package/dist/components/ThemeToggle/ThemeToggle.d.ts +10 -0
  62. package/dist/components/ThemeToggle/index.d.ts +1 -0
  63. package/dist/components/TokenSwatch/TokenSwatch.d.ts +21 -0
  64. package/dist/components/TokenSwatch/index.d.ts +1 -0
  65. package/dist/components/TopNav/TopNav.d.ts +9 -0
  66. package/dist/components/TopNav/TopNav.types.d.ts +50 -0
  67. package/dist/components/TopNav/TopNav.vue.d.ts +33 -0
  68. package/dist/components/TopNav/index.d.ts +1 -0
  69. package/dist/components/Typography/Typography.d.ts +41 -0
  70. package/dist/components/Typography/index.d.ts +1 -0
  71. package/dist/components/index.d.ts +13 -0
  72. package/dist/format-D40SMATK.js +108 -0
  73. package/dist/format-D40SMATK.js.map +1 -0
  74. package/dist/index.d.ts +15 -0
  75. package/dist/index.js +2239 -0
  76. package/dist/index.js.map +1 -0
  77. package/dist/provider/JcProvider.d.ts +285 -0
  78. package/dist/styles.css +2 -0
  79. package/dist/theme/colors.d.ts +26 -0
  80. package/dist/theme/components/buttons.d.ts +2 -0
  81. package/dist/theme/components/combobox.d.ts +2 -0
  82. package/dist/theme/components/dataDisplay.d.ts +2 -0
  83. package/dist/theme/components/feedback.d.ts +2 -0
  84. package/dist/theme/components/index.d.ts +3 -0
  85. package/dist/theme/components/inputs.d.ts +2 -0
  86. package/dist/theme/components/layout.d.ts +2 -0
  87. package/dist/theme/components/misc.d.ts +2 -0
  88. package/dist/theme/components/navigation.d.ts +2 -0
  89. package/dist/theme/components/overlays.d.ts +2 -0
  90. package/dist/theme/components/types.d.ts +11 -0
  91. package/dist/theme/components/typography.d.ts +2 -0
  92. package/dist/theme/controls.d.ts +44 -0
  93. package/dist/theme/cssVariablesResolver.d.ts +2 -0
  94. package/dist/theme/theme.d.ts +3 -0
  95. package/dist/theme/themeDefaults.d.ts +18 -0
  96. package/dist/theme/tokens.d.ts +457 -0
  97. package/dist/theme/variantColorResolver.d.ts +9 -0
  98. package/dist/themeDefaults-Ckd05FUY.js +29 -0
  99. package/dist/themeDefaults-Ckd05FUY.js.map +1 -0
  100. package/dist/tokens-CDSk_JkY.js +315 -0
  101. package/dist/tokens-CDSk_JkY.js.map +1 -0
  102. package/dist/tokens.d.ts +2 -0
  103. package/dist/tokens.js +3 -0
  104. package/dist/utils/format.d.ts +14 -0
  105. package/dist/utils/styles-api.d.ts +15 -0
  106. package/dist/utils/vue.d.ts +27 -0
  107. package/package.json +109 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chat.js","names":["Text","classes","Tooltip","classes","classes","classes","Tooltip","classes","classes","Tooltip$1","Text$1","DAY","toDate","value","startOfDay","date","dayLabel","diff","now","shortTimeLabel","buildThread","items","lastDay","messages","message","day","prev","index","next","joinsPrev","groupWindowMs","joinsNext","position","initialsName","name","formatBytes","bytes","nodeProp","hasContent","node","child","isVNode","Comment","Fragment","Chat_module_default","statusLabel","statusIcon","status","h","Loader","IconCheck","IconAlertCircle","IconChecks","timeFormat","ChatMessage","defineComponent","children","slots","props","Box","isLast","isFirst","time","createdAt","avatarSlot","own","author","Avatar","attachmentList","attachments","file","IconFile","meta","typingLabel","names","TypingIndicator","label","NEAR_BOTTOM","ChatThread","viewport","content","nearBottom","mounted","observer","userMap","computed","u","scrollToEnd","el","lastMessage","observeContent","onMounted","watch","onBeforeUnmount","viewportProps","setContent","onScrollPositionChange","y","renderBubble","emptyNode","item","bubble","ScrollArea","ChatComposer","text","setText","useUncontrolled","emit","files","ref","canSend","send","onKeydown","event","removeFile","i","addFiles","selected","Pill","resolveNode","FileButton","ActionIcon","triggerProps","IconPaperclip","Textarea","IconSend2","ConversationList","query","filtered","q","c","renderItem","unread","active","Indicator","Badge","TextInput","IconSearch","ChatHeader","back","handlers","fn","subtitle","IconArrowLeft","toCss","v","ChatLayout","sidebar","withSidebar"],"sources":["../src/chat/utils.ts","../src/chat/node.ts","../src/chat/Chat.module.css","../src/chat/ChatMessage.ts","../src/chat/TypingIndicator.ts","../src/chat/ChatThread.ts","../src/chat/ChatComposer.ts","../src/chat/ConversationList.ts","../src/chat/ChatLayout.ts"],"sourcesContent":["// @generated sincronizado de packages/ui/src/chat/utils.ts — edite lá e rode `npm run sync -w @jcdecor/vue`\nimport type { ChatMessageData } from './types';\n\nconst DAY = 24 * 60 * 60 * 1000;\n\nexport function toDate(value: Date | string | number) {\n return value instanceof Date ? value : new Date(value);\n}\n\nfunction startOfDay(date: Date) {\n return new Date(date.getFullYear(), date.getMonth(), date.getDate()).getTime();\n}\n\n/** \"Hoje\", \"Ontem\", \"segunda-feira\" (últimos 7 dias) ou \"12 de set. de 2026\". */\nexport function dayLabel(value: Date | string | number, now = new Date()) {\n const date = toDate(value);\n const diff = Math.round((startOfDay(now) - startOfDay(date)) / DAY);\n if (diff === 0) return 'Hoje';\n if (diff === 1) return 'Ontem';\n if (diff > 1 && diff < 7) return new Intl.DateTimeFormat('pt-BR', { weekday: 'long' }).format(date);\n return new Intl.DateTimeFormat('pt-BR', { day: 'numeric', month: 'short', year: 'numeric' }).format(date);\n}\n\n/** Horário curto para listas: \"14:32\" hoje, \"Ontem\", ou \"12/09\". */\nexport function shortTimeLabel(value: Date | string | number, now = new Date()) {\n const date = toDate(value);\n const diff = Math.round((startOfDay(now) - startOfDay(date)) / DAY);\n if (diff === 0) return new Intl.DateTimeFormat('pt-BR', { hour: '2-digit', minute: '2-digit' }).format(date);\n if (diff === 1) return 'Ontem';\n return new Intl.DateTimeFormat('pt-BR', { day: '2-digit', month: '2-digit' }).format(date);\n}\n\nexport type GroupPosition = 'single' | 'first' | 'middle' | 'last';\n\nexport type ThreadItem =\n | { type: 'separator'; key: string; label: string }\n | { type: 'message'; key: string; message: ChatMessageData; position: GroupPosition };\n\n/**\n * Agrupa mensagens consecutivas do mesmo autor (janela de `groupWindowMs`)\n * e insere separadores de data.\n */\nexport function buildThread(messages: ChatMessageData[], groupWindowMs = 5 * 60 * 1000, now = new Date()): ThreadItem[] {\n const items: ThreadItem[] = [];\n let lastDay: number | null = null;\n\n messages.forEach((message, index) => {\n const date = toDate(message.createdAt);\n const day = startOfDay(date);\n if (day !== lastDay) {\n items.push({ type: 'separator', key: `sep-${day}`, label: dayLabel(date, now) });\n lastDay = day;\n }\n\n const prev = messages[index - 1];\n const next = messages[index + 1];\n const joinsPrev =\n !!prev && !prev.system && !message.system && prev.authorId === message.authorId &&\n startOfDay(toDate(prev.createdAt)) === day &&\n date.getTime() - toDate(prev.createdAt).getTime() <= groupWindowMs;\n const joinsNext =\n !!next && !next.system && !message.system && next.authorId === message.authorId &&\n startOfDay(toDate(next.createdAt)) === day &&\n toDate(next.createdAt).getTime() - date.getTime() <= groupWindowMs;\n\n const position: GroupPosition = joinsPrev && joinsNext ? 'middle' : joinsPrev ? 'last' : joinsNext ? 'first' : 'single';\n items.push({ type: 'message', key: message.id, message, position });\n });\n\n return items;\n}\n\n/** Remove símbolos/separadores para as iniciais do Avatar: \"Bruno · Instalação\" → \"Bruno Instalação\" (BI). */\nexport function initialsName(name: string) {\n return name.replace(/[^\\p{L}\\s]/gu, ' ').replace(/\\s+/g, ' ').trim() || name;\n}\n\nexport function formatBytes(bytes: number) {\n if (bytes < 1024) return `${bytes} B`;\n if (bytes < 1024 * 1024) return `${(bytes / 1024).toLocaleString('pt-BR', { maximumFractionDigits: 1 })} KB`;\n return `${(bytes / 1024 / 1024).toLocaleString('pt-BR', { maximumFractionDigits: 1 })} MB`;\n}\n","import { Comment, Fragment, Text, isVNode, type PropType, type VNodeChild } from 'vue';\nimport type { MantineNode } from '@mantine-vue/core';\n\n/**\n * Prop que espelha um `React.ReactNode` do @jcdecor/ui: aceita VNode, texto ou função de render.\n * Sem validação de tipo em runtime (VNodeChild inclui string, número, array, objeto, função…).\n */\nexport const nodeProp = { type: null as unknown as PropType<MantineNode>, default: undefined };\n\n/** `true` se o conteúdo renderiza algo visível (ignora null, false, '', comentários e fragments vazios). */\nexport function hasContent(node: VNodeChild): boolean {\n if (node === null || node === undefined || node === false || node === true || node === '') return false;\n if (Array.isArray(node)) return node.some((child) => hasContent(child as VNodeChild));\n if (isVNode(node)) {\n if (node.type === Comment) return false;\n if (node.type === Text) return node.children !== '' && node.children != null;\n if (node.type === Fragment) return hasContent(node.children as VNodeChild);\n }\n return true;\n}\n","/* @generated sincronizado de packages/ui/src/chat/Chat.module.css — edite lá e rode `npm run sync -w @jcdecor/vue` */\n/* ── ChatMessage ── */\n.message {\n display: flex;\n gap: var(--sp-8);\n align-items: flex-end;\n max-width: 100%;\n}\n.message[data-own] {\n flex-direction: row-reverse;\n}\n.avatarSlot {\n width: 32px;\n flex-shrink: 0;\n}\n.bubbleColumn {\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n max-width: min(75%, 560px);\n min-width: 0;\n}\n.message[data-own] .bubbleColumn {\n align-items: flex-end;\n}\n.author {\n font-size: var(--type-disclaimer);\n font-weight: 600;\n color: var(--ds-text-3);\n margin: 0 var(--sp-12) var(--sp-4);\n}\n.bubble {\n --bubble-radius: 16px;\n --bubble-tail: 4px;\n position: relative;\n padding: var(--sp-8) var(--sp-12);\n border-radius: var(--bubble-radius);\n background: var(--ds-surface);\n color: var(--ds-text);\n border: 1px solid var(--ds-border-soft);\n font-size: var(--type-subheadline-sm);\n line-height: 1.45;\n white-space: pre-wrap;\n overflow-wrap: anywhere;\n box-shadow: var(--ds-shadow-sm);\n}\n.message[data-own] .bubble {\n /* azul fixo (#2663EB): branco 5,2:1 nos dois temas */\n background: var(--dc-horizon);\n color: #fff;\n border-color: transparent;\n}\n/* cantos agrupados (estilo mensageiro) */\n.message:not([data-own])[data-position='first'] .bubble { border-bottom-left-radius: var(--bubble-tail); }\n.message:not([data-own])[data-position='middle'] .bubble { border-top-left-radius: var(--bubble-tail); border-bottom-left-radius: var(--bubble-tail); }\n.message:not([data-own])[data-position='last'] .bubble { border-top-left-radius: var(--bubble-tail); }\n.message[data-own][data-position='first'] .bubble { border-bottom-right-radius: var(--bubble-tail); }\n.message[data-own][data-position='middle'] .bubble { border-top-right-radius: var(--bubble-tail); border-bottom-right-radius: var(--bubble-tail); }\n.message[data-own][data-position='last'] .bubble { border-top-right-radius: var(--bubble-tail); }\n.message[data-status='error'] .bubble {\n background: var(--ds-error-bg);\n color: var(--ds-error);\n border-color: var(--ds-error);\n}\n.meta {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n font-size: 11px;\n color: var(--ds-text-3);\n margin: 2px var(--sp-8) 0;\n font-variant-numeric: tabular-nums;\n}\n.meta[data-read] .status {\n color: var(--ds-primary);\n}\n.attachments {\n display: flex;\n flex-wrap: wrap;\n gap: var(--sp-4);\n margin-bottom: var(--sp-4);\n}\n.message[data-own] .attachments {\n justify-content: flex-end;\n}\n.imageAttachment {\n display: block;\n max-width: 240px;\n max-height: 180px;\n border-radius: 12px;\n object-fit: cover;\n border: 1px solid var(--ds-border-soft);\n}\n.fileAttachment {\n display: inline-flex;\n align-items: center;\n gap: var(--sp-8);\n padding: var(--sp-8) var(--sp-12);\n border-radius: 12px;\n background: var(--ds-surface-2);\n border: 1px solid var(--ds-border-soft);\n color: var(--ds-text);\n text-decoration: none;\n font-size: var(--type-disclaimer);\n max-width: 260px;\n}\n.fileName {\n flex: 1;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.fileSize {\n flex-shrink: 0;\n white-space: nowrap;\n color: var(--ds-text-3);\n}\n.fileAttachment:hover {\n border-color: var(--ds-primary);\n}\n.system {\n align-self: center;\n font-size: var(--type-disclaimer);\n color: var(--ds-text-3);\n background: var(--ds-surface-2);\n padding: 4px var(--sp-12);\n border-radius: 99px;\n text-align: center;\n}\n\n/* ── ChatThread ── */\n.thread {\n display: flex;\n flex-direction: column;\n gap: 2px;\n padding: var(--sp-16);\n}\n.thread > [data-group-start] {\n margin-top: var(--sp-12);\n}\n.separator {\n display: flex;\n align-items: center;\n gap: var(--sp-12);\n margin: var(--sp-16) 0 var(--sp-8);\n font-size: var(--type-disclaimer);\n font-weight: 600;\n color: var(--ds-text-3);\n text-transform: uppercase;\n letter-spacing: 0.05em;\n}\n.separator::before,\n.separator::after {\n content: '';\n flex: 1;\n height: 1px;\n background: var(--ds-border-soft);\n}\n\n/* ── TypingIndicator ── */\n.typing {\n display: inline-flex;\n align-items: center;\n gap: var(--sp-8);\n font-size: var(--type-disclaimer);\n color: var(--ds-text-3);\n}\n.dots {\n display: inline-flex;\n gap: 3px;\n padding: 10px 12px;\n border-radius: 16px;\n background: var(--ds-surface);\n border: 1px solid var(--ds-border-soft);\n}\n.dot {\n width: 6px;\n height: 6px;\n border-radius: 50%;\n background: var(--ds-text-3);\n animation: jc-typing 1.2s infinite ease-in-out;\n}\n.dot:nth-child(2) { animation-delay: 0.15s; }\n.dot:nth-child(3) { animation-delay: 0.3s; }\n@keyframes jc-typing {\n 0%, 60%, 100% { transform: translateY(0); opacity: 0.4; }\n 30% { transform: translateY(-4px); opacity: 1; }\n}\n@media (prefers-reduced-motion: reduce) {\n .dot { animation: none; opacity: 0.7; }\n}\n\n/* ── ChatComposer ── */\n.composer {\n display: flex;\n align-items: flex-end;\n gap: var(--sp-8);\n padding: var(--sp-12);\n border-top: 1px solid var(--ds-border-soft);\n background: var(--ds-surface);\n}\n.composerInput {\n flex: 1;\n}\n.composerFiles {\n display: flex;\n flex-wrap: wrap;\n gap: var(--sp-4);\n padding: var(--sp-8) var(--sp-12) 0;\n background: var(--ds-surface);\n border-top: 1px solid var(--ds-border-soft);\n}\n\n/* ── ConversationList ── */\n.conversations {\n display: flex;\n flex-direction: column;\n min-height: 0;\n height: 100%;\n}\n.conversationSearch {\n padding: var(--sp-12);\n border-bottom: 1px solid var(--ds-border-soft);\n}\n.conversation {\n all: unset;\n box-sizing: border-box;\n display: flex;\n gap: var(--sp-12);\n align-items: center;\n width: 100%;\n padding: var(--sp-12) var(--sp-16);\n cursor: pointer;\n border-bottom: 1px solid var(--ds-border-soft);\n transition: background 0.15s;\n}\n.conversation:hover {\n background: var(--ds-surface-2);\n}\n.conversation[data-active] {\n background: var(--ds-primary-soft);\n box-shadow: inset 3px 0 0 var(--ds-primary);\n}\n.conversation:focus-visible {\n outline: 2px solid var(--ds-primary);\n outline-offset: -2px;\n}\n.conversationBody {\n flex: 1;\n min-width: 0;\n}\n.conversationTop {\n display: flex;\n justify-content: space-between;\n gap: var(--sp-8);\n align-items: baseline;\n}\n.conversationName {\n font-weight: 600;\n font-size: var(--type-subheadline-sm);\n color: var(--ds-text);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n.conversation[data-unread] .conversationName {\n font-weight: 700;\n}\n.conversationTime {\n font-size: 11px;\n color: var(--ds-text-3);\n flex-shrink: 0;\n}\n.conversationBottom {\n display: flex;\n justify-content: space-between;\n gap: var(--sp-8);\n align-items: center;\n margin-top: 2px;\n}\n.conversationPreview {\n font-size: var(--type-disclaimer);\n color: var(--ds-text-3);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n.conversation[data-unread] .conversationPreview {\n color: var(--ds-text-2);\n font-weight: 500;\n}\n\n/* ── ChatHeader / ChatLayout ── */\n.header {\n display: flex;\n align-items: center;\n gap: var(--sp-12);\n padding: var(--sp-12) var(--sp-16);\n border-bottom: 1px solid var(--ds-border-soft);\n background: var(--ds-surface);\n min-height: 64px;\n box-sizing: border-box;\n}\n.headerBody {\n flex: 1;\n min-width: 0;\n}\n.headerTitle {\n font-weight: 600;\n color: var(--ds-text);\n}\n.headerSubtitle {\n font-size: var(--type-disclaimer);\n color: var(--ds-text-3);\n}\n.layoutContainer {\n container-type: inline-size;\n container-name: jc-chat;\n}\n.layout {\n display: grid;\n grid-template-columns: var(--chat-sidebar-width, 320px) 1fr;\n height: var(--chat-height, 600px);\n background: var(--ds-bg);\n border: 1px solid var(--ds-border-soft);\n border-radius: var(--ds-radius);\n overflow: hidden;\n}\n.layout[data-single] {\n grid-template-columns: 1fr;\n}\n.layoutSidebar {\n background: var(--ds-surface);\n border-right: 1px solid var(--ds-border-soft);\n min-height: 0;\n overflow: hidden;\n}\n.layoutMain {\n display: flex;\n flex-direction: column;\n min-height: 0;\n min-width: 0;\n}\n.layoutMessages {\n flex: 1;\n min-height: 0;\n}\n/* Abaixo de 640px de largura útil: uma coluna (lista OU conversa) */\n@container jc-chat (max-width: 640px) {\n .layout {\n grid-template-columns: 1fr;\n }\n .layout[data-mobile-view='thread'] .layoutSidebar,\n .layout[data-mobile-view='list'] .layoutMain {\n display: none;\n }\n}\n@container jc-chat (min-width: 640.02px) {\n .backButton {\n display: none;\n }\n}\n/* fora de um ChatLayout o botão voltar segue a tela */\n@media (min-width: 48em) {\n :not(.layoutContainer *) > .backButton {\n display: none;\n }\n}\n","import { defineComponent, h, type DefineSetupFnComponent, type PropType, type SlotsType, type VNodeChild } from 'vue';\nimport { Avatar, Box, Loader, type BoxProps } from '@mantine-vue/core';\nimport { Tooltip } from '../theme/themeDefaults';\nimport { IconAlertCircle, IconCheck, IconChecks, IconFile } from '@tabler/icons-vue';\nimport { formatBytes, initialsName, toDate, type GroupPosition } from './utils';\nimport type { ChatAttachment, ChatMessageStatus, ChatUser } from './types';\nimport { hasContent } from './node';\nimport classes from './Chat.module.css';\n\nexport interface ChatMessageProps extends BoxProps {\n /** Mensagem do usuário atual (alinhada à direita, bolha azul) */\n own?: boolean;\n author?: ChatUser;\n /** Exibe o nome do autor acima da bolha (útil em grupos) */\n showAuthor?: boolean;\n /** Exibe avatar ao lado da bolha (só na última mensagem do grupo) @default true */\n showAvatar?: boolean;\n createdAt?: Date | string | number;\n status?: ChatMessageStatus;\n attachments?: ChatAttachment[];\n /** Posição dentro de um grupo de mensagens consecutivas @default 'single' */\n position?: GroupPosition;\n /** Mensagem de sistema (centralizada) */\n system?: boolean;\n}\n\nexport interface ChatMessageSlots {\n /** Conteúdo da bolha (texto, links, cards…). Sem conteúdo, a bolha não é renderizada. */\n default?: () => VNodeChild;\n}\n\nconst statusLabel: Record<ChatMessageStatus, string> = {\n sending: 'Enviando…',\n sent: 'Enviada',\n delivered: 'Entregue',\n read: 'Lida',\n error: 'Falha no envio',\n};\n\nfunction statusIcon(status: ChatMessageStatus) {\n if (status === 'sending') return h(Loader as any, { size: 10, color: 'gray' });\n if (status === 'sent') return h(IconCheck, { size: 14 });\n if (status === 'error') return h(IconAlertCircle, { size: 14, color: 'var(--ds-error)' });\n return h(IconChecks, { size: 14 });\n}\n\nconst timeFormat = new Intl.DateTimeFormat('pt-BR', { hour: '2-digit', minute: '2-digit' });\n\n/** Bolha de mensagem de chat. O slot padrão é o conteúdo da bolha; atributos vão para o Box raiz. */\nexport const ChatMessage = defineComponent({\n name: 'ChatMessage',\n props: {\n own: { type: Boolean, default: false },\n author: { type: Object as PropType<ChatUser>, default: undefined },\n showAuthor: { type: Boolean, default: false },\n showAvatar: { type: Boolean, default: true },\n createdAt: { type: [Date, String, Number] as PropType<Date | string | number>, default: undefined },\n status: { type: String as PropType<ChatMessageStatus>, default: undefined },\n attachments: { type: Array as PropType<ChatAttachment[]>, default: undefined },\n position: { type: String as PropType<GroupPosition>, default: 'single' },\n system: { type: Boolean, default: false },\n },\n setup(props, { slots }) {\n return () => {\n const children = slots.default?.();\n\n if (props.system) {\n return h(Box as any, { class: classes.system, role: 'status' }, () => children);\n }\n\n const { own, author, status, position, createdAt, attachments } = props;\n const isLast = position === 'single' || position === 'last';\n const isFirst = position === 'single' || position === 'first';\n const time = createdAt ? timeFormat.format(toDate(createdAt)) : null;\n\n const avatarSlot = !own\n ? h(\n 'div',\n { class: classes.avatarSlot },\n props.showAvatar && isLast && author\n ? [\n h(Avatar as any, {\n src: author.avatar,\n name: initialsName(author.name),\n color: author.color ?? 'initials',\n size: 32,\n alt: author.name,\n }),\n ]\n : undefined,\n )\n : null;\n\n const attachmentList =\n attachments && attachments.length > 0\n ? h(\n 'div',\n { class: classes.attachments },\n attachments.map((file, index) =>\n file.type === 'image' && file.url\n ? h('a', { key: index, href: file.url, target: '_blank', rel: 'noreferrer' }, [\n h('img', { class: classes.imageAttachment, src: file.url, alt: file.name }),\n ])\n : h(\n 'a',\n {\n key: index,\n class: classes.fileAttachment,\n href: file.url,\n target: '_blank',\n rel: 'noreferrer',\n download: file.name,\n },\n [\n h(IconFile, { size: 18 }),\n h('span', { class: classes.fileName }, file.name),\n file.size !== undefined ? h('span', { class: classes.fileSize }, formatBytes(file.size)) : null,\n ],\n ),\n ),\n )\n : null;\n\n const meta =\n isLast && (time || (own && status))\n ? h('div', { class: classes.meta, 'data-read': status === 'read' || undefined }, [\n time && createdAt\n ? h('time', { datetime: toDate(createdAt).toISOString() }, time)\n : null,\n own && status\n ? h(\n Tooltip as any,\n { label: statusLabel[status], withArrow: true },\n () =>\n h(\n 'span',\n { class: classes.status, 'aria-label': statusLabel[status], style: { display: 'inline-flex' } },\n [statusIcon(status)],\n ),\n )\n : null,\n ])\n : null;\n\n return h(Box as any, { class: classes.message, mod: { own, position, status } }, () => [\n avatarSlot,\n h('div', { class: classes.bubbleColumn }, [\n props.showAuthor && isFirst && author && !own ? h('div', { class: classes.author }, author.name) : null,\n attachmentList,\n hasContent(children) ? h('div', { class: classes.bubble }, children) : null,\n meta,\n ]),\n ]);\n };\n },\n}) as unknown as DefineSetupFnComponent<ChatMessageProps, {}, SlotsType<ChatMessageSlots>>;\n","import { defineComponent, h, type DefineSetupFnComponent, type PropType } from 'vue';\nimport { Box, type BoxProps } from '@mantine-vue/core';\nimport classes from './Chat.module.css';\n\nexport interface TypingIndicatorProps extends BoxProps {\n /** Nomes de quem está digitando. Vazio = só os pontinhos. */\n names?: string[];\n}\n\nfunction typingLabel(names: string[]) {\n if (names.length === 0) return '';\n if (names.length === 1) return `${names[0]} está digitando…`;\n if (names.length === 2) return `${names[0]} e ${names[1]} estão digitando…`;\n return `${names[0]} e mais ${names.length - 1} estão digitando…`;\n}\n\n/** Indicador animado de \"digitando…\". Atributos e style props (`mt`, `ml`…) vão para o Box raiz. */\nexport const TypingIndicator = defineComponent({\n name: 'TypingIndicator',\n props: {\n names: { type: Array as PropType<string[]>, default: () => [] },\n },\n setup(props) {\n return () => {\n const label = typingLabel(props.names);\n return h(\n Box as any,\n { class: classes.typing, role: 'status', 'aria-live': 'polite', 'aria-label': label || 'Digitando' },\n () => [\n h('span', { class: classes.dots, 'aria-hidden': 'true' }, [\n h('span', { class: classes.dot }),\n h('span', { class: classes.dot }),\n h('span', { class: classes.dot }),\n ]),\n label ? h('span', label) : null,\n ],\n );\n };\n },\n}) as unknown as DefineSetupFnComponent<TypingIndicatorProps>;\n","import {\n computed,\n defineComponent,\n h,\n onBeforeUnmount,\n onMounted,\n watch,\n type DefineSetupFnComponent,\n type PropType,\n type SlotsType,\n type VNodeChild,\n} from 'vue';\nimport { Box, ScrollArea, type MantineNode, type ScrollAreaProps } from '@mantine-vue/core';\nimport { ChatMessage } from './ChatMessage';\nimport { TypingIndicator } from './TypingIndicator';\nimport { buildThread } from './utils';\nimport type { ChatMessageData, ChatUser } from './types';\nimport { nodeProp } from './node';\nimport classes from './Chat.module.css';\n\nexport interface ChatThreadProps extends ScrollAreaProps {\n messages: ChatMessageData[];\n /** Id do usuário atual — suas mensagens ficam à direita */\n currentUserId: string;\n users?: ChatUser[] | Record<string, ChatUser>;\n /** Nomes de quem está digitando agora */\n typing?: string[];\n /** Mostra nome do autor no início de cada grupo (conversas em grupo) */\n showAuthors?: boolean;\n /** Rola para a última mensagem quando chegam novas (se o usuário estiver perto do fim) @default true */\n autoScroll?: boolean;\n /** Janela (ms) para agrupar mensagens consecutivas do mesmo autor @default 300000 */\n groupWindow?: number;\n /** Conteúdo exibido quando não há mensagens. O slot `#empty` tem prioridade. */\n empty?: MantineNode;\n /** Renderização customizada do conteúdo da bolha. O slot `#content=\"{ message }\"` tem prioridade. */\n renderContent?: (message: ChatMessageData) => VNodeChild;\n /** Altura da área rolável @default '100%' */\n h?: ScrollAreaProps['h'];\n}\n\nexport interface ChatThreadSlots {\n /** Conteúdo exibido quando não há mensagens */\n empty?: () => VNodeChild;\n /** Conteúdo customizado da bolha de cada mensagem */\n content?: (props: { message: ChatMessageData }) => VNodeChild;\n}\n\n/** Distância (px) do fim abaixo da qual o usuário é considerado \"no fim\" da conversa. */\nconst NEAR_BOTTOM = 80;\n\n/**\n * Lista rolável de mensagens com separadores de data, agrupamento e auto-scroll.\n * Atributos e props do ScrollArea (`type`, `scrollbarSize`…) vão para o ScrollArea raiz.\n */\nexport const ChatThread = defineComponent({\n name: 'ChatThread',\n props: {\n messages: { type: Array as PropType<ChatMessageData[]>, required: true },\n currentUserId: { type: String, required: true },\n users: { type: [Array, Object] as PropType<ChatUser[] | Record<string, ChatUser>>, default: () => [] },\n typing: { type: Array as PropType<string[]>, default: undefined },\n showAuthors: { type: Boolean, default: false },\n autoScroll: { type: Boolean, default: true },\n groupWindow: { type: Number, default: undefined },\n empty: nodeProp,\n renderContent: { type: Function as PropType<(message: ChatMessageData) => VNodeChild>, default: undefined },\n h: { type: [String, Number] as PropType<ScrollAreaProps['h']>, default: '100%' },\n },\n setup(props, { slots }) {\n let viewport: HTMLDivElement | null = null;\n let content: HTMLElement | null = null;\n let nearBottom = true;\n let mounted = false;\n let observer: ResizeObserver | null = null;\n\n const userMap = computed<Record<string, ChatUser>>(() =>\n Array.isArray(props.users) ? Object.fromEntries(props.users.map((u) => [u.id, u])) : props.users,\n );\n const items = computed(() => buildThread(props.messages, props.groupWindow));\n\n function scrollToEnd() {\n const el = viewport;\n if (!el || !props.autoScroll) return;\n const lastMessage = props.messages[props.messages.length - 1];\n if (nearBottom || lastMessage?.authorId === props.currentUserId) {\n // Primeira renderização: pula direto para o fim; depois, rolagem suave.\n el.scrollTo({ top: el.scrollHeight, behavior: mounted ? 'smooth' : 'auto' });\n }\n mounted = true;\n }\n\n // Conteúdo que cresce depois (imagens, fontes) mantém o fim visível se o usuário já estava lá.\n function observeContent() {\n observer?.disconnect();\n observer = null;\n const el = viewport;\n if (!el || !content || !props.autoScroll || typeof ResizeObserver === 'undefined') return;\n observer = new ResizeObserver(() => {\n if (nearBottom) el.scrollTo({ top: el.scrollHeight });\n });\n observer.observe(content);\n }\n\n onMounted(() => {\n scrollToEnd();\n observeContent();\n });\n\n watch(\n () => [\n props.messages.length,\n props.messages[props.messages.length - 1]?.id,\n props.typing?.length,\n props.autoScroll,\n props.currentUserId,\n ],\n scrollToEnd,\n { flush: 'post' },\n );\n watch(() => props.autoScroll, observeContent, { flush: 'post' });\n\n onBeforeUnmount(() => observer?.disconnect());\n\n // O ScrollArea do Mantine Vue não tem `viewportRef`: o elemento chega via `viewportProps.rootRef`.\n const viewportProps = {\n rootRef: (node: Element | null) => {\n viewport = node as HTMLDivElement | null;\n },\n };\n const setContent = (node: Element | null) => {\n content = node as HTMLElement | null;\n };\n const onScrollPositionChange = ({ y }: { x: number; y: number }) => {\n const el = viewport;\n if (el) nearBottom = el.scrollHeight - el.clientHeight - y < NEAR_BOTTOM;\n };\n\n return () => {\n const renderBubble = (message: ChatMessageData): VNodeChild =>\n slots.content\n ? slots.content({ message })\n : props.renderContent\n ? props.renderContent(message)\n : message.text;\n\n const emptyNode =\n props.messages.length === 0\n ? slots.empty\n ? slots.empty()\n : typeof props.empty === 'function'\n ? props.empty()\n : props.empty\n : null;\n\n const children = items.value.map((item) => {\n if (item.type === 'separator') {\n return h('div', { key: item.key, class: classes.separator, role: 'separator' }, item.label);\n }\n const { message, position } = item;\n const own = message.authorId === props.currentUserId;\n const bubble = renderBubble(message);\n return h(\n ChatMessage as any,\n {\n key: item.key,\n own,\n system: message.system,\n author: userMap.value[message.authorId],\n showAuthor: props.showAuthors,\n createdAt: message.createdAt,\n status: own ? message.status : undefined,\n attachments: message.attachments,\n position,\n 'data-group-start': position === 'single' || position === 'first' ? true : undefined,\n },\n { default: () => bubble },\n );\n });\n\n return h(\n ScrollArea as any,\n { h: props.h, viewportProps, onScrollPositionChange },\n () =>\n h(\n Box as any,\n {\n rootRef: setContent,\n class: classes.thread,\n role: 'log',\n 'aria-live': 'polite',\n 'aria-relevant': 'additions',\n },\n () => [\n emptyNode,\n ...children,\n props.typing && props.typing.length > 0\n ? h(TypingIndicator as any, { names: props.typing, mt: 'sm', ml: 40 })\n : null,\n ],\n ),\n );\n };\n },\n}) as unknown as DefineSetupFnComponent<ChatThreadProps, {}, SlotsType<ChatThreadSlots>>;\n","import { computed, defineComponent, h, ref, type DefineSetupFnComponent, type SlotsType, type VNodeChild } from 'vue';\nimport { ActionIcon, Box, FileButton, Pill, Textarea, resolveNode, type BoxProps, type MantineNode } from '@mantine-vue/core';\nimport { Tooltip } from '../theme/themeDefaults';\nimport { useUncontrolled } from '@mantine-vue/hooks';\nimport { IconPaperclip, IconSend2 } from '@tabler/icons-vue';\nimport { nodeProp } from './node';\nimport classes from './Chat.module.css';\n\nexport interface ChatComposerSendPayload {\n text: string;\n files: File[];\n}\n\nexport interface ChatComposerProps extends BoxProps {\n /** Texto controlado (`v-model`). Sem `v-model`, o campo é não controlado. */\n modelValue?: string;\n /** Texto inicial no modo não controlado */\n defaultValue?: string;\n placeholder?: string;\n disabled?: boolean;\n /** Habilita anexos; `accept` segue o atributo HTML (ex.: \"image/*,.pdf\") */\n allowAttachments?: boolean;\n accept?: string;\n /** Máximo de linhas antes de rolar @default 5 */\n maxRows?: number;\n /** Elementos extras à esquerda (ex.: emoji picker, respostas rápidas). O slot `#leftSection` tem prioridade. */\n leftSection?: MantineNode;\n sendLabel?: string;\n}\n\nexport type ChatComposerEmits = {\n /** Ao enviar (Enter ou botão). O campo é limpo em seguida. */\n send: (payload: ChatComposerSendPayload) => void;\n /** `v-model` do texto */\n 'update:modelValue': (value: string) => void;\n}\n\nexport interface ChatComposerSlots {\n /** Elementos extras à esquerda (ex.: emoji picker, respostas rápidas) */\n leftSection?: () => VNodeChild;\n}\n\n/** Campo de mensagem: Enter envia, Shift+Enter quebra linha, anexos opcionais. */\nexport const ChatComposer = defineComponent({\n name: 'ChatComposer',\n props: {\n modelValue: { type: String, default: undefined },\n defaultValue: { type: String, default: undefined },\n placeholder: { type: String, default: 'Digite uma mensagem…' },\n disabled: { type: Boolean, default: false },\n allowAttachments: { type: Boolean, default: false },\n accept: { type: String, default: undefined },\n maxRows: { type: Number, default: 5 },\n leftSection: nodeProp,\n sendLabel: { type: String, default: 'Enviar' },\n },\n emits: {\n send: (_payload: ChatComposerSendPayload) => true,\n 'update:modelValue': (_value: string) => true,\n },\n setup(props, { emit, slots }) {\n const [text, setText] = useUncontrolled<string>({\n value: () => props.modelValue,\n defaultValue: props.defaultValue,\n finalValue: '',\n onChange: (value) => emit('update:modelValue', value),\n });\n const files = ref<File[]>([]);\n const canSend = computed(() => !props.disabled && (text.value.trim().length > 0 || files.value.length > 0));\n\n const send = () => {\n if (!canSend.value) return;\n emit('send', { text: text.value.trim(), files: files.value });\n setText('');\n files.value = [];\n };\n\n const onKeydown = (event: KeyboardEvent) => {\n if (event.key === 'Enter' && !event.shiftKey && !event.isComposing) {\n event.preventDefault();\n send();\n }\n };\n\n const removeFile = (index: number) => {\n files.value = files.value.filter((_, i) => i !== index);\n };\n\n const addFiles = (selected: File | File[] | null) => {\n files.value = [...files.value, ...(Array.isArray(selected) ? selected : selected ? [selected] : [])];\n };\n\n return () =>\n h(Box as any, null, () => [\n files.value.length > 0\n ? h(\n 'div',\n { class: classes.composerFiles },\n files.value.map((file, index) =>\n h(\n Pill as any,\n { key: `${file.name}-${index}`, withRemoveButton: true, onRemove: () => removeFile(index) },\n () => file.name,\n ),\n ),\n )\n : null,\n h('div', { class: classes.composer }, [\n resolveNode(props.leftSection, slots.leftSection),\n props.allowAttachments\n ? h(\n FileButton as any,\n { multiple: true, accept: props.accept, disabled: props.disabled, onChange: addFiles },\n {\n default: (triggerProps: Record<string, unknown>) =>\n h(Tooltip as any, { label: 'Anexar arquivo' }, () =>\n h(\n ActionIcon as any,\n { ...triggerProps, size: 'lg', variant: 'subtle', 'aria-label': 'Anexar arquivo' },\n () => h(IconPaperclip, { size: 20 }),\n ),\n ),\n },\n )\n : null,\n h(Textarea as any, {\n class: classes.composerInput,\n modelValue: text.value,\n 'onUpdate:modelValue': (value: string) => setText(value),\n onKeydown,\n placeholder: props.placeholder,\n disabled: props.disabled,\n autosize: true,\n minRows: 1,\n maxRows: props.maxRows,\n radius: 'lg',\n 'aria-label': props.placeholder,\n }),\n h(\n ActionIcon as any,\n { size: 44, radius: 'xl', variant: 'filled', onClick: send, disabled: !canSend.value, 'aria-label': props.sendLabel },\n () => h(IconSend2, { size: 20 }),\n ),\n ]),\n ]);\n },\n}) as unknown as DefineSetupFnComponent<ChatComposerProps, ChatComposerEmits, SlotsType<ChatComposerSlots>>;\n","import { computed, defineComponent, h, ref, type DefineSetupFnComponent, type PropType, type SlotsType, type VNodeChild } from 'vue';\nimport { Avatar, Badge, Box, Indicator, ScrollArea, TextInput, resolveNode, type BoxProps, type MantineNode } from '@mantine-vue/core';\nimport { IconSearch } from '@tabler/icons-vue';\nimport { initialsName, shortTimeLabel } from './utils';\nimport type { Conversation } from './types';\nimport { nodeProp } from './node';\nimport classes from './Chat.module.css';\n\nexport interface ConversationListProps extends BoxProps {\n conversations: Conversation[];\n activeId?: string | null;\n /** Exibe campo de busca @default true */\n searchable?: boolean;\n searchPlaceholder?: string;\n /** Conteúdo quando a lista (ou a busca) fica vazia. O slot `#empty` tem prioridade. */\n empty?: MantineNode;\n}\n\nexport type ConversationListEmits = {\n /** Clique em uma conversa */\n select: (conversation: Conversation) => void;\n}\n\nexport interface ConversationListSlots {\n /** Conteúdo quando a lista (ou a busca) fica vazia */\n empty?: () => VNodeChild;\n}\n\n/** Lista de conversas com busca, não lidas, presença e última mensagem. */\nexport const ConversationList = defineComponent({\n name: 'ConversationList',\n props: {\n conversations: { type: Array as PropType<Conversation[]>, required: true },\n activeId: { type: String as PropType<string | null>, default: undefined },\n searchable: { type: Boolean, default: true },\n searchPlaceholder: { type: String, default: 'Buscar conversas' },\n empty: nodeProp,\n },\n emits: {\n select: (_conversation: Conversation) => true,\n },\n setup(props, { emit, slots }) {\n const query = ref('');\n const filtered = computed(() => {\n const q = query.value.trim().toLocaleLowerCase('pt-BR');\n if (!q) return props.conversations;\n return props.conversations.filter(\n (c) => c.name.toLocaleLowerCase('pt-BR').includes(q) || c.lastMessage?.toLocaleLowerCase('pt-BR').includes(q),\n );\n });\n\n const renderItem = (c: Conversation) => {\n const unread = c.unread ?? 0;\n const active = c.id === props.activeId;\n return h(\n 'button',\n {\n key: c.id,\n type: 'button',\n role: 'listitem',\n class: classes.conversation,\n 'data-active': active || undefined,\n 'data-unread': unread > 0 || undefined,\n 'aria-current': active ? 'true' : undefined,\n onClick: () => emit('select', c),\n },\n [\n h(\n Indicator as any,\n { color: 'evergreen', position: 'bottom-end', offset: 5, size: 10, withBorder: true, disabled: !c.online },\n () => h(Avatar as any, { src: c.avatar, name: initialsName(c.name), color: c.color ?? 'initials', size: 40 }),\n ),\n h('div', { class: classes.conversationBody }, [\n h('div', { class: classes.conversationTop }, [\n h('span', { class: classes.conversationName }, c.name),\n c.lastMessageAt !== undefined\n ? h('span', { class: classes.conversationTime }, shortTimeLabel(c.lastMessageAt))\n : null,\n ]),\n h('div', { class: classes.conversationBottom }, [\n h('span', { class: classes.conversationPreview }, c.lastMessage),\n unread > 0\n ? h(\n Badge as any,\n { size: 'sm', variant: 'filled', circle: unread < 10, 'aria-label': `${c.unread} não lidas` },\n () => (unread > 99 ? '99+' : String(unread)),\n )\n : null,\n ]),\n c.tag ? h(Badge as any, { size: 'xs', color: 'obsidian', mt: 6 }, () => c.tag) : null,\n ]),\n ],\n );\n };\n\n return () =>\n h(Box as any, { class: classes.conversations }, () => [\n props.searchable\n ? h('div', { class: classes.conversationSearch }, [\n h(\n TextInput as any,\n {\n size: 'sm',\n placeholder: props.searchPlaceholder,\n modelValue: query.value,\n 'onUpdate:modelValue': (value: string) => (query.value = value),\n 'aria-label': props.searchPlaceholder,\n },\n { leftSection: () => h(IconSearch, { size: 16 }) },\n ),\n ])\n : null,\n h(ScrollArea as any, { style: { flex: 1 }, type: 'auto' }, () =>\n h('div', { role: 'list' }, [\n filtered.value.length === 0\n ? h(Box as any, { p: 'lg', ta: 'center', c: 'var(--ds-text-3)', fz: 'sm' }, () =>\n slots.empty || props.empty != null ? resolveNode(props.empty, slots.empty) : 'Nenhuma conversa encontrada',\n )\n : null,\n ...filtered.value.map(renderItem),\n ]),\n ),\n ]);\n },\n}) as unknown as DefineSetupFnComponent<ConversationListProps, ConversationListEmits, SlotsType<ConversationListSlots>>;\n","import { defineComponent, h, type DefineSetupFnComponent, type PropType, type SlotsType, type VNodeChild } from 'vue';\nimport { ActionIcon, Avatar, Box, Indicator, resolveNode, type BoxProps, type MantineNode } from '@mantine-vue/core';\nimport { IconArrowLeft } from '@tabler/icons-vue';\nimport { initialsName } from './utils';\nimport { hasContent, nodeProp } from './node';\nimport classes from './Chat.module.css';\n\nexport interface ChatHeaderProps extends BoxProps {\n /** Nome da conversa. O slot `#title` tem prioridade. */\n title?: MantineNode;\n /** Status/descrição abaixo do título. O slot `#subtitle` tem prioridade. */\n subtitle?: MantineNode;\n avatar?: string;\n /** Nome para iniciais do avatar */\n avatarName?: string;\n online?: boolean;\n /** Ações à direita (botões, menu). O slot `#actions` tem prioridade. */\n actions?: MantineNode;\n}\n\nexport type ChatHeaderEmits = {\n /** Clique no botão voltar. O botão (mobile) só aparece quando há um listener `@back`. */\n back: () => void;\n}\n\nexport interface ChatHeaderSlots {\n title?: () => VNodeChild;\n subtitle?: () => VNodeChild;\n actions?: () => VNodeChild;\n}\n\n/**\n * Cabeçalho da conversa: avatar, nome, status e ações.\n *\n * O botão voltar aparece só com `@back` (equivalente à presença de `onBack` no @jcdecor/ui):\n * `onBack` é declarado como prop — padrão do Vue para detectar se o pai escutou o evento.\n */\nexport const ChatHeader = defineComponent({\n name: 'ChatHeader',\n props: {\n title: nodeProp,\n subtitle: nodeProp,\n avatar: { type: String, default: undefined },\n avatarName: { type: String, default: undefined },\n online: { type: Boolean, default: false },\n actions: nodeProp,\n onBack: { type: [Function, Array] as PropType<(() => void) | Array<() => void>>, default: undefined },\n },\n setup(props, { slots }) {\n const back = () => {\n const handlers = props.onBack;\n if (Array.isArray(handlers)) handlers.forEach((fn) => fn());\n else handlers?.();\n };\n\n return () => {\n const subtitle = resolveNode(props.subtitle, slots.subtitle);\n return h(Box as any, { class: classes.header }, () => [\n props.onBack\n ? h(ActionIcon as any, { class: classes.backButton, variant: 'subtle', onClick: back, 'aria-label': 'Voltar' }, () =>\n h(IconArrowLeft, { size: 20 }),\n )\n : null,\n props.avatar || props.avatarName\n ? h(\n Indicator as any,\n { color: 'evergreen', position: 'bottom-end', offset: 5, size: 10, withBorder: true, disabled: !props.online },\n () =>\n h(Avatar as any, {\n src: props.avatar,\n name: props.avatarName ? initialsName(props.avatarName) : undefined,\n color: 'initials',\n size: 40,\n }),\n )\n : null,\n h('div', { class: classes.headerBody }, [\n h('div', { class: classes.headerTitle }, [resolveNode(props.title, slots.title)]),\n hasContent(subtitle) ? h('div', { class: classes.headerSubtitle }, [subtitle]) : null,\n ]),\n resolveNode(props.actions, slots.actions),\n ]);\n };\n },\n}) as unknown as DefineSetupFnComponent<ChatHeaderProps, ChatHeaderEmits, SlotsType<ChatHeaderSlots>>;\n\nexport interface ChatLayoutProps extends BoxProps {\n /** Lista de conversas (coluna esquerda) — omita para um chat único. O slot `#sidebar` tem prioridade. */\n sidebar?: MantineNode;\n /** Normalmente um <ChatHeader />. O slot `#header` tem prioridade. */\n header?: MantineNode;\n /** Normalmente um <ChatComposer />. O slot `#composer` tem prioridade. */\n composer?: MantineNode;\n /** Altura total @default 600 */\n height?: number | string;\n /** @default 320 */\n sidebarWidth?: number | string;\n /** Em telas pequenas mostra só a lista ou só a conversa @default 'thread' */\n mobileView?: 'list' | 'thread';\n}\n\nexport interface ChatLayoutSlots {\n /** Normalmente um <ChatThread /> */\n default?: () => VNodeChild;\n sidebar?: () => VNodeChild;\n header?: () => VNodeChild;\n composer?: () => VNodeChild;\n}\n\nconst toCss = (v: number | string) => (typeof v === 'number' ? `${v}px` : v);\n\n/** Layout de chat: conversas + cabeçalho + mensagens + composer (responsivo). */\nexport const ChatLayout = defineComponent({\n name: 'ChatLayout',\n props: {\n sidebar: nodeProp,\n header: nodeProp,\n composer: nodeProp,\n height: { type: [Number, String], default: 600 },\n sidebarWidth: { type: [Number, String], default: 320 },\n mobileView: { type: String as PropType<'list' | 'thread'>, default: 'thread' },\n },\n setup(props, { slots }) {\n return () => {\n const sidebar = resolveNode(props.sidebar, slots.sidebar);\n const withSidebar = hasContent(sidebar);\n // O wrapper é o contêiner das container queries: o layout se adapta ao espaço disponível, não à tela.\n // Estilos do usuário (`style` em atributos) são mesclados depois destas variáveis.\n return h(\n Box as any,\n {\n class: classes.layoutContainer,\n style: { '--chat-height': toCss(props.height), '--chat-sidebar-width': toCss(props.sidebarWidth) },\n },\n () =>\n h(\n 'div',\n {\n class: classes.layout,\n 'data-mobile-view': withSidebar ? props.mobileView : undefined,\n 'data-single': withSidebar ? undefined : true,\n },\n [\n withSidebar ? h('aside', { class: classes.layoutSidebar }, [sidebar]) : null,\n h('section', { class: classes.layoutMain }, [\n resolveNode(props.header, slots.header),\n h('div', { class: classes.layoutMessages }, slots.default?.()),\n resolveNode(props.composer, slots.composer),\n ]),\n ],\n ),\n );\n };\n },\n}) as unknown as DefineSetupFnComponent<ChatLayoutProps, {}, SlotsType<ChatLayoutSlots>>;\n"],"mappings":"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"}
@@ -0,0 +1,32 @@
1
+ import { i as e, l as t } from "./tokens-CDSk_JkY.js";
2
+ //#region src/theme/colors.ts
3
+ var n = [
4
+ 50,
5
+ 100,
6
+ 200,
7
+ 300,
8
+ 400,
9
+ 500,
10
+ 600,
11
+ 700,
12
+ 800,
13
+ 900
14
+ ], r = (e) => n.map((t) => e[t]), i = r(t.horizon), a = r(t.obsidian), o = r(t.electric), s = r(t.evergreen), c = r(t.danger), l = {
15
+ horizon: i,
16
+ obsidian: a,
17
+ electric: o,
18
+ evergreen: s,
19
+ danger: c,
20
+ gray: r(t.gray),
21
+ dark: [...e],
22
+ blue: i,
23
+ indigo: a,
24
+ green: s,
25
+ teal: s,
26
+ yellow: o,
27
+ red: c
28
+ };
29
+ //#endregion
30
+ export { l as t };
31
+
32
+ //# sourceMappingURL=colors-DUSEhAuo.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"colors-DUSEhAuo.js","names":["darkNeutrals","ramps","STEPS","tuple","ramp","s","horizon","obsidian","electric","evergreen","danger","jcColors"],"sources":["../src/theme/colors.ts"],"sourcesContent":["import type { MantineColorsTuple } from '@mantine-vue/core';\nimport { darkNeutrals, ramps, type RampStep } from './tokens';\n\n/**\n * Tuplas de 10 tons do Mantine geradas das rampas OKLCH em tokens.ts.\n * Índice → tom: 0=50 · 1=100 · … · 6=600 · … · 9=900.\n * `primaryShade` é 6 no claro e 4 no escuro, então `color=\"evergreen\"` etc.\n * preenche com o tom 600 (claro) / 400 (escuro) de qualquer cor.\n */\nconst STEPS: RampStep[] = [50, 100, 200, 300, 400, 500, 600, 700, 800, 900];\nconst tuple = (ramp: Record<RampStep, string>) => STEPS.map((s) => ramp[s]) as unknown as MantineColorsTuple;\n\nexport const horizon = tuple(ramps.horizon);\nexport const obsidian = tuple(ramps.obsidian);\nexport const electric = tuple(ramps.electric);\nexport const evergreen = tuple(ramps.evergreen);\nexport const danger = tuple(ramps.danger);\n/** Substitui o `gray` do Mantine: neutro frio da marca. */\nexport const gray = tuple(ramps.gray);\n/** Substitui o `dark` do Mantine com os neutros do tema escuro (0 = texto · 7 = fundo). */\nexport const dark = [...darkNeutrals] as unknown as MantineColorsTuple;\n\nexport const jcColors = {\n horizon,\n obsidian,\n electric,\n evergreen,\n danger,\n gray,\n dark,\n // Aliases: `color=\"blue\"` etc. continuam na paleta da marca.\n blue: horizon,\n indigo: obsidian,\n green: evergreen,\n teal: evergreen,\n yellow: electric,\n red: danger,\n} satisfies Record<string, MantineColorsTuple>;\n\nexport type JcColor = 'horizon' | 'obsidian' | 'electric' | 'evergreen' | 'danger' | 'gray';\n"],"mappings":";;AASA,IAAME,IAAoB;CAAC;CAAI;CAAK;CAAK;CAAK;CAAK;CAAK;CAAK;CAAK;CAAK;AAAG,GACpEC,KAAS,MAAmCD,EAAM,KAAK,MAAME,EAAKC,EAAE,GAE7DC,IAAUH,EAAMF,EAAM,OAAO,GAC7BM,IAAWJ,EAAMF,EAAM,QAAQ,GAC/BO,IAAWL,EAAMF,EAAM,QAAQ,GAC/BQ,IAAYN,EAAMF,EAAM,SAAS,GACjCS,IAASP,EAAMF,EAAM,MAAM,GAM3BU,IAAW;CACtB;CACA;CACA;CACA;CACA;CACA,MAVkBR,EAAMF,EAAM,IAU9B;CACA,OATmB,GAAGD,CAStB;CAEA,MAAMM;CACN,QAAQC;CACR,OAAOE;CACP,MAAMA;CACN,QAAQD;CACR,KAAKE;AACP"}
@@ -0,0 +1,8 @@
1
+ /** Card de conteúdo: superfície branca sobre LightGray, borda suave e sombra pequena (ds-card). */
2
+ export declare const ContentCard: import("@mantine-vue/core").MantineComponent<{
3
+ props: import("./ContentCard.types").ContentCardProps;
4
+ slots: import("./ContentCard.types").ContentCardSlots;
5
+ ref: HTMLDivElement;
6
+ stylesNames: import("./ContentCard.types").ContentCardStylesNames;
7
+ }>;
8
+ export type { ContentCardFactory, ContentCardOwnProps, ContentCardProps, ContentCardSlots, ContentCardStylesNames, } from './ContentCard.types';
@@ -0,0 +1,34 @@
1
+ import type { VNodeChild } from 'vue';
2
+ import type { CardProps, Factory, MantineNode } from '@mantine-vue/core';
3
+ import type { JcStylesApiProps } from '../../utils/styles-api';
4
+ export type ContentCardStylesNames = 'root' | 'image' | 'kicker' | 'title' | 'body' | 'actions';
5
+ /** Props declaradas pelo próprio ContentCard. As demais (props do Card/Box) vão para o Card raiz. */
6
+ export interface ContentCardOwnProps extends JcStylesApiProps<ContentCardFactory> {
7
+ /** Sobretítulo em caixa-alta. Também aceita o slot `kicker` (o slot tem prioridade). */
8
+ kicker?: MantineNode;
9
+ /** Também aceita o slot `title` (o slot tem prioridade). */
10
+ title?: MantineNode;
11
+ /** Imagem de capa (URL) ou nó customizado. Também aceita o slot `image` (o slot tem prioridade). */
12
+ image?: string | MantineNode;
13
+ imageAlt?: string;
14
+ /** @default 180 */
15
+ imageHeight?: number;
16
+ /** Botões/links no rodapé do card. Também aceita o slot `actions` (o slot tem prioridade). */
17
+ actions?: MantineNode;
18
+ }
19
+ export interface ContentCardProps extends Omit<CardProps, keyof ContentCardOwnProps>, ContentCardOwnProps {
20
+ }
21
+ export interface ContentCardSlots {
22
+ /** Corpo do card */
23
+ default?: () => VNodeChild;
24
+ kicker?: () => VNodeChild;
25
+ title?: () => VNodeChild;
26
+ image?: () => VNodeChild;
27
+ actions?: () => VNodeChild;
28
+ }
29
+ export type ContentCardFactory = Factory<{
30
+ props: ContentCardProps;
31
+ slots: ContentCardSlots;
32
+ ref: HTMLDivElement;
33
+ stylesNames: ContentCardStylesNames;
34
+ }>;
@@ -0,0 +1,35 @@
1
+ import type { ContentCardOwnProps, ContentCardSlots } from './ContentCard.types';
2
+ type __VLS_Slots = ContentCardSlots;
3
+ declare const __VLS_base: import("vue").DefineComponent<ContentCardOwnProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<ContentCardOwnProps> & Readonly<{}>, {
4
+ title: string | number | boolean | import("vue").VNode<import("vue").RendererNode, import("vue").RendererElement, {
5
+ [key: string]: any;
6
+ }> | import("vue").VNodeArrayChildren | (() => import("vue").VNodeChild) | null;
7
+ vars: import("@mantine-vue/core").FactoryPartialVarsResolver<{
8
+ props: import("./ContentCard.types").ContentCardProps;
9
+ slots: ContentCardSlots;
10
+ ref: HTMLDivElement;
11
+ stylesNames: import("./ContentCard.types").ContentCardStylesNames;
12
+ } & import("@mantine-vue/core").FactoryPayload>;
13
+ image: string | number | boolean | import("vue").VNode<import("vue").RendererNode, import("vue").RendererElement, {
14
+ [key: string]: any;
15
+ }> | import("vue").VNodeArrayChildren | (() => import("vue").VNodeChild) | null;
16
+ classNames: Partial<Record<"title" | "body" | "image" | "kicker" | "actions" | "root", string>> | ((theme: import("@mantine-vue/core").MantineTheme, props: import("./ContentCard.types").ContentCardProps & Record<string, any>, ctx: Record<string, any>) => Partial<Record<"title" | "body" | "image" | "kicker" | "actions" | "root", string>>);
17
+ styles: Partial<Record<"title" | "body" | "image" | "kicker" | "actions" | "root", import("vue").CSSProperties>> | ((theme: import("@mantine-vue/core").MantineTheme, props: import("./ContentCard.types").ContentCardProps & Record<string, any>, ctx: Record<string, any>) => Partial<Record<"title" | "body" | "image" | "kicker" | "actions" | "root", import("vue").CSSProperties>>);
18
+ unstyled: boolean;
19
+ kicker: string | number | boolean | import("vue").VNode<import("vue").RendererNode, import("vue").RendererElement, {
20
+ [key: string]: any;
21
+ }> | import("vue").VNodeArrayChildren | (() => import("vue").VNodeChild) | null;
22
+ actions: string | number | boolean | import("vue").VNode<import("vue").RendererNode, import("vue").RendererElement, {
23
+ [key: string]: any;
24
+ }> | import("vue").VNodeArrayChildren | (() => import("vue").VNodeChild) | null;
25
+ imageAlt: string;
26
+ imageHeight: number;
27
+ }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
28
+ declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
29
+ declare const _default: typeof __VLS_export;
30
+ export default _default;
31
+ type __VLS_WithSlots<T, S> = T & {
32
+ new (): {
33
+ $slots: S;
34
+ };
35
+ };
@@ -0,0 +1 @@
1
+ export * from './ContentCard';
@@ -0,0 +1,20 @@
1
+ import { type DefineSetupFnComponent, type SlotsType, type VNodeChild } from 'vue';
2
+ import { type BoxProps, type MantineNode } from '@mantine-vue/core';
3
+ export interface CouponCodeProps extends BoxProps {
4
+ code: string;
5
+ /** Texto do benefício (ex.: "5% OFF na 1ª compra"). Também aceita o slot `description` (o slot tem prioridade). */
6
+ description?: MantineNode;
7
+ /** @default 'Copiar' */
8
+ copyLabel?: string;
9
+ /** @default 'Copiado!' */
10
+ copiedLabel?: string;
11
+ }
12
+ export interface CouponCodeSlots {
13
+ description?: () => VNodeChild;
14
+ }
15
+ export type CouponCodeEmits = {
16
+ /** Emitido ao clicar em copiar, com o código copiado */
17
+ copy: (code: string) => void;
18
+ };
19
+ /** Cupom com borda tracejada e botão de copiar. Emite `copy` com o código. */
20
+ export declare const CouponCode: DefineSetupFnComponent<CouponCodeProps, CouponCodeEmits, SlotsType<CouponCodeSlots>>;
@@ -0,0 +1 @@
1
+ export * from './CouponCode';
@@ -0,0 +1,95 @@
1
+ import { type VNodeChild } from 'vue';
2
+ import { type BoxProps, type MantineNode, type TableProps } from '@mantine-vue/core';
3
+ export interface DataTableColumn<T> {
4
+ /** Chave do campo em `T` (também usada para ordenar). Omita em colunas calculadas/de ações e use `id` + `render`. */
5
+ key?: keyof T & string;
6
+ /** Identificador da coluna quando não há `key` (ex.: 'acoes') */
7
+ id?: string;
8
+ /** Cabeçalho. Também aceita o slot `header-<id>` (o slot tem prioridade). */
9
+ header: MantineNode;
10
+ /** Renderização customizada da célula. O slot `cell-<id>` (`{ row, index }`) tem prioridade. */
11
+ render?: (row: T, index: number) => VNodeChild;
12
+ /** Coluna numérica: alinhada à direita, tabular-nums e formatada em pt-BR */
13
+ numeric?: boolean;
14
+ /** Opções de Intl.NumberFormat para colunas numéricas */
15
+ format?: Intl.NumberFormatOptions;
16
+ sortable?: boolean;
17
+ /** Valor usado na ordenação quando diferente do campo */
18
+ sortValue?: (row: T) => string | number;
19
+ width?: number | string;
20
+ }
21
+ export type SortDirection = 'asc' | 'desc';
22
+ export interface DataTableSort<T> {
23
+ /** `key` ou `id` da coluna ordenada */
24
+ key: (keyof T & string) | (string & {});
25
+ direction: SortDirection;
26
+ }
27
+ /** Props declaradas pelo próprio DataTable. As demais (style props do Box, atributos) vão para o wrapper. */
28
+ export interface DataTableOwnProps<T> {
29
+ columns: DataTableColumn<T>[];
30
+ data: T[];
31
+ /** Chave única de cada linha @default índice */
32
+ rowKey?: (row: T, index: number) => PropertyKey;
33
+ /** Ordenação inicial quando não controlada */
34
+ initialSort?: DataTableSort<T>;
35
+ /** Controle externo da ordenação (use `v-model:sort`; `null` = sem ordenação) */
36
+ sort?: DataTableSort<T> | null;
37
+ /** Ativa paginação local com N linhas por página */
38
+ pageSize?: number;
39
+ loading?: boolean;
40
+ /** Linhas de skeleton durante loading @default 5 */
41
+ loadingRows?: number;
42
+ /** Estado vazio customizado. Também aceita o slot `empty` (o slot tem prioridade). */
43
+ empty?: MantineNode;
44
+ /** Remove a moldura (card) em volta da tabela */
45
+ plain?: boolean;
46
+ striped?: boolean;
47
+ stickyHeader?: boolean;
48
+ /** Props repassadas para o Table do Mantine */
49
+ tableProps?: Omit<TableProps, 'data'>;
50
+ }
51
+ export interface DataTableProps<T> extends Omit<BoxProps, keyof DataTableOwnProps<T>>, DataTableOwnProps<T> {
52
+ 'onUpdate:sort'?: (sort: DataTableSort<T> | null) => void;
53
+ /** Mudança de ordenação (controlada ou não) */
54
+ onSortChange?: (sort: DataTableSort<T> | null) => void;
55
+ /** Clique (ou Enter/Espaço) numa linha. Torna as linhas focáveis. */
56
+ onRowClick?: (row: T, index: number) => void;
57
+ }
58
+ export type DataTableSlots<T> = {
59
+ /** Estado vazio customizado */
60
+ empty?: () => VNodeChild;
61
+ } & {
62
+ [K in `cell-${string}`]?: (scope: {
63
+ row: T;
64
+ index: number;
65
+ }) => VNodeChild;
66
+ } & {
67
+ [K in `header-${string}`]?: () => VNodeChild;
68
+ };
69
+ /**
70
+ * Tabela de dados com ordenação, colunas numéricas pt-BR, paginação e estados vazio/carregando.
71
+ *
72
+ * - `v-model:sort` (controlado) ou `initialSort` (não controlado); `@sort-change` em ambos os casos.
73
+ * - `@row-click="(row, index) => …"` torna as linhas clicáveis/focáveis.
74
+ * - Slots: `#cell-<coluna>="{ row, index }"`, `#header-<coluna>`, `#empty`.
75
+ */
76
+ export declare const DataTable: new <T extends Record<string, any>>(props: DataTableProps<T> & {
77
+ "onUpdate:sort"?: ((...args: any[]) => any) | undefined;
78
+ "onSort-change"?: ((...args: any[]) => any) | undefined;
79
+ "onRow-click"?: ((...args: any[]) => any) | undefined;
80
+ } & import("vue").VNodeProps & import("vue").AllowedComponentProps & import("vue").ComponentCustomProps) => import("vue").CreateComponentPublicInstanceWithMixins<DataTableProps<T> & {
81
+ "onUpdate:sort"?: ((...args: any[]) => any) | undefined;
82
+ "onSort-change"?: ((...args: any[]) => any) | undefined;
83
+ "onRow-click"?: ((...args: any[]) => any) | undefined;
84
+ }, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, ("update:sort" | "sort-change" | "row-click")[], import("vue").PublicProps, {}, false, {}, {}, {}, {}, string, {}, any, import("vue").ComponentProvideOptions, {
85
+ P: {};
86
+ B: {};
87
+ D: {};
88
+ C: {};
89
+ M: {};
90
+ Defaults: {};
91
+ }, DataTableProps<T> & {
92
+ "onUpdate:sort"?: ((...args: any[]) => any) | undefined;
93
+ "onSort-change"?: ((...args: any[]) => any) | undefined;
94
+ "onRow-click"?: ((...args: any[]) => any) | undefined;
95
+ }, {}, {}, {}, {}, {}>;
@@ -0,0 +1 @@
1
+ export * from './DataTable';
@@ -0,0 +1,12 @@
1
+ /** Tile de KPI dos dashboards (ds-kpi). */
2
+ export declare const KpiCard: import("@mantine-vue/core").MantineComponent<{
3
+ props: import("./KpiCard.types").KpiCardProps;
4
+ slots: import("./KpiCard.types").KpiCardSlots;
5
+ ref: HTMLDivElement;
6
+ element: "div";
7
+ stylesNames: import("./KpiCard.types").KpiCardStylesNames;
8
+ vars: import("./KpiCard.types").KpiCardCssVariables;
9
+ }>;
10
+ export { getDeltaTone } from './KpiCard.vars';
11
+ export { KpiGroup, type KpiGroupProps } from './KpiGroup';
12
+ export type { KpiCardCssVariables, KpiCardFactory, KpiCardOwnProps, KpiCardProps, KpiCardSlots, KpiCardStylesNames, } from './KpiCard.types';
@@ -0,0 +1,44 @@
1
+ import type { VNodeChild } from 'vue';
2
+ import type { BoxProps, Factory, MantineNode } from '@mantine-vue/core';
3
+ import type { JcStylesApiProps } from '../../utils/styles-api';
4
+ export type KpiCardStylesNames = 'root' | 'header' | 'label' | 'icon' | 'value' | 'footer' | 'delta' | 'chart';
5
+ export type KpiCardCssVariables = {
6
+ root: '--kpi-delta-color' | '--kpi-value-color';
7
+ };
8
+ /** Props declaradas pelo próprio KpiCard. As demais (style props do Box, atributos) vão para a raiz. */
9
+ export interface KpiCardOwnProps extends JcStylesApiProps<KpiCardFactory> {
10
+ /** Rótulo em caixa-alta (ex.: "Acessos (60d)"). Também aceita o slot `label` (o slot tem prioridade). */
11
+ label?: MantineNode;
12
+ /** Valor principal. Números são formatados em pt-BR. Também aceita o slot `value` (o slot tem prioridade). */
13
+ value?: MantineNode;
14
+ /** Variação em pontos percentuais (ex.: -5.6). Cor e seta automáticas. */
15
+ delta?: number;
16
+ /** Texto ao lado da variação (ex.: "vs. mês anterior"). Também aceita o slot `deltaLabel`. */
17
+ deltaLabel?: MantineNode;
18
+ /** Quando queda é algo bom (ex.: taxa de rejeição), inverte as cores. */
19
+ invertDelta?: boolean;
20
+ /** Pinta o próprio valor com a cor da variação (como o KPI "-5,6%" do DS) */
21
+ colorValue?: boolean;
22
+ /** Também aceita o slot `icon` (o slot tem prioridade). */
23
+ icon?: MantineNode;
24
+ /** Slot para um Sparkline ou mini-gráfico. Também aceita o slot `chart` (o slot tem prioridade). */
25
+ chart?: MantineNode;
26
+ loading?: boolean;
27
+ }
28
+ export interface KpiCardProps extends Omit<BoxProps, keyof KpiCardOwnProps>, KpiCardOwnProps {
29
+ }
30
+ export interface KpiCardSlots {
31
+ label?: () => VNodeChild;
32
+ value?: () => VNodeChild;
33
+ deltaLabel?: () => VNodeChild;
34
+ icon?: () => VNodeChild;
35
+ chart?: () => VNodeChild;
36
+ }
37
+ export type KpiCardFactory = Factory<{
38
+ props: KpiCardProps;
39
+ slots: KpiCardSlots;
40
+ ref: HTMLDivElement;
41
+ element: 'div';
42
+ stylesNames: KpiCardStylesNames;
43
+ vars: KpiCardCssVariables;
44
+ }>;
@@ -0,0 +1,3 @@
1
+ import type { KpiCardProps } from './KpiCard.types';
2
+ export declare function getDeltaTone(delta: number | undefined, invert?: boolean): 'up' | 'down' | 'flat';
3
+ export declare const varsResolver: (theme: import("@mantine-vue/core").MantineTheme, props: KpiCardProps, ctx: Record<string, any>) => Record<string, Record<string, string | undefined>>;
@@ -0,0 +1,42 @@
1
+ import type { KpiCardOwnProps, KpiCardSlots } from './KpiCard.types';
2
+ type __VLS_Slots = KpiCardSlots;
3
+ declare const __VLS_base: import("vue").DefineComponent<KpiCardOwnProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<KpiCardOwnProps> & Readonly<{}>, {
4
+ label: string | number | boolean | import("vue").VNode<import("vue").RendererNode, import("vue").RendererElement, {
5
+ [key: string]: any;
6
+ }> | import("vue").VNodeArrayChildren | (() => import("vue").VNodeChild) | null;
7
+ value: string | number | boolean | import("vue").VNode<import("vue").RendererNode, import("vue").RendererElement, {
8
+ [key: string]: any;
9
+ }> | import("vue").VNodeArrayChildren | (() => import("vue").VNodeChild) | null;
10
+ loading: boolean;
11
+ vars: import("@mantine-vue/core").FactoryPartialVarsResolver<{
12
+ props: import("./KpiCard.types").KpiCardProps;
13
+ slots: KpiCardSlots;
14
+ ref: HTMLDivElement;
15
+ element: "div";
16
+ stylesNames: import("./KpiCard.types").KpiCardStylesNames;
17
+ vars: import("./KpiCard.types").KpiCardCssVariables;
18
+ } & import("@mantine-vue/core").FactoryPayload>;
19
+ icon: string | number | boolean | import("vue").VNode<import("vue").RendererNode, import("vue").RendererElement, {
20
+ [key: string]: any;
21
+ }> | import("vue").VNodeArrayChildren | (() => import("vue").VNodeChild) | null;
22
+ classNames: Partial<Record<"footer" | "header" | "label" | "value" | "icon" | "root" | "delta" | "chart", string>> | ((theme: import("@mantine-vue/core").MantineTheme, props: import("./KpiCard.types").KpiCardProps & Record<string, any>, ctx: Record<string, any>) => Partial<Record<"footer" | "header" | "label" | "value" | "icon" | "root" | "delta" | "chart", string>>);
23
+ styles: Partial<Record<"footer" | "header" | "label" | "value" | "icon" | "root" | "delta" | "chart", import("vue").CSSProperties>> | ((theme: import("@mantine-vue/core").MantineTheme, props: import("./KpiCard.types").KpiCardProps & Record<string, any>, ctx: Record<string, any>) => Partial<Record<"footer" | "header" | "label" | "value" | "icon" | "root" | "delta" | "chart", import("vue").CSSProperties>>);
24
+ unstyled: boolean;
25
+ delta: number;
26
+ chart: string | number | boolean | import("vue").VNode<import("vue").RendererNode, import("vue").RendererElement, {
27
+ [key: string]: any;
28
+ }> | import("vue").VNodeArrayChildren | (() => import("vue").VNodeChild) | null;
29
+ deltaLabel: string | number | boolean | import("vue").VNode<import("vue").RendererNode, import("vue").RendererElement, {
30
+ [key: string]: any;
31
+ }> | import("vue").VNodeArrayChildren | (() => import("vue").VNodeChild) | null;
32
+ invertDelta: boolean;
33
+ colorValue: boolean;
34
+ }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
35
+ declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
36
+ declare const _default: typeof __VLS_export;
37
+ export default _default;
38
+ type __VLS_WithSlots<T, S> = T & {
39
+ new (): {
40
+ $slots: S;
41
+ };
42
+ };
@@ -0,0 +1,10 @@
1
+ import { type DefineSetupFnComponent, type SlotsType, type VNodeChild } from 'vue';
2
+ import { type SimpleGridProps } from '@mantine-vue/core';
3
+ export type KpiGroupProps = SimpleGridProps;
4
+ /**
5
+ * Grade responsiva de KPIs baseada na largura do CONTÊINER (container queries), não da tela:
6
+ * 1 coluna até 440px · 2 até 880px · 4 acima. Funciona igual em página cheia, ao lado de sidebar ou dentro de card.
7
+ */
8
+ export declare const KpiGroup: DefineSetupFnComponent<KpiGroupProps, {}, SlotsType<{
9
+ default?: () => VNodeChild;
10
+ }>>;
@@ -0,0 +1 @@
1
+ export * from './KpiCard';
@@ -0,0 +1,29 @@
1
+ import { type Component, type DefineSetupFnComponent, type SlotsType, type VNodeChild } from 'vue';
2
+ import { type BoxProps, type MantineNode } from '@mantine-vue/core';
3
+ export interface PageHeaderBreadcrumb {
4
+ label: MantineNode;
5
+ href?: string;
6
+ }
7
+ export interface PageHeaderProps extends Omit<BoxProps, 'title'> {
8
+ /** Também aceita o slot `kicker` (o slot tem prioridade). */
9
+ kicker?: MantineNode;
10
+ /** Também aceita o slot `title` (o slot tem prioridade). */
11
+ title?: MantineNode;
12
+ /** Também aceita o slot `description` (o slot tem prioridade). */
13
+ description?: MantineNode;
14
+ /** Botões à direita do título. Também aceita o slot `actions` (o slot tem prioridade). */
15
+ actions?: MantineNode;
16
+ breadcrumbs?: PageHeaderBreadcrumb[];
17
+ /** Componente dos links do breadcrumb (ex.: `RouterLink` do vue-router) @default 'a' */
18
+ linkComponent?: string | Component;
19
+ /** `display` usa display-small (página principal); `headline` usa headline-large @default 'headline' */
20
+ size?: 'display' | 'headline';
21
+ }
22
+ export interface PageHeaderSlots {
23
+ kicker?: () => VNodeChild;
24
+ title?: () => VNodeChild;
25
+ description?: () => VNodeChild;
26
+ actions?: () => VNodeChild;
27
+ }
28
+ /** Cabeçalho de página: breadcrumbs, kicker, título, descrição e ações. */
29
+ export declare const PageHeader: DefineSetupFnComponent<PageHeaderProps, {}, SlotsType<PageHeaderSlots>>;
@@ -0,0 +1 @@
1
+ export * from './PageHeader';
@@ -0,0 +1,21 @@
1
+ import { type DefineSetupFnComponent } from 'vue';
2
+ import { type BoxProps } from '@mantine-vue/core';
3
+ export interface PriceTagProps extends BoxProps {
4
+ /** Preço atual em reais */
5
+ value: number;
6
+ /** Preço "de" (riscado) */
7
+ oldValue?: number;
8
+ /** Parcelamento: `{ count: 10 }` → "ou 10x de R$ 12,99 sem juros" */
9
+ installments?: {
10
+ count: number;
11
+ interestFree?: boolean;
12
+ };
13
+ /** Desconto no Pix em % (ex.: 5) → "R$ 94,05 no Pix" */
14
+ pixDiscount?: number;
15
+ /** Unidade (ex.: "/m²", "/rolo") */
16
+ unit?: string;
17
+ /** @default 'md' */
18
+ size?: 'sm' | 'md' | 'lg';
19
+ }
20
+ /** Preço em BRL com preço antigo, parcelamento e desconto Pix. */
21
+ export declare const PriceTag: DefineSetupFnComponent<PriceTagProps>;
@@ -0,0 +1 @@
1
+ export * from './PriceTag';
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Card de produto do e-commerce: imagem, selos, nome, avaliação, preço e CTA.
3
+ * `v-model:favorite` mostra o botão de favoritar; `@action` mostra o CTA.
4
+ */
5
+ export declare const ProductCard: import("@mantine-vue/core").MantineComponent<{
6
+ props: import("./ProductCard.types").ProductCardProps;
7
+ slots: import("./ProductCard.types").ProductCardSlots;
8
+ emits: import("./ProductCard.types").ProductCardEmits;
9
+ ref: HTMLDivElement;
10
+ stylesNames: import("./ProductCard.types").ProductCardStylesNames;
11
+ }>;
12
+ export type { ProductCardEmits, ProductCardFactory, ProductCardOwnProps, ProductCardProps, ProductCardSlots, ProductCardStylesNames, } from './ProductCard.types';