@rendra-ui/web 2.6.0 → 2.7.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 (55) hide show
  1. package/README.md +2 -1
  2. package/dist/base.css +1 -1
  3. package/dist/{empty-state-DrQjqxvp.js → brand-feedback-icon-BYNcqBel.js} +4 -64
  4. package/dist/brand-feedback-icon-BYNcqBel.js.map +1 -0
  5. package/dist/{button-B6-644xP.js → button-DlzWwpZk.js} +6 -6
  6. package/dist/{button-B6-644xP.js.map → button-DlzWwpZk.js.map} +1 -1
  7. package/dist/chart.js +7 -7
  8. package/dist/cli/auditar.js +1 -1
  9. package/dist/cli/codigos.js +2 -2
  10. package/dist/cli/executar-auditar.js +1 -1
  11. package/dist/cli/help.js +1 -1
  12. package/dist/cli/trocar.js +2 -2
  13. package/dist/cli/typescript-loader.js +1 -1
  14. package/dist/{cn-TBlI6-gS.js → cn-B0N3Pek0.js} +2 -2
  15. package/dist/{cn-TBlI6-gS.js.map → cn-B0N3Pek0.js.map} +1 -1
  16. package/dist/{components-Btk1cUg2.js → components-CpQPMGfT.js} +18 -2
  17. package/dist/{components-Btk1cUg2.js.map → components-CpQPMGfT.js.map} +1 -1
  18. package/dist/components.css +90 -1
  19. package/dist/document-viewer.js +4 -4
  20. package/dist/{tooltip-kgsorOg6.js → dropdown-menu-M8vs0byD.js} +9 -75
  21. package/dist/dropdown-menu-M8vs0byD.js.map +1 -0
  22. package/dist/empty-state-a47Kd_Ci.js +67 -0
  23. package/dist/empty-state-a47Kd_Ci.js.map +1 -0
  24. package/dist/{features-max-CC6CorTg.js → features-max-ScxV8gb3.js} +1 -1
  25. package/dist/flow.js +1485 -0
  26. package/dist/flow.js.map +1 -0
  27. package/dist/index.js +72 -1854
  28. package/dist/index.js.map +1 -1
  29. package/dist/{motion-context-BL545cb6.js → motion-context-BUMPf0e9.js} +4 -4
  30. package/dist/{motion-context-BL545cb6.js.map → motion-context-BUMPf0e9.js.map} +1 -1
  31. package/dist/{motion-on-DMoTsWrG.js → motion-on-CNN6y8g-.js} +2 -2
  32. package/dist/{motion-on-DMoTsWrG.js.map → motion-on-CNN6y8g-.js.map} +1 -1
  33. package/dist/motion.js +2 -2
  34. package/dist/{rendra-provider-CeCkPafT.js → rendra-provider-DEURIIL3.js} +3 -3
  35. package/dist/{rendra-provider-CeCkPafT.js.map → rendra-provider-DEURIIL3.js.map} +1 -1
  36. package/dist/rich-text-editor.js +4 -3
  37. package/dist/rich-text-editor.js.map +1 -1
  38. package/dist/router-bridge.js +2 -2
  39. package/dist/timeline-BOh7gUdA.js +1803 -0
  40. package/dist/timeline-BOh7gUdA.js.map +1 -0
  41. package/dist/tokens.css +1 -1
  42. package/dist/tooltip-Ym9S4h9_.js +76 -0
  43. package/dist/tooltip-Ym9S4h9_.js.map +1 -0
  44. package/dist/types/components/ui/flow-editor.d.ts +11 -0
  45. package/dist/types/components/ui/flow-viewer.d.ts +58 -0
  46. package/dist/types/flow.d.ts +3 -0
  47. package/dist/types/lib/flow.d.ts +121 -0
  48. package/dist/{use-breakpoint-CNxDwEpc.js → use-breakpoint-En17oXKY.js} +2 -2
  49. package/dist/{use-breakpoint-CNxDwEpc.js.map → use-breakpoint-En17oXKY.js.map} +1 -1
  50. package/dist/{use-motion-presets-DCJPBfNJ.js → use-motion-presets-D3ww1oJX.js} +3 -3
  51. package/dist/{use-motion-presets-DCJPBfNJ.js.map → use-motion-presets-D3ww1oJX.js.map} +1 -1
  52. package/dist/widget-grid.js +2 -2
  53. package/package.json +7 -1
  54. package/dist/empty-state-DrQjqxvp.js.map +0 -1
  55. package/dist/tooltip-kgsorOg6.js.map +0 -1
package/dist/index.js CHANGED
@@ -1,22 +1,23 @@
1
- /*! Rendra Design System v2.6.0 | MIT | © 2026 Bruno Magalhaes | brunomagalhaes.me */
2
- import { t as cn } from "./cn-TBlI6-gS.js";
3
- import { a as useMotionMode, c as getReducedMotion, i as useMotionLib, l as subscribeReducedMotion, n as useLayoutReady, o as useMotionOn, r as useMotionAdopted, u as usePrefersReducedMotion } from "./motion-context-BL545cb6.js";
4
- import { t as useMotionPresets } from "./use-motion-presets-DCJPBfNJ.js";
5
- import { a as catalogByComponent, c as findComponentsWithoutDefault, d as findPresetCollisions, f as getCatalogEntry, i as assertCatalogIntegrity, l as findDuplicateCodes, n as CATALOG_EXCLUDED_FILES, o as filesMissingCatalogEntry, p as resolveCatalogCode, r as COMPONENT_CODE_PATTERN, s as findComponentsWithMultipleDefaults, t as CATALOG, u as findInvalidFormatCodes } from "./components-Btk1cUg2.js";
6
- import { n as buttonVariants, r as Spinner, t as Button } from "./button-B6-644xP.js";
7
- import { a as DropdownMenuContent, c as DropdownMenuLabel, d as DropdownMenuSeparator, f as DropdownMenuSub, h as DropdownMenuTrigger, i as DropdownMenuCheckboxItem, l as DropdownMenuRadioGroup, m as DropdownMenuSubTrigger, n as TooltipProvider, o as DropdownMenuGroup, p as DropdownMenuSubContent, r as DropdownMenu, s as DropdownMenuItem, t as Tooltip, u as DropdownMenuRadioItem } from "./tooltip-kgsorOg6.js";
8
- import { a as BrandContext, i as useBrand, n as BrandFeedbackIcon, r as feedbackLabels, t as EmptyState } from "./empty-state-DrQjqxvp.js";
9
- import { a as useRendraNavigate, i as useRendraLink, n as useCurrentPath, r as useRendraBreadcrumbs, t as RendraProvider } from "./rendra-provider-CeCkPafT.js";
10
- import { n as useBreakpoint, t as breakpoints } from "./use-breakpoint-CNxDwEpc.js";
11
- import { ArrowDown, ArrowDownRight, ArrowLeft, ArrowRight, ArrowRightLeft, ArrowUp, ArrowUpRight, Bell, Bot, CalendarDays, Check, CheckCheck, CheckCircle2, ChevronDown, ChevronLeft, ChevronRight, ChevronsUpDown, Clock, Columns3, Download, EllipsisVertical, Eye, EyeOff, FileText, Film, Filter, Globe, GripVertical, Home, ImageIcon, ImagePlus, Info, LayoutTemplate, LogOut, Mail, MapPin, Menu, MessageCircle, MessagesSquare, Mic, Minus, Monitor, Moon, MoreHorizontal, Palette, PanelLeft, Paperclip, Pause, Pencil, Phone, Play, Plus, Reply, RotateCw, Search, Send, SkipForward, Smartphone, Smile, Star, Sun, Trash2, TriangleAlert, UploadCloud, User, VideoIcon, X, XCircle, Zap } from "lucide-react";
12
- import { Accordion as Accordion$1, Avatar as Avatar$1, Checkbox as Checkbox$1, Collapsible, ContextMenu, Dialog, Label as Label$1, NavigationMenu, Popover as Popover$1, Progress as Progress$1, RadioGroup as RadioGroup$1, Slider as Slider$1, Slot, Switch as Switch$1, Tabs as Tabs$1, VisuallyHidden } from "radix-ui";
13
- import { Fragment, cloneElement, createContext, forwardRef, isValidElement, useCallback, useContext, useEffect, useId, useImperativeHandle, useLayoutEffect, useMemo, useRef, useState, useSyncExternalStore } from "react";
1
+ /*! Rendra Design System v2.7.0 | MIT | © 2026 Bruno Magalhaes | brunomagalhaes.me */
2
+ import { t as cn } from "./cn-B0N3Pek0.js";
3
+ import { a as useMotionMode, c as getReducedMotion, i as useMotionLib, l as subscribeReducedMotion, n as useLayoutReady, o as useMotionOn, r as useMotionAdopted, u as usePrefersReducedMotion } from "./motion-context-BUMPf0e9.js";
4
+ import { t as useMotionPresets } from "./use-motion-presets-D3ww1oJX.js";
5
+ import { A as lookupCnpj, B as ActionBar, C as toE164, D as controlInput, E as controlFrame, F as CardHeader, H as useShell, I as CardTitle, L as InfoHint, M as CardContent, N as CardDescription, O as useLookup, P as CardFooter, R as Modal, S as toCents, T as controlAdornmentSpace, V as ShellContext, _ as internationalPhoneMask, a as Label, b as percentMask, c as fieldGridClass, d as Drawer, f as PickerPanel, g as formatCurrency, h as formatCents, i as Field, j as Card, k as lookupCep, l as gapClass, m as DEFAULT_DDI, n as useFillHeight, o as useFieldControl, p as Input, r as Select, s as alignClass, t as Timeline, u as justifyClass, v as masks, w as controlAdornmentButton, x as phoneCountries, y as parseLocaleNumber, z as Alert } from "./timeline-BOh7gUdA.js";
6
+ import { a as catalogByComponent, c as findComponentsWithoutDefault, d as findPresetCollisions, f as getCatalogEntry, i as assertCatalogIntegrity, l as findDuplicateCodes, n as CATALOG_EXCLUDED_FILES, o as filesMissingCatalogEntry, p as resolveCatalogCode, r as COMPONENT_CODE_PATTERN, s as findComponentsWithMultipleDefaults, t as CATALOG, u as findInvalidFormatCodes } from "./components-CpQPMGfT.js";
7
+ import { n as buttonVariants, r as Spinner, t as Button } from "./button-DlzWwpZk.js";
8
+ import { a as DropdownMenuItem, c as DropdownMenuRadioItem, d as DropdownMenuSubContent, f as DropdownMenuSubTrigger, i as DropdownMenuGroup, l as DropdownMenuSeparator, n as DropdownMenuCheckboxItem, o as DropdownMenuLabel, p as DropdownMenuTrigger, r as DropdownMenuContent, s as DropdownMenuRadioGroup, t as DropdownMenu, u as DropdownMenuSub } from "./dropdown-menu-M8vs0byD.js";
9
+ import { i as BrandContext, n as feedbackLabels, r as useBrand, t as BrandFeedbackIcon } from "./brand-feedback-icon-BYNcqBel.js";
10
+ import { a as useRendraNavigate, i as useRendraLink, n as useCurrentPath, r as useRendraBreadcrumbs, t as RendraProvider } from "./rendra-provider-DEURIIL3.js";
11
+ import { n as useBreakpoint, t as breakpoints } from "./use-breakpoint-En17oXKY.js";
12
+ import { t as EmptyState } from "./empty-state-a47Kd_Ci.js";
13
+ import { n as TooltipProvider, t as Tooltip } from "./tooltip-Ym9S4h9_.js";
14
+ import { ArrowDown, ArrowDownRight, ArrowLeft, ArrowRight, ArrowRightLeft, ArrowUp, ArrowUpRight, Bell, Bot, CalendarDays, Check, CheckCheck, ChevronDown, ChevronLeft, ChevronRight, ChevronsUpDown, Clock, Columns3, Download, EllipsisVertical, FileText, Film, Filter, Globe, GripVertical, Home, ImageIcon, ImagePlus, LayoutTemplate, LogOut, Mail, MapPin, Menu, MessageCircle, MessagesSquare, Mic, Minus, Monitor, Moon, MoreHorizontal, Palette, PanelLeft, Paperclip, Pause, Pencil, Phone, Play, Plus, Reply, RotateCw, Search, Send, Smartphone, Smile, Star, Sun, Trash2, TriangleAlert, UploadCloud, User, VideoIcon, X, Zap } from "lucide-react";
15
+ import { Accordion as Accordion$1, Avatar as Avatar$1, Checkbox as Checkbox$1, Collapsible, ContextMenu, Dialog, NavigationMenu, Popover as Popover$1, Progress as Progress$1, RadioGroup as RadioGroup$1, Slider as Slider$1, Slot, Switch as Switch$1, Tabs as Tabs$1, VisuallyHidden } from "radix-ui";
16
+ import { Fragment, createContext, forwardRef, useCallback, useContext, useEffect, useId, useLayoutEffect, useMemo, useRef, useState, useSyncExternalStore } from "react";
14
17
  import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
15
- import { createPortal } from "react-dom";
16
18
  import { cva } from "class-variance-authority";
17
19
  import { addDays, addMonths, addWeeks, differenceInMinutes, endOfMonth, endOfWeek, format, isSameDay, isSameMonth, isToday, isYesterday, startOfDay, startOfMonth, startOfWeek } from "date-fns";
18
20
  import { ptBR } from "date-fns/locale";
19
- import IMask from "imask";
20
21
  import { DayPicker } from "react-day-picker";
21
22
  import { ptBR as ptBR$1 } from "react-day-picker/locale";
22
23
  import { FormProvider, useController, useFormContext } from "react-hook-form";
@@ -171,129 +172,6 @@ function Accordion({ items, multiple, defaultValue, className }) {
171
172
  });
172
173
  }
173
174
  //#endregion
174
- //#region src/components/app-shell/shell-context.ts
175
- var ShellContext = createContext(null);
176
- function useShell() {
177
- const ctx = useContext(ShellContext);
178
- if (!ctx) throw new Error("useShell precisa estar dentro de <AppShell>.");
179
- return ctx;
180
- }
181
- //#endregion
182
- //#region src/components/ui/action-bar.tsx
183
- /**
184
- * Barra de ações única, com a regra de botões do sistema:
185
- * 1 botão = 100%; 2 botões = cancelar 30% + principal 70%; 3 ou mais = extras no menu.
186
- * Vale para drawer, modal e formulário em página, em qualquer tamanho de tela.
187
- */
188
- function ActionBar({ primary, cancel, secondary, sticky, className }) {
189
- const slot = useContext(ShellContext)?.footerSlot;
190
- const hasMenu = Boolean(secondary?.length);
191
- const layout = cancel ? hasMenu ? "grid-actions-3" : "grid-actions-2" : hasMenu ? "grid-actions-3" : "";
192
- const bar = /* @__PURE__ */ jsx("div", {
193
- "data-rendra": "ACB-001",
194
- className: cn(sticky && "border-t bg-card px-4 pt-4 pb-safe md:px-6", sticky && !slot && "sticky bottom-0 z-20", className),
195
- children: /* @__PURE__ */ jsxs("div", {
196
- className: cn("grid gap-3", layout || "grid-cols-1", sticky && "w-full"),
197
- children: [
198
- hasMenu && /* @__PURE__ */ jsxs(DropdownMenu, { children: [/* @__PURE__ */ jsx(DropdownMenuTrigger, {
199
- asChild: true,
200
- children: /* @__PURE__ */ jsx(Button, {
201
- variant: "outline",
202
- iconOnly: true,
203
- "aria-label": "Mais ações",
204
- children: /* @__PURE__ */ jsx(MoreHorizontal, {})
205
- })
206
- }), /* @__PURE__ */ jsx(DropdownMenuContent, {
207
- align: "start",
208
- side: "top",
209
- children: secondary.map((a) => /* @__PURE__ */ jsxs(DropdownMenuItem, {
210
- onSelect: a.onClick,
211
- disabled: a.disabled,
212
- destructive: a.destructive,
213
- children: [a.icon, a.label]
214
- }, a.label))
215
- })] }),
216
- cancel ? /* @__PURE__ */ jsx(Button, {
217
- variant: "outline",
218
- icon: cancel.icon,
219
- onClick: cancel.onClick,
220
- disabled: cancel.disabled || primary.loading,
221
- fullWidth: true,
222
- children: cancel.label
223
- }) : hasMenu ? /* @__PURE__ */ jsx("span", { "aria-hidden": true }) : null,
224
- /* @__PURE__ */ jsx(Button, {
225
- type: primary.type ?? "button",
226
- form: primary.form,
227
- variant: primary.destructive ? "destructive" : "primary",
228
- icon: primary.icon,
229
- onClick: primary.onClick,
230
- disabled: primary.disabled,
231
- loading: primary.loading,
232
- fullWidth: true,
233
- children: primary.loading ? primary.loadingLabel ?? "Salvando..." : primary.label
234
- })
235
- ]
236
- })
237
- });
238
- return sticky && slot ? createPortal(bar, slot) : bar;
239
- }
240
- //#endregion
241
- //#region src/components/ui/alert.tsx
242
- /**
243
- * Alert único do sistema: ícone da marca à esquerda, título em destaque e descrição.
244
- * O tipo é prop; o formato vem do template ativo (quadrado, meio-termo ou arredondado).
245
- */
246
- var alertVariants = cva("flex w-full min-w-0 items-start gap-3 rounded-control border", {
247
- variants: { type: {
248
- success: "border-success/25 bg-success-soft text-success-soft-foreground",
249
- error: "border-destructive/25 bg-destructive-soft text-destructive-soft-foreground",
250
- warning: "border-warning/25 bg-warning-soft text-warning-soft-foreground",
251
- info: "border-info/25 bg-info-soft text-info-soft-foreground"
252
- } },
253
- defaultVariants: { type: "info" }
254
- });
255
- function Alert({ type, title, description, action, onDismiss, animated = false, className }) {
256
- const { shape } = useBrand();
257
- const pill = shape === "pill";
258
- return /* @__PURE__ */ jsxs("div", {
259
- role: type === "error" || type === "warning" ? "alert" : "status",
260
- "data-rendra": "ALRT-001",
261
- className: cn(alertVariants({ type }), pill ? "items-center py-3 pr-4 pl-4 md:pr-6" : "p-4", className),
262
- children: [
263
- /* @__PURE__ */ jsx(BrandFeedbackIcon, {
264
- type,
265
- size: "lg",
266
- animated,
267
- className: cn(!pill && "mt-px")
268
- }),
269
- /* @__PURE__ */ jsxs("div", {
270
- className: cn("flex min-w-0 flex-1 flex-col", !pill && "gap-1"),
271
- children: [/* @__PURE__ */ jsx("p", {
272
- className: "text-sm font-semibold",
273
- children: title
274
- }), description && /* @__PURE__ */ jsx("p", {
275
- className: "text-sm opacity-90",
276
- children: description
277
- })]
278
- }),
279
- action && /* @__PURE__ */ jsx("div", {
280
- className: "shrink-0 self-center",
281
- children: action
282
- }),
283
- onDismiss && /* @__PURE__ */ jsx("button", {
284
- type: "button",
285
- onClick: onDismiss,
286
- "aria-label": "Fechar aviso",
287
- className: cn("flex size-touch shrink-0 items-center justify-center rounded-full transition-colors hover:bg-card/60 md:size-8", pill ? "-my-2" : "-mt-2 -mr-2"),
288
- children: /* @__PURE__ */ jsx(X, {
289
- className: "size-icon-sm",
290
- "aria-hidden": true
291
- })
292
- })
293
- ]
294
- });
295
- }
296
- //#endregion
297
175
  //#region src/lib/initials.ts
298
176
  /** Iniciais de um nome: primeira letra do primeiro e do último nome, em maiúsculas. */
299
177
  function initials(name) {
@@ -617,264 +495,6 @@ function ButtonGroup({ children, options, value, onChange, size = "md", fullWidt
617
495
  });
618
496
  }
619
497
  //#endregion
620
- //#region src/components/ui/overlay-shell.tsx
621
- function OverlayShell({ title, description, icon, children, footer, hideHeader, onRequestClose, bodyClassName }) {
622
- const closeButton = /* @__PURE__ */ jsx("button", {
623
- type: "button",
624
- onClick: onRequestClose,
625
- "aria-label": "Fechar",
626
- className: cn("-mt-1 -mr-2 flex size-touch shrink-0 cursor-pointer items-center justify-center rounded-item text-muted-foreground transition-colors hover:bg-accent hover:text-foreground md:size-control-md", hideHeader && "pointer-events-auto m-0 cursor-default opacity-0 focus-visible:cursor-pointer focus-visible:opacity-100"),
627
- children: /* @__PURE__ */ jsx(X, {
628
- className: "size-icon-md",
629
- "aria-hidden": true
630
- })
631
- });
632
- return /* @__PURE__ */ jsxs(Fragment$1, { children: [
633
- hideHeader && /* @__PURE__ */ jsx("div", {
634
- className: "pointer-events-none absolute inset-x-0 top-0 z-10 flex justify-end px-2 pt-safe md:px-4 md:pt-4",
635
- children: closeButton
636
- }),
637
- /* @__PURE__ */ jsxs("header", {
638
- className: cn("flex shrink-0 items-start gap-3 border-b px-4 pt-safe pb-4 md:px-6 md:pt-6", hideHeader && "sr-only"),
639
- children: [
640
- icon && /* @__PURE__ */ jsx("span", {
641
- "aria-hidden": true,
642
- className: "flex size-control-md shrink-0 items-center justify-center rounded-control bg-primary-soft text-primary-soft-foreground [&_svg]:size-icon-md",
643
- children: icon
644
- }),
645
- /* @__PURE__ */ jsxs("div", {
646
- className: "flex min-w-0 flex-1 flex-col gap-1 pt-1",
647
- children: [/* @__PURE__ */ jsx(Dialog.Title, {
648
- className: "text-lg font-semibold wrap-break-word",
649
- children: title
650
- }), description ? /* @__PURE__ */ jsx(Dialog.Description, {
651
- className: "text-sm wrap-break-word text-muted-foreground",
652
- children: description
653
- }) : /* @__PURE__ */ jsx(Dialog.Description, {
654
- className: "sr-only",
655
- children: title
656
- })]
657
- }),
658
- !hideHeader && closeButton
659
- ]
660
- }),
661
- /* @__PURE__ */ jsx("div", {
662
- className: cn("min-h-0 flex-1 overflow-y-auto overscroll-contain px-4 py-6 md:px-6", bodyClassName),
663
- children
664
- }),
665
- footer && /* @__PURE__ */ jsx("footer", {
666
- className: "shrink-0 border-t bg-card px-4 pt-4 pb-safe md:px-6 md:pb-6",
667
- children: footer
668
- })
669
- ] });
670
- }
671
- //#endregion
672
- //#region src/components/ui/modal.tsx
673
- var sizes$1 = {
674
- sm: "md:max-w-sm",
675
- md: "md:max-w-lg",
676
- lg: "md:max-w-2xl"
677
- };
678
- var overlayCls$1 = "fixed inset-0 z-50 bg-overlay";
679
- var overlayOffCls = cn(overlayCls$1, "data-[state=closed]:animate-out data-[state=closed]:duration-(--rendra-duration-fast) data-[state=closed]:fade-out-0 data-[state=open]:animate-in data-[state=open]:fade-in-0");
680
- var contentCls = cn("fixed inset-0 z-50 flex h-dvh flex-col bg-card text-card-foreground outline-none", "md:inset-auto md:top-1/2 md:left-1/2 md:h-auto md:max-h-sheet md:w-full md:-translate-x-1/2 md:-translate-y-1/2 md:rounded-surface md:border md:shadow-lg");
681
- var feedback = {
682
- confirm: "info",
683
- destructive: "error",
684
- info: "info"
685
- };
686
- function Modal({ open, onOpenChange, title, description, type = "confirm", size = "sm", children, confirmLabel = type === "destructive" ? "Excluir" : type === "info" ? "Entendi" : "Confirmar", cancelLabel, onConfirm, formId, loading }) {
687
- const [busy, setBusy] = useState(false);
688
- const close = () => onOpenChange(false);
689
- const confirm = async () => {
690
- if (!onConfirm) return close();
691
- try {
692
- setBusy(true);
693
- await onConfirm();
694
- close();
695
- } finally {
696
- setBusy(false);
697
- }
698
- };
699
- const isForm = type === "form";
700
- const lib = useMotionLib();
701
- const presets = useMotionPresets();
702
- const { isMobile } = useBreakpoint();
703
- const code = resolveCatalogCode("Modal", { type: type === "destructive" ? "confirm" : type });
704
- const sizeCls = sizes$1[size];
705
- const shell = /* @__PURE__ */ jsxs(OverlayShell, {
706
- title,
707
- description: isForm ? description : void 0,
708
- hideHeader: !isForm,
709
- onRequestClose: close,
710
- bodyClassName: cn(!isForm && "flex flex-col items-center justify-center gap-4 text-center"),
711
- footer: /* @__PURE__ */ jsx(ActionBar, {
712
- primary: {
713
- label: confirmLabel,
714
- destructive: type === "destructive",
715
- loading: busy || loading,
716
- loadingLabel: `${confirmLabel}...`,
717
- type: isForm && formId ? "submit" : "button",
718
- form: isForm ? formId : void 0,
719
- onClick: isForm && formId ? void 0 : confirm
720
- },
721
- cancel: type === "info" && cancelLabel === void 0 ? void 0 : {
722
- label: cancelLabel ?? "Cancelar",
723
- onClick: close
724
- }
725
- }),
726
- children: [!isForm && /* @__PURE__ */ jsxs(Fragment$1, { children: [
727
- /* @__PURE__ */ jsx(BrandFeedbackIcon, {
728
- type: feedback[type],
729
- size: "2xl",
730
- animated: true
731
- }),
732
- /* @__PURE__ */ jsxs("div", {
733
- className: "flex flex-col gap-2",
734
- children: [/* @__PURE__ */ jsx("p", {
735
- className: "text-lg font-semibold wrap-anywhere",
736
- children: title
737
- }), description && /* @__PURE__ */ jsx("p", {
738
- className: "text-sm wrap-anywhere text-muted-foreground",
739
- children: description
740
- })]
741
- }),
742
- children
743
- ] }), isForm && /* @__PURE__ */ jsx("div", {
744
- className: "flex flex-col gap-2",
745
- children
746
- })]
747
- });
748
- if (lib) return /* @__PURE__ */ jsx(Dialog.Root, {
749
- open,
750
- onOpenChange,
751
- children: /* @__PURE__ */ jsx(lib.AnimatePresence, { children: open && /* @__PURE__ */ jsxs(Dialog.Portal, {
752
- forceMount: true,
753
- children: [/* @__PURE__ */ jsx(Dialog.Overlay, {
754
- forceMount: true,
755
- asChild: true,
756
- children: /* @__PURE__ */ jsx(lib.m.div, {
757
- className: overlayCls$1,
758
- ...presets.fade
759
- })
760
- }), /* @__PURE__ */ jsx(Dialog.Content, {
761
- forceMount: true,
762
- asChild: true,
763
- "data-rendra": code,
764
- className: cn(contentCls, sizeCls),
765
- children: /* @__PURE__ */ jsx(lib.m.div, {
766
- ...presets.open(isMobile ? { y: 8 } : void 0),
767
- children: shell
768
- })
769
- })]
770
- }, "modal") })
771
- });
772
- return /* @__PURE__ */ jsx(Dialog.Root, {
773
- open,
774
- onOpenChange,
775
- children: /* @__PURE__ */ jsxs(Dialog.Portal, { children: [/* @__PURE__ */ jsx(Dialog.Overlay, { className: overlayOffCls }), /* @__PURE__ */ jsx(Dialog.Content, {
776
- "data-rendra": code,
777
- className: cn(contentCls, "data-[state=closed]:animate-out data-[state=closed]:duration-(--rendra-duration-fast) data-[state=closed]:fade-out-0 data-[state=open]:animate-in data-[state=open]:fade-in-0 md:data-[state=open]:zoom-in-95", sizeCls),
778
- children: shell
779
- })] })
780
- });
781
- }
782
- //#endregion
783
- //#region src/components/ui/info-hint.tsx
784
- function InfoHint({ title, children, className }) {
785
- const [open, setOpen] = useState(false);
786
- return /* @__PURE__ */ jsxs("span", {
787
- className: "contents",
788
- "data-rendra": "INFO-001",
789
- children: [/* @__PURE__ */ jsx(Button, {
790
- variant: "ghost",
791
- size: "sm",
792
- iconOnly: true,
793
- "aria-label": `Sobre: ${title}`,
794
- onClick: () => setOpen(true),
795
- className: cn("shrink-0 text-muted-foreground hover:text-primary-text max-md:size-touch", className),
796
- children: /* @__PURE__ */ jsx(Info, { "aria-hidden": true })
797
- }), /* @__PURE__ */ jsx(Modal, {
798
- open,
799
- onOpenChange: setOpen,
800
- type: "info",
801
- title,
802
- size: "md",
803
- children: /* @__PURE__ */ jsx("div", {
804
- className: "flex flex-col gap-3 text-sm text-muted-foreground",
805
- children
806
- })
807
- })]
808
- });
809
- }
810
- //#endregion
811
- //#region src/components/ui/card.tsx
812
- function Card({ className, "data-rendra": dataRendra, ...props }) {
813
- return /* @__PURE__ */ jsx("div", {
814
- "data-slot": "card",
815
- "data-rendra": dataRendra ?? "CARD-001",
816
- className: cn("flex min-w-0 flex-col rounded-surface border bg-card text-card-foreground", className),
817
- ...props
818
- });
819
- }
820
- function CardHeader({ className, actions, children, ...props }) {
821
- if (!actions) return /* @__PURE__ */ jsx("div", {
822
- "data-slot": "card-header",
823
- className: cn("flex flex-col gap-1 p-4 md:p-6", className),
824
- ...props,
825
- children
826
- });
827
- return /* @__PURE__ */ jsxs("div", {
828
- "data-slot": "card-header",
829
- className: cn("flex flex-wrap items-start justify-between gap-x-4 gap-y-3 p-4 md:p-6", className),
830
- ...props,
831
- children: [/* @__PURE__ */ jsx("div", {
832
- className: "flex min-w-0 flex-1 flex-col gap-1",
833
- children
834
- }), /* @__PURE__ */ jsx("div", {
835
- className: "flex shrink-0 items-center gap-2",
836
- children: actions
837
- })]
838
- });
839
- }
840
- function CardTitle({ className, children, help, ...props }) {
841
- const heading = /* @__PURE__ */ jsx("h3", {
842
- "data-slot": "card-title",
843
- className: cn("text-lg font-semibold", className),
844
- ...props,
845
- children
846
- });
847
- if (!help) return heading;
848
- return /* @__PURE__ */ jsxs("div", {
849
- className: "flex min-w-0 items-center gap-1",
850
- children: [heading, /* @__PURE__ */ jsx(InfoHint, {
851
- title: typeof children === "string" ? children : "Sobre esta seção",
852
- children: help
853
- })]
854
- });
855
- }
856
- function CardDescription({ className, ...props }) {
857
- return /* @__PURE__ */ jsx("p", {
858
- "data-slot": "card-description",
859
- className: cn("text-sm text-muted-foreground", className),
860
- ...props
861
- });
862
- }
863
- function CardContent({ className, ...props }) {
864
- return /* @__PURE__ */ jsx("div", {
865
- "data-slot": "card-content",
866
- className: cn("p-4 md:p-6 [[data-slot=card-header]+&]:pt-0", className),
867
- ...props
868
- });
869
- }
870
- function CardFooter({ className, ...props }) {
871
- return /* @__PURE__ */ jsx("div", {
872
- "data-slot": "card-footer",
873
- className: cn("flex items-center gap-3 border-t px-4 py-3 md:px-6", className),
874
- ...props
875
- });
876
- }
877
- //#endregion
878
498
  //#region src/components/ui/calendar.tsx
879
499
  var viewLabels = {
880
500
  month: "Mês",
@@ -1313,575 +933,6 @@ function Calendar({ events, view: viewProp, defaultView = "month", onViewChange,
1313
933
  });
1314
934
  }
1315
935
  //#endregion
1316
- //#region src/lib/lookup.ts
1317
- var digits$1 = (v) => v.replace(/\D/g, "");
1318
- /** Endereço do CEP (8 dígitos). null se não existir; lança erro se a busca falhar. */
1319
- async function lookupCep(cep, signal) {
1320
- const d = digits$1(cep);
1321
- if (d.length !== 8) return null;
1322
- const res = await fetch(`https://viacep.com.br/ws/${d}/json/`, { signal });
1323
- if (!res.ok) throw new Error("Não foi possível buscar o CEP agora.");
1324
- const data = await res.json();
1325
- if (data.erro) return null;
1326
- return {
1327
- cep: String(data.cep ?? ""),
1328
- logradouro: String(data.logradouro ?? ""),
1329
- complemento: String(data.complemento ?? ""),
1330
- bairro: String(data.bairro ?? ""),
1331
- cidade: String(data.localidade ?? ""),
1332
- uf: String(data.uf ?? "")
1333
- };
1334
- }
1335
- /** Dados públicos do CNPJ (14 dígitos). null se não existir; lança erro se a busca falhar. */
1336
- async function lookupCnpj(cnpj, signal) {
1337
- const d = digits$1(cnpj);
1338
- if (d.length !== 14) return null;
1339
- const res = await fetch(`https://brasilapi.com.br/api/cnpj/v1/${d}`, { signal });
1340
- if (res.status === 404) return null;
1341
- if (!res.ok) throw new Error("Não foi possível buscar o CNPJ agora.");
1342
- const data = await res.json();
1343
- const s = (k) => data[k] == null ? "" : String(data[k]);
1344
- const fone = digits$1(s("ddd_telefone_1"));
1345
- return {
1346
- razaoSocial: s("razao_social"),
1347
- nomeFantasia: s("nome_fantasia"),
1348
- email: s("email").toLowerCase(),
1349
- telefone: fone.length >= 10 ? `(${fone.slice(0, 2)}) ${fone.slice(2, -4)}-${fone.slice(-4)}` : "",
1350
- situacao: s("descricao_situacao_cadastral"),
1351
- endereco: {
1352
- cep: s("cep"),
1353
- logradouro: [s("descricao_tipo_de_logradouro"), s("logradouro")].filter(Boolean).join(" "),
1354
- numero: s("numero"),
1355
- complemento: s("complemento"),
1356
- bairro: s("bairro"),
1357
- cidade: s("municipio"),
1358
- uf: s("uf")
1359
- }
1360
- };
1361
- }
1362
- //#endregion
1363
- //#region src/hooks/use-lookup.ts
1364
- /**
1365
- * Busca CEP (8 dígitos) ou CNPJ (14 dígitos) assim que o valor fica completo. Cancela a
1366
- * busca anterior quando o valor muda. `kind` 'auto' decide pelo tamanho (CPF ou CNPJ: só
1367
- * o CNPJ busca). Sem `onResult`, não faz nada.
1368
- */
1369
- function useLookup(kind, value, onResult) {
1370
- const [loading, setLoading] = useState(false);
1371
- const cb = useRef(onResult);
1372
- cb.current = onResult;
1373
- const digits = value.replace(/\D/g, "");
1374
- const target = kind === "cep" && digits.length === 8 ? "cep" : (kind === "cnpj" || kind === "auto") && digits.length === 14 ? "cnpj" : null;
1375
- const enabled = Boolean(onResult) && target !== null;
1376
- useEffect(() => {
1377
- if (!enabled || !target) return;
1378
- const ctrl = new AbortController();
1379
- const send = (r) => {
1380
- if (!ctrl.signal.aborted) cb.current?.(r);
1381
- };
1382
- setLoading(true);
1383
- send({
1384
- status: "loading",
1385
- kind: target
1386
- });
1387
- (target === "cep" ? lookupCep(digits, ctrl.signal).then((data) => data ? send({
1388
- status: "found",
1389
- kind: "cep",
1390
- data,
1391
- message: "Endereço preenchido pelo CEP."
1392
- }) : send({
1393
- status: "not-found",
1394
- kind: "cep",
1395
- message: "CEP não encontrado. Preencha o endereço."
1396
- })) : lookupCnpj(digits, ctrl.signal).then((data) => data ? send({
1397
- status: "found",
1398
- kind: "cnpj",
1399
- data,
1400
- message: `${data.situacao ? `Situação: ${data.situacao}. ` : ""}Dados preenchidos pelo CNPJ.`
1401
- }) : send({
1402
- status: "not-found",
1403
- kind: "cnpj",
1404
- message: "CNPJ não encontrado. Preencha os dados abaixo."
1405
- }))).catch((e) => send({
1406
- status: "error",
1407
- kind: target,
1408
- message: e instanceof Error ? e.message : "Não foi possível buscar agora."
1409
- })).finally(() => {
1410
- if (!ctrl.signal.aborted) setLoading(false);
1411
- });
1412
- return () => {
1413
- ctrl.abort();
1414
- setLoading(false);
1415
- };
1416
- }, [
1417
- enabled,
1418
- target,
1419
- digits
1420
- ]);
1421
- return loading;
1422
- }
1423
- //#endregion
1424
- //#region src/lib/control.ts
1425
- /**
1426
- * Moldura única dos campos (Input, Select, DatePicker, Textarea). Mesma altura dos botões
1427
- * em cada tamanho; fonte de 16px no mobile para o iOS não dar zoom ao focar.
1428
- */
1429
- /** Marque o elemento com data-slot="control": o teste de toque mede a moldura, não o input. */
1430
- var controlFrame = cva("group/control flex w-full min-w-0 items-center gap-2 rounded-control border border-input bg-field text-base text-foreground transition-[border-color,box-shadow] duration-150 focus-within:border-ring focus-within:bg-card focus-within:ring-2 focus-within:ring-ring/25 hover:border-foreground/40 has-[:disabled]:cursor-not-allowed has-[:disabled]:opacity-60 has-[:disabled]:hover:border-input md:text-sm", {
1431
- variants: {
1432
- size: {
1433
- sm: "h-control-sm px-3",
1434
- md: "h-control-md px-3",
1435
- lg: "h-control-lg px-4"
1436
- },
1437
- invalid: {
1438
- true: "border-destructive focus-within:border-destructive focus-within:ring-destructive/25 hover:border-destructive",
1439
- false: ""
1440
- }
1441
- },
1442
- defaultVariants: {
1443
- size: "md",
1444
- invalid: false
1445
- }
1446
- });
1447
- /** Classe do <input> nativo dentro da moldura. */
1448
- var controlInput = "h-full min-w-0 flex-1 bg-transparent outline-none placeholder:text-muted-foreground disabled:cursor-not-allowed";
1449
- /** Botão pequeno dentro da moldura (limpar, mostrar senha). */
1450
- var controlAdornmentButton = "-mr-2 flex size-control-sm shrink-0 cursor-pointer items-center justify-center rounded-item text-muted-foreground transition-colors outline-none hover:bg-accent hover:text-foreground focus-visible:ring-2 focus-visible:ring-ring md:-mr-1 md:size-8 [&_svg]:size-icon-sm";
1451
- /**
1452
- * Reserva, dentro de um gatilho, o espaço do botão sobreposto (limpar do Select e do
1453
- * DatePicker), para o texto não passar por baixo dele.
1454
- */
1455
- var controlAdornmentSpace = "size-control-sm shrink-0 md:size-8";
1456
- //#endregion
1457
- //#region src/lib/masks.ts
1458
- var numberBlock = (scale, max) => ({
1459
- mask: Number,
1460
- scale,
1461
- thousandsSeparator: ".",
1462
- radix: ",",
1463
- mapToRadix: ["."],
1464
- padFractionalZeros: true,
1465
- normalizeZeros: true,
1466
- min: 0,
1467
- ...max !== void 0 ? { max } : {}
1468
- });
1469
- var masks = {
1470
- cpf: {
1471
- options: { mask: "000.000.000-00" },
1472
- inputMode: "numeric",
1473
- placeholder: "000.000.000-00"
1474
- },
1475
- cnpj: {
1476
- options: { mask: "00.000.000/0000-00" },
1477
- inputMode: "numeric",
1478
- placeholder: "00.000.000/0000-00"
1479
- },
1480
- cpfCnpj: {
1481
- options: { mask: [{ mask: "000.000.000-00" }, { mask: "00.000.000/0000-00" }] },
1482
- inputMode: "numeric",
1483
- placeholder: "CPF ou CNPJ"
1484
- },
1485
- phone: {
1486
- options: { mask: [{ mask: "(00) 0000-0000" }, { mask: "(00) 00000-0000" }] },
1487
- inputMode: "tel",
1488
- placeholder: "(00) 00000-0000"
1489
- },
1490
- cep: {
1491
- options: { mask: "00000-000" },
1492
- inputMode: "numeric",
1493
- placeholder: "00000-000"
1494
- },
1495
- date: {
1496
- options: { mask: "00/00/0000" },
1497
- inputMode: "numeric",
1498
- placeholder: "DD/MM/AAAA"
1499
- },
1500
- time: {
1501
- options: { mask: "00:00" },
1502
- inputMode: "numeric",
1503
- placeholder: "00:00"
1504
- },
1505
- currency: {
1506
- options: {
1507
- mask: "R$ num",
1508
- lazy: false,
1509
- blocks: { num: numberBlock(2) }
1510
- },
1511
- inputMode: "decimal",
1512
- placeholder: "R$ 0,00"
1513
- },
1514
- percent: {
1515
- options: {
1516
- mask: "num %",
1517
- lazy: false,
1518
- blocks: { num: numberBlock(2, 100) }
1519
- },
1520
- inputMode: "decimal",
1521
- placeholder: "0,00 %"
1522
- }
1523
- };
1524
- /** Máscara de percentual com teto configurável (padrão 100), para o Input com unidades (A9). */
1525
- function percentMask(max = 100) {
1526
- return {
1527
- options: {
1528
- mask: "num %",
1529
- lazy: false,
1530
- blocks: { num: numberBlock(2, max) }
1531
- },
1532
- inputMode: "decimal",
1533
- placeholder: "0,00 %"
1534
- };
1535
- }
1536
- /** DDI padrão do campo de telefone. */
1537
- var DEFAULT_DDI = "55";
1538
- /** Lista padrão do seletor de DDI (Brasil primeiro). Troque com a prop ddiOptions do Input. */
1539
- var phoneCountries = [
1540
- {
1541
- ddi: "55",
1542
- name: "Brasil"
1543
- },
1544
- {
1545
- ddi: "54",
1546
- name: "Argentina"
1547
- },
1548
- {
1549
- ddi: "56",
1550
- name: "Chile"
1551
- },
1552
- {
1553
- ddi: "57",
1554
- name: "Colômbia"
1555
- },
1556
- {
1557
- ddi: "595",
1558
- name: "Paraguai"
1559
- },
1560
- {
1561
- ddi: "598",
1562
- name: "Uruguai"
1563
- },
1564
- {
1565
- ddi: "52",
1566
- name: "México"
1567
- },
1568
- {
1569
- ddi: "1",
1570
- name: "Estados Unidos e Canadá"
1571
- },
1572
- {
1573
- ddi: "351",
1574
- name: "Portugal"
1575
- },
1576
- {
1577
- ddi: "34",
1578
- name: "Espanha"
1579
- },
1580
- {
1581
- ddi: "33",
1582
- name: "França"
1583
- },
1584
- {
1585
- ddi: "39",
1586
- name: "Itália"
1587
- },
1588
- {
1589
- ddi: "49",
1590
- name: "Alemanha"
1591
- },
1592
- {
1593
- ddi: "44",
1594
- name: "Reino Unido"
1595
- }
1596
- ];
1597
- /** Máscara do número fora do Brasil: só dígitos, em grupos, até 15 (limite do padrão E.164). */
1598
- var internationalPhoneMask = {
1599
- options: { mask: "000 000 000 000 000" },
1600
- inputMode: "tel",
1601
- placeholder: "Número com DDD"
1602
- };
1603
- /** Número completo no padrão internacional: toE164("55", "(11) 91234-5678") = "+5511912345678". */
1604
- function toE164(ddi, national) {
1605
- const digits = national.replace(/\D/g, "");
1606
- return digits ? `+${ddi}${digits}` : "";
1607
- }
1608
- /** Converte "R$ 1.250,00" ou "12,5 %" em número. */
1609
- function parseLocaleNumber(masked) {
1610
- const clean = masked.replace(/[^\d,-]/g, "").replace(",", ".");
1611
- if (!clean) return null;
1612
- const n = Number(clean);
1613
- return Number.isFinite(n) ? n : null;
1614
- }
1615
- /**
1616
- * Moeda em centavos inteiros, sem erro de arredondamento de ponto flutuante:
1617
- * "R$ 1.250,50" -> 125050. Vazio -> null. Use centavos para guardar e somar dinheiro.
1618
- */
1619
- function toCents(masked) {
1620
- const d = masked.replace(/\D/g, "");
1621
- if (!d) return null;
1622
- if (!/,\d{1,2}\s*$/.test(masked.replace(/\s*%$/, ""))) return Number(d) * 100;
1623
- const [int = "", dec = ""] = masked.replace(/[^\d,]/g, "").split(",");
1624
- return Number(int || "0") * 100 + Number(dec.padEnd(2, "0").slice(0, 2));
1625
- }
1626
- /** Centavos para o texto do campo de moeda: 125050 -> "R$ 1.250,50". */
1627
- function formatCents(cents) {
1628
- return formatCurrency(cents / 100);
1629
- }
1630
- /** Formata número como moeda brasileira: 1250 -> "R$ 1.250,00". */
1631
- function formatCurrency(value) {
1632
- return value.toLocaleString("pt-BR", {
1633
- style: "currency",
1634
- currency: "BRL"
1635
- });
1636
- }
1637
- //#endregion
1638
- //#region src/components/ui/input.tsx
1639
- /**
1640
- * Input único. Tipos, máscaras, ícone, limpar, senha, unidades e valor guardado são props:
1641
- * nunca crie InputCPF, InputTelefone, InputSenha ou InputSegredo.
1642
- */
1643
- var Input = forwardRef(function Input({ size, mask, icon, suffix, clearable, invalid, type = "text", value, defaultValue, onChange, onValueChange, disabled, className, inputClassName, inputMode, placeholder, ddi: ddiProp, onDdiChange, ddiOptions = phoneCountries, hideDdi, onCentsChange, onLookup, units, unit: unitProp, onUnitChange, percentMax, variant, hasValue, maskedHint, isEditing, onStartEdit, onCancelEdit, onRemove, removing, ...props }, ref) {
1644
- const inputRef = useRef(null);
1645
- useImperativeHandle(ref, () => inputRef.current);
1646
- const maskRef = useRef(null);
1647
- const [showPassword, setShowPassword] = useState(false);
1648
- const [inner, setInner] = useState(String(value ?? defaultValue ?? ""));
1649
- const current = value ?? inner;
1650
- const [secretDraft, setSecretDraft] = useState("");
1651
- const [lastIsEditing, setLastIsEditing] = useState(isEditing);
1652
- if (isEditing !== lastIsEditing) {
1653
- setLastIsEditing(isEditing);
1654
- if (isEditing) setSecretDraft("");
1655
- }
1656
- const cb = useRef({
1657
- onChange,
1658
- onValueChange,
1659
- onCentsChange
1660
- });
1661
- cb.current = {
1662
- onChange,
1663
- onValueChange,
1664
- onCentsChange
1665
- };
1666
- const searching = useLookup(mask === "cep" ? "cep" : mask === "cnpj" ? "cnpj" : mask === "cpfCnpj" ? "auto" : void 0, current, onLookup);
1667
- const isPhone = mask === "phone";
1668
- const [innerDdi, setInnerDdi] = useState(ddiProp ?? "55");
1669
- const ddi = ddiProp ?? innerDdi;
1670
- const showDdi = isPhone && !hideDdi;
1671
- const intl = isPhone && ddi !== "55";
1672
- const hasUnits = Boolean(units && units.length > 0);
1673
- const [innerUnit, setInnerUnit] = useState(unitProp ?? units?.[0]?.id ?? "");
1674
- const unit = hasUnits ? unitProp ?? innerUnit : void 0;
1675
- const unitMaskName = unit === "percent" ? "percent" : unit === "currency" ? "currency" : void 0;
1676
- const def = intl ? internationalPhoneMask : hasUnits ? unitMaskName === "percent" ? percentMask(percentMax) : unitMaskName === "currency" ? masks.currency : void 0 : mask ? masks[mask] : void 0;
1677
- const maskKey = !def ? void 0 : intl ? "phone-intl" : hasUnits ? `unit-${unitMaskName}-${percentMax ?? ""}` : mask;
1678
- useEffect(() => {
1679
- if (!maskKey || !def || !inputRef.current) return;
1680
- const m = IMask(inputRef.current, def.options);
1681
- maskRef.current = m;
1682
- m.on("accept", () => {
1683
- setInner(m.value);
1684
- cb.current.onChange?.(m.value);
1685
- cb.current.onValueChange?.(m.unmaskedValue, m.value);
1686
- if (mask === "currency" || unitMaskName === "currency") cb.current.onCentsChange?.(toCents(m.value));
1687
- });
1688
- return () => {
1689
- m.destroy();
1690
- maskRef.current = null;
1691
- };
1692
- }, [maskKey]);
1693
- useEffect(() => {
1694
- const m = maskRef.current;
1695
- if (m && value !== void 0 && value !== m.value) m.value = value;
1696
- }, [value]);
1697
- const isPassword = type === "password";
1698
- const country = ddiOptions.find((c) => c.ddi === ddi);
1699
- const isSecret = variant === "secret";
1700
- const { id: fieldId, "aria-describedby": fieldDescribedBy, "aria-required": fieldRequired } = props;
1701
- const resetValue = () => {
1702
- if (maskRef.current) maskRef.current.value = "";
1703
- setInner("");
1704
- setSecretDraft("");
1705
- onChange?.("");
1706
- onValueChange?.("", "");
1707
- onCentsChange?.(null);
1708
- };
1709
- const clear = () => {
1710
- resetValue();
1711
- inputRef.current?.focus();
1712
- };
1713
- const changeUnit = (id) => {
1714
- setInnerUnit(id);
1715
- onUnitChange?.(id);
1716
- resetValue();
1717
- };
1718
- if (isSecret && !isEditing) return /* @__PURE__ */ jsxs("div", {
1719
- "data-slot": "control",
1720
- "data-rendra": "CAMP-001",
1721
- className: cn(controlFrame({
1722
- size,
1723
- invalid
1724
- }), className),
1725
- children: [
1726
- /* @__PURE__ */ jsx("span", {
1727
- className: "min-w-0 flex-1 truncate font-mono text-sm text-muted-foreground",
1728
- children: hasValue ? maskedHint ?? "••••••••" : "Nenhum valor salvo"
1729
- }),
1730
- /* @__PURE__ */ jsx(Button, {
1731
- type: "button",
1732
- variant: "ghost",
1733
- size: "sm",
1734
- onClick: onStartEdit,
1735
- disabled,
1736
- id: fieldId,
1737
- "aria-describedby": fieldDescribedBy,
1738
- "aria-required": fieldRequired,
1739
- children: "Trocar"
1740
- }),
1741
- hasValue && onRemove && /* @__PURE__ */ jsx(Button, {
1742
- type: "button",
1743
- variant: "ghost",
1744
- size: "sm",
1745
- onClick: onRemove,
1746
- disabled: disabled || removing,
1747
- loading: removing,
1748
- children: "Remover"
1749
- })
1750
- ]
1751
- });
1752
- return /* @__PURE__ */ jsxs("div", {
1753
- "data-slot": "control",
1754
- "data-rendra": "CAMP-001",
1755
- className: cn(controlFrame({
1756
- size,
1757
- invalid
1758
- }), className),
1759
- children: [
1760
- showDdi && /* @__PURE__ */ jsxs("span", {
1761
- className: "relative -ml-1 flex h-full min-w-touch shrink-0 items-center gap-1 border-r pr-2 text-sm font-medium",
1762
- children: [
1763
- /* @__PURE__ */ jsxs("span", {
1764
- "aria-hidden": true,
1765
- children: ["+", ddi]
1766
- }),
1767
- /* @__PURE__ */ jsx(ChevronDown, {
1768
- className: "size-icon-sm text-muted-foreground",
1769
- "aria-hidden": true
1770
- }),
1771
- /* @__PURE__ */ jsx("select", {
1772
- "aria-label": `Código do país (DDI): ${country?.name ?? ""} +${ddi}`,
1773
- value: ddi,
1774
- disabled,
1775
- onChange: (e) => {
1776
- setInnerDdi(e.target.value);
1777
- onDdiChange?.(e.target.value);
1778
- },
1779
- className: "absolute inset-0 cursor-pointer bg-popover text-popover-foreground opacity-0 disabled:cursor-not-allowed",
1780
- children: ddiOptions.map((c) => /* @__PURE__ */ jsxs("option", {
1781
- value: c.ddi,
1782
- className: "bg-popover text-popover-foreground",
1783
- children: [
1784
- c.name,
1785
- " (+",
1786
- c.ddi,
1787
- ")"
1788
- ]
1789
- }, c.ddi))
1790
- })
1791
- ]
1792
- }),
1793
- icon && /* @__PURE__ */ jsx("span", {
1794
- className: "flex shrink-0 text-muted-foreground [&_svg]:size-icon-sm",
1795
- "aria-hidden": true,
1796
- children: icon
1797
- }),
1798
- /* @__PURE__ */ jsx("input", {
1799
- ref: inputRef,
1800
- type: isSecret ? showPassword ? "text" : "password" : isPassword && showPassword ? "text" : type,
1801
- inputMode: inputMode ?? def?.inputMode,
1802
- placeholder: placeholder ?? def?.placeholder,
1803
- disabled,
1804
- "aria-invalid": invalid || void 0,
1805
- "aria-busy": searching || void 0,
1806
- className: cn(controlInput, inputClassName),
1807
- ...isSecret ? {
1808
- value: secretDraft,
1809
- onChange: (e) => {
1810
- setSecretDraft(e.target.value);
1811
- onChange?.(e.target.value);
1812
- onValueChange?.(e.target.value, e.target.value);
1813
- }
1814
- } : maskKey ? { defaultValue: current } : {
1815
- value: current,
1816
- onChange: (e) => {
1817
- setInner(e.target.value);
1818
- onChange?.(e.target.value);
1819
- onValueChange?.(e.target.value, e.target.value);
1820
- }
1821
- },
1822
- ...props
1823
- }, hasUnits ? `unit-${unit}` : void 0),
1824
- searching && /* @__PURE__ */ jsx(Spinner, {
1825
- size: "sm",
1826
- label: "Buscando…",
1827
- className: "shrink-0 text-muted-foreground"
1828
- }),
1829
- hasUnits && /* @__PURE__ */ jsxs("span", {
1830
- className: "relative -mr-1 flex h-full min-w-touch shrink-0 items-center gap-1 border-l pl-2 text-sm font-medium",
1831
- children: [
1832
- /* @__PURE__ */ jsx("span", {
1833
- "aria-hidden": true,
1834
- children: units?.find((u) => u.id === unit)?.label ?? unit
1835
- }),
1836
- /* @__PURE__ */ jsx(ChevronDown, {
1837
- className: "size-icon-sm text-muted-foreground",
1838
- "aria-hidden": true
1839
- }),
1840
- /* @__PURE__ */ jsx("select", {
1841
- "aria-label": `Unidade: ${units?.find((u) => u.id === unit)?.label ?? unit}`,
1842
- value: unit,
1843
- disabled,
1844
- onChange: (e) => changeUnit(e.target.value),
1845
- className: "absolute inset-0 cursor-pointer bg-popover text-popover-foreground opacity-0 disabled:cursor-not-allowed",
1846
- children: units?.map((u) => /* @__PURE__ */ jsx("option", {
1847
- value: u.id,
1848
- className: "bg-popover text-popover-foreground",
1849
- children: u.label
1850
- }, u.id))
1851
- })
1852
- ]
1853
- }),
1854
- !hasUnits && suffix && /* @__PURE__ */ jsx("span", {
1855
- className: "shrink-0 text-sm text-muted-foreground",
1856
- children: suffix
1857
- }),
1858
- clearable && (isSecret ? secretDraft : current) && !disabled && /* @__PURE__ */ jsx("button", {
1859
- type: "button",
1860
- onClick: clear,
1861
- "aria-label": "Limpar campo",
1862
- className: "-mr-2 flex size-control-sm shrink-0 cursor-pointer items-center justify-center rounded-item text-muted-foreground transition-colors outline-none hover:bg-accent hover:text-foreground focus-visible:ring-2 focus-visible:ring-ring md:-mr-1 md:size-8 [&_svg]:size-icon-sm",
1863
- children: /* @__PURE__ */ jsx(X, { "aria-hidden": true })
1864
- }),
1865
- (isPassword || isSecret) && /* @__PURE__ */ jsx("button", {
1866
- type: "button",
1867
- onClick: () => setShowPassword((s) => !s),
1868
- "aria-label": showPassword ? "Ocultar senha" : "Mostrar senha",
1869
- "aria-pressed": showPassword,
1870
- className: "-mr-2 flex size-control-sm shrink-0 cursor-pointer items-center justify-center rounded-item text-muted-foreground transition-colors outline-none hover:bg-accent hover:text-foreground focus-visible:ring-2 focus-visible:ring-ring md:-mr-1 md:size-8 [&_svg]:size-icon-sm",
1871
- children: showPassword ? /* @__PURE__ */ jsx(EyeOff, { "aria-hidden": true }) : /* @__PURE__ */ jsx(Eye, { "aria-hidden": true })
1872
- }),
1873
- isSecret && /* @__PURE__ */ jsx(Button, {
1874
- type: "button",
1875
- variant: "ghost",
1876
- size: "sm",
1877
- onClick: onCancelEdit,
1878
- disabled,
1879
- children: "Cancelar"
1880
- })
1881
- ]
1882
- });
1883
- });
1884
- //#endregion
1885
936
  //#region src/components/ui/popover.tsx
1886
937
  var PopoverOpenContext = createContext(null);
1887
938
  function AnimatedRoot({ open, defaultOpen, onOpenChange, ...rest }) {
@@ -3424,276 +2475,62 @@ function createPalette(seeds) {
3424
2475
  "--rendra-card": cardD,
3425
2476
  "--rendra-card-foreground": fgD,
3426
2477
  "--rendra-popover": popD,
3427
- "--rendra-popover-foreground": fgD,
3428
- "--rendra-muted": mutedD,
3429
- "--rendra-muted-foreground": reach(mix(fgD, mutedD, .35), mutedD, 4.5, "light"),
3430
- "--rendra-border": mix(cardD, WHITE$1, .12),
3431
- "--rendra-input": reach(mix(cardD, WHITE$1, .32), cardD, 3, "light"),
3432
- "--rendra-field": mix(g2, BLACK$1, .1),
3433
- "--rendra-overlay": alpha(mix(g2, BLACK$1, .6), .7),
3434
- ...brandDark,
3435
- "--rendra-primary-soft": softD,
3436
- "--rendra-primary-soft-foreground": reach(mix(P, WHITE$1, .45), softD, 4.5, "light"),
3437
- "--rendra-primary-text": textD,
3438
- "--rendra-ring": textD,
3439
- "--rendra-accent": mix(cardD, WHITE$1, .06),
3440
- "--rendra-accent-foreground": fgD,
3441
- ...sidebar,
3442
- "--rendra-sidebar": mix(g2, BLACK$1, .1),
3443
- "--rendra-gradient-soft": `linear-gradient(135deg, ${softD} 0%, ${cardD} 65%)`,
3444
- "--rendra-chart-1": reach(P, cardD, 3, "light"),
3445
- "--rendra-chart-2": reach(S, cardD, 3, "light"),
3446
- "--rendra-chart-3": mix(P, WHITE$1, .45),
3447
- "--rendra-chart-4": mix(P, WHITE$1, .72),
3448
- "--rendra-chart-5": reach(mix(S, WHITE$1, .3), cardD, 3, "light"),
3449
- "--rendra-shadow-color": "0 0 0"
3450
- },
3451
- sidebarLogo: sidebarDark ? "dark" : "light",
3452
- adjustments: notes
3453
- };
3454
- }
3455
- var block$1 = (selector, vars) => `${selector} {\n${Object.entries(vars).map(([k, v]) => ` ${k}: ${v};`).join("\n")}\n}\n`;
3456
- /**
3457
- * CSS da paleta. `isDefault` também aplica a paleta quando o <html> ainda não tem
3458
- * data-palette (primeira pintura).
3459
- */
3460
- function paletteCss(palette, isDefault = false) {
3461
- const id = palette.seeds.id;
3462
- const light = isDefault ? `:root:not([data-palette]),\n:root[data-palette='${id}']` : `:root[data-palette='${id}']`;
3463
- const dark = isDefault ? `:root:not([data-palette]).dark,\n:root[data-palette='${id}'].dark` : `:root[data-palette='${id}'].dark`;
3464
- const notes = palette.adjustments.length ? `/* Ajustes de contraste: ${palette.adjustments.join("; ")}. */\n` : "";
3465
- return `/* ${palette.seeds.name} */\n${notes}${block$1(light, palette.light)}\n${block$1(dark, palette.dark)}`;
3466
- }
3467
- /**
3468
- * White label em tempo de execução: gera a paleta de um cliente e a injeta na página
3469
- * (um <style> por paleta), sem build. Depois é só usar data-palette com o id dela.
3470
- * Devolve a paleta gerada, com os ajustes de contraste feitos.
3471
- */
3472
- function applyPalette(seeds, doc = document) {
3473
- const palette = createPalette(seeds);
3474
- const attr = "data-palette-runtime";
3475
- let style = doc.head.querySelector(`style[${attr}="${seeds.id}"]`);
3476
- if (!style) {
3477
- style = doc.createElement("style");
3478
- style.setAttribute(attr, seeds.id);
3479
- doc.head.appendChild(style);
3480
- }
3481
- style.textContent = paletteCss(palette);
3482
- return palette;
3483
- }
3484
- //#endregion
3485
- //#region src/components/ui/picker-panel.tsx
3486
- /** A folha fecha se o arraste passou de 40% da altura ou se foi um arremesso (> 0,11 px/ms). */
3487
- var DISMISS_FRACTION = .4;
3488
- var DISMISS_VELOCITY = 110;
3489
- /**
3490
- * A folha do celular em `on`: entra de baixo, acompanha o dedo (arraste vertical pela alça, com
3491
- * fricção ao puxar para cima), fecha por distância ou por arremesso e, se o dedo solta antes
3492
- * disso, volta à origem com a mola da folha (a velocidade do dedo entra na mola, sem costura). O
3493
- * fundo escurecido acompanha a distância. Só a alça arrasta: o corpo rola sem disputar o gesto.
3494
- * Nenhum valor passa por `style`: o Motion guarda a posição do arraste, e o escurecimento do
3495
- * fundo é gravado direto no elemento (sem render por quadro).
3496
- */
3497
- function MobileSheet({ open, onOpenChange, trigger, adornment, head, rest }) {
3498
- const { AnimatePresence, animate, m, useDragControls } = useMotionOn();
3499
- const presets = useMotionPresets();
3500
- const ready = useLayoutReady();
3501
- const controls = useDragControls();
3502
- const sheetRef = useRef(null);
3503
- const dimRef = useRef(null);
3504
- const height = useRef(1);
3505
- return /* @__PURE__ */ jsxs(Dialog.Root, {
3506
- open,
3507
- onOpenChange,
3508
- children: [/* @__PURE__ */ jsx(Anchor, {
3509
- adornment,
3510
- children: /* @__PURE__ */ jsx(Dialog.Trigger, {
3511
- asChild: true,
3512
- children: trigger
3513
- })
3514
- }), /* @__PURE__ */ jsx(AnimatePresence, { children: open && /* @__PURE__ */ jsxs(Dialog.Portal, {
3515
- forceMount: true,
3516
- children: [/* @__PURE__ */ jsx(Dialog.Overlay, {
3517
- forceMount: true,
3518
- asChild: true,
3519
- children: /* @__PURE__ */ jsx(m.div, {
3520
- className: "fixed inset-0 z-40",
3521
- ...presets.fade,
3522
- children: /* @__PURE__ */ jsx("div", {
3523
- ref: dimRef,
3524
- className: "absolute inset-0 bg-overlay"
3525
- })
3526
- })
3527
- }), /* @__PURE__ */ jsx(Dialog.Content, {
3528
- forceMount: true,
3529
- asChild: true,
3530
- "aria-describedby": void 0,
3531
- className: "fixed inset-x-0 bottom-0 z-50 flex max-h-sheet flex-col rounded-t-surface border-t bg-popover text-popover-foreground shadow-lg outline-none",
3532
- children: /* @__PURE__ */ jsxs(m.div, {
3533
- ref: sheetRef,
3534
- ...presets.sheet("bottom"),
3535
- drag: ready ? "y" : false,
3536
- dragControls: controls,
3537
- dragListener: false,
3538
- dragConstraints: { top: 0 },
3539
- dragElastic: {
3540
- top: .2,
3541
- bottom: 0
3542
- },
3543
- dragSnapToOrigin: true,
3544
- dragTransition: presets.sheetBounce,
3545
- onDragStart: () => {
3546
- height.current = sheetRef.current?.offsetHeight || 1;
3547
- },
3548
- onDrag: (_, info) => {
3549
- const dim = dimRef.current;
3550
- if (dim) dim.style.opacity = String(1 - Math.min(1, Math.max(0, info.offset.y / height.current)));
3551
- },
3552
- onDragEnd: (_, info) => {
3553
- if (info.offset.y > height.current * DISMISS_FRACTION || info.velocity.y > DISMISS_VELOCITY) {
3554
- onOpenChange(false);
3555
- return;
3556
- }
3557
- if (dimRef.current) animate(dimRef.current, { opacity: 1 }, presets.springSheet);
3558
- },
3559
- children: [/* @__PURE__ */ jsx("div", {
3560
- "data-sheet-handle": true,
3561
- onPointerDown: (e) => controls.start(e),
3562
- className: "touch-none",
3563
- children: head
3564
- }), rest]
3565
- })
3566
- })]
3567
- }, "sheet") })]
3568
- });
3569
- }
3570
- function Anchor({ adornment, children }) {
3571
- if (!adornment) return children;
3572
- return /* @__PURE__ */ jsxs("div", {
3573
- className: "relative w-full min-w-0",
3574
- children: [children, adornment]
3575
- });
3576
- }
3577
- function PickerPanel({ open, onOpenChange, trigger, title, header, children, footer, width = "trigger", adornment, align = "start" }) {
3578
- const { isMobile } = useBreakpoint();
3579
- const lib = useMotionLib();
3580
- const presets = useMotionPresets();
3581
- const on = lib !== null;
3582
- const sheetHead = /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx("div", {
3583
- className: "flex shrink-0 flex-col items-center pt-2",
3584
- children: /* @__PURE__ */ jsx("span", {
3585
- "aria-hidden": true,
3586
- className: "h-1 w-12 rounded-full bg-border"
3587
- })
3588
- }), /* @__PURE__ */ jsxs("div", {
3589
- className: "flex shrink-0 items-center justify-between gap-2 pr-2 pl-4",
3590
- children: [/* @__PURE__ */ jsx(Dialog.Title, {
3591
- className: "truncate text-base font-semibold",
3592
- children: title
3593
- }), /* @__PURE__ */ jsx(Dialog.Close, {
3594
- "aria-label": "Fechar",
3595
- className: "flex size-touch items-center justify-center rounded-item text-muted-foreground hover:bg-accent",
3596
- children: /* @__PURE__ */ jsx(X, {
3597
- className: "size-icon-md",
3598
- "aria-hidden": true
3599
- })
3600
- })]
3601
- })] });
3602
- const sheetRest = /* @__PURE__ */ jsxs(Fragment$1, { children: [
3603
- header && /* @__PURE__ */ jsx("div", {
3604
- className: "shrink-0 border-b px-4 pb-3",
3605
- children: header
3606
- }),
3607
- /* @__PURE__ */ jsx("div", {
3608
- className: "min-h-0 flex-1 overflow-y-auto overscroll-contain p-2",
3609
- children
3610
- }),
3611
- footer && /* @__PURE__ */ jsx("div", {
3612
- className: "shrink-0 border-t px-4 pt-3 pb-safe",
3613
- children: footer
3614
- })
3615
- ] });
3616
- const sheetBody = /* @__PURE__ */ jsxs(Fragment$1, { children: [sheetHead, sheetRest] });
3617
- const panelCls = cn("z-50 flex max-h-command origin-(--radix-popover-content-transform-origin) flex-col overflow-hidden rounded-surface border bg-popover text-popover-foreground shadow-md outline-none", width === "trigger" ? "w-trigger max-w-popover" : "w-auto max-w-popover md:max-w-none");
3618
- const panelBody = /* @__PURE__ */ jsxs(Fragment$1, { children: [
3619
- header && /* @__PURE__ */ jsx("div", {
3620
- className: "shrink-0 border-b p-2",
3621
- children: header
3622
- }),
3623
- /* @__PURE__ */ jsx("div", {
3624
- className: "min-h-0 flex-1 overflow-y-auto overscroll-contain p-1",
3625
- children
3626
- }),
3627
- footer && /* @__PURE__ */ jsx("div", {
3628
- className: "shrink-0 border-t p-2",
3629
- children: footer
3630
- })
3631
- ] });
3632
- if (on && isMobile) return /* @__PURE__ */ jsx(MobileSheet, {
3633
- open,
3634
- onOpenChange,
3635
- trigger,
3636
- adornment,
3637
- head: sheetHead,
3638
- rest: sheetRest
3639
- });
3640
- if (on) return /* @__PURE__ */ jsxs(Popover$1.Root, {
3641
- open,
3642
- onOpenChange,
3643
- children: [/* @__PURE__ */ jsx(Anchor, {
3644
- adornment,
3645
- children: /* @__PURE__ */ jsx(Popover$1.Trigger, {
3646
- asChild: true,
3647
- children: trigger
3648
- })
3649
- }), /* @__PURE__ */ jsx(lib.AnimatePresence, { children: open && /* @__PURE__ */ jsx(Popover$1.Portal, {
3650
- forceMount: true,
3651
- children: /* @__PURE__ */ jsx(Popover$1.Content, {
3652
- forceMount: true,
3653
- asChild: true,
3654
- align,
3655
- sideOffset: 6,
3656
- collisionPadding: 16,
3657
- className: panelCls,
3658
- children: /* @__PURE__ */ jsx(lib.m.div, {
3659
- ...presets.open(),
3660
- children: panelBody
3661
- })
3662
- })
3663
- }, "panel") })]
3664
- });
3665
- if (isMobile) return /* @__PURE__ */ jsxs(Dialog.Root, {
3666
- open,
3667
- onOpenChange,
3668
- children: [/* @__PURE__ */ jsx(Anchor, {
3669
- adornment,
3670
- children: /* @__PURE__ */ jsx(Dialog.Trigger, {
3671
- asChild: true,
3672
- children: trigger
3673
- })
3674
- }), /* @__PURE__ */ jsxs(Dialog.Portal, { children: [/* @__PURE__ */ jsx(Dialog.Overlay, { className: "fixed inset-0 z-40 bg-overlay data-[state=closed]:animate-out data-[state=closed]:duration-(--rendra-duration-fast) data-[state=closed]:fade-out-0 data-[state=open]:animate-in data-[state=open]:fade-in-0" }), /* @__PURE__ */ jsx(Dialog.Content, {
3675
- "aria-describedby": void 0,
3676
- className: "fixed inset-x-0 bottom-0 z-50 flex max-h-sheet flex-col rounded-t-surface border-t bg-popover text-popover-foreground shadow-lg outline-none data-[state=closed]:animate-out data-[state=closed]:duration-(--rendra-duration-fast) data-[state=closed]:slide-out-to-bottom data-[state=open]:animate-in data-[state=open]:slide-in-from-bottom",
3677
- children: sheetBody
3678
- })] })]
3679
- });
3680
- return /* @__PURE__ */ jsxs(Popover$1.Root, {
3681
- open,
3682
- onOpenChange,
3683
- children: [/* @__PURE__ */ jsx(Anchor, {
3684
- adornment,
3685
- children: /* @__PURE__ */ jsx(Popover$1.Trigger, {
3686
- asChild: true,
3687
- children: trigger
3688
- })
3689
- }), /* @__PURE__ */ jsx(Popover$1.Portal, { children: /* @__PURE__ */ jsx(Popover$1.Content, {
3690
- align,
3691
- sideOffset: 6,
3692
- collisionPadding: 16,
3693
- className: cn("z-50 flex max-h-command origin-(--radix-popover-content-transform-origin) flex-col overflow-hidden rounded-surface border bg-popover text-popover-foreground shadow-md outline-none", "data-[state=closed]:animate-out data-[state=closed]:duration-(--rendra-duration-fast) data-[state=closed]:fade-out-0 data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95", width === "trigger" ? "w-trigger max-w-popover" : "w-auto max-w-popover md:max-w-none"),
3694
- children: panelBody
3695
- }) })]
3696
- });
2478
+ "--rendra-popover-foreground": fgD,
2479
+ "--rendra-muted": mutedD,
2480
+ "--rendra-muted-foreground": reach(mix(fgD, mutedD, .35), mutedD, 4.5, "light"),
2481
+ "--rendra-border": mix(cardD, WHITE$1, .12),
2482
+ "--rendra-input": reach(mix(cardD, WHITE$1, .32), cardD, 3, "light"),
2483
+ "--rendra-field": mix(g2, BLACK$1, .1),
2484
+ "--rendra-overlay": alpha(mix(g2, BLACK$1, .6), .7),
2485
+ ...brandDark,
2486
+ "--rendra-primary-soft": softD,
2487
+ "--rendra-primary-soft-foreground": reach(mix(P, WHITE$1, .45), softD, 4.5, "light"),
2488
+ "--rendra-primary-text": textD,
2489
+ "--rendra-ring": textD,
2490
+ "--rendra-accent": mix(cardD, WHITE$1, .06),
2491
+ "--rendra-accent-foreground": fgD,
2492
+ ...sidebar,
2493
+ "--rendra-sidebar": mix(g2, BLACK$1, .1),
2494
+ "--rendra-gradient-soft": `linear-gradient(135deg, ${softD} 0%, ${cardD} 65%)`,
2495
+ "--rendra-chart-1": reach(P, cardD, 3, "light"),
2496
+ "--rendra-chart-2": reach(S, cardD, 3, "light"),
2497
+ "--rendra-chart-3": mix(P, WHITE$1, .45),
2498
+ "--rendra-chart-4": mix(P, WHITE$1, .72),
2499
+ "--rendra-chart-5": reach(mix(S, WHITE$1, .3), cardD, 3, "light"),
2500
+ "--rendra-shadow-color": "0 0 0"
2501
+ },
2502
+ sidebarLogo: sidebarDark ? "dark" : "light",
2503
+ adjustments: notes
2504
+ };
2505
+ }
2506
+ var block$1 = (selector, vars) => `${selector} {\n${Object.entries(vars).map(([k, v]) => ` ${k}: ${v};`).join("\n")}\n}\n`;
2507
+ /**
2508
+ * CSS da paleta. `isDefault` também aplica a paleta quando o <html> ainda não tem
2509
+ * data-palette (primeira pintura).
2510
+ */
2511
+ function paletteCss(palette, isDefault = false) {
2512
+ const id = palette.seeds.id;
2513
+ const light = isDefault ? `:root:not([data-palette]),\n:root[data-palette='${id}']` : `:root[data-palette='${id}']`;
2514
+ const dark = isDefault ? `:root:not([data-palette]).dark,\n:root[data-palette='${id}'].dark` : `:root[data-palette='${id}'].dark`;
2515
+ const notes = palette.adjustments.length ? `/* Ajustes de contraste: ${palette.adjustments.join("; ")}. */\n` : "";
2516
+ return `/* ${palette.seeds.name} */\n${notes}${block$1(light, palette.light)}\n${block$1(dark, palette.dark)}`;
2517
+ }
2518
+ /**
2519
+ * White label em tempo de execução: gera a paleta de um cliente e a injeta na página
2520
+ * (um <style> por paleta), sem build. Depois é só usar data-palette com o id dela.
2521
+ * Devolve a paleta gerada, com os ajustes de contraste feitos.
2522
+ */
2523
+ function applyPalette(seeds, doc = document) {
2524
+ const palette = createPalette(seeds);
2525
+ const attr = "data-palette-runtime";
2526
+ let style = doc.head.querySelector(`style[${attr}="${seeds.id}"]`);
2527
+ if (!style) {
2528
+ style = doc.createElement("style");
2529
+ style.setAttribute(attr, seeds.id);
2530
+ doc.head.appendChild(style);
2531
+ }
2532
+ style.textContent = paletteCss(palette);
2533
+ return palette;
3697
2534
  }
3698
2535
  //#endregion
3699
2536
  //#region src/components/ui/color-picker.tsx
@@ -3790,82 +2627,6 @@ var ColorPicker = forwardRef(function ColorPicker({ value, onChange, swatches =
3790
2627
  });
3791
2628
  });
3792
2629
  //#endregion
3793
- //#region src/components/ui/drawer.tsx
3794
- var sizes = {
3795
- "30": "md:w-sheet-30",
3796
- "40": "md:w-sheet-40",
3797
- "50": "md:w-sheet-50",
3798
- "75": "md:w-sheet-75",
3799
- full: "md:w-full",
3800
- sm: "md:w-sheet-30",
3801
- md: "md:w-sheet-30",
3802
- lg: "md:w-sheet-50",
3803
- xl: "md:w-sheet-75"
3804
- };
3805
- var overlayCls = "fixed inset-0 z-50 bg-overlay";
3806
- var panelCls = "fixed inset-y-0 right-0 z-50 flex h-dvh w-full flex-col bg-card text-card-foreground shadow-lg outline-none md:border-l";
3807
- function Drawer({ open, onOpenChange, title, description, icon, size = "30", children, footer, dirty, discardTitle = "Descartar alterações?", discardDescription = "As informações preenchidas neste painel serão perdidas." }) {
3808
- const [confirming, setConfirming] = useState(false);
3809
- const requestClose = () => dirty ? setConfirming(true) : onOpenChange(false);
3810
- const lib = useMotionLib();
3811
- const presets = useMotionPresets();
3812
- const keepOpenIfDirty = (e) => {
3813
- if (dirty) {
3814
- e.preventDefault();
3815
- setConfirming(true);
3816
- }
3817
- };
3818
- const shell = /* @__PURE__ */ jsx(OverlayShell, {
3819
- title,
3820
- description,
3821
- icon,
3822
- footer,
3823
- onRequestClose: requestClose,
3824
- children
3825
- });
3826
- return /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx(Dialog.Root, {
3827
- open,
3828
- onOpenChange: (o) => o ? onOpenChange(true) : requestClose(),
3829
- children: lib ? /* @__PURE__ */ jsx(lib.AnimatePresence, { children: open && /* @__PURE__ */ jsxs(Dialog.Portal, {
3830
- forceMount: true,
3831
- children: [/* @__PURE__ */ jsx(Dialog.Overlay, {
3832
- forceMount: true,
3833
- asChild: true,
3834
- children: /* @__PURE__ */ jsx(lib.m.div, {
3835
- className: overlayCls,
3836
- ...presets.fade
3837
- })
3838
- }), /* @__PURE__ */ jsx(Dialog.Content, {
3839
- forceMount: true,
3840
- asChild: true,
3841
- onEscapeKeyDown: keepOpenIfDirty,
3842
- onPointerDownOutside: keepOpenIfDirty,
3843
- "data-rendra": "GAV-001",
3844
- className: cn(panelCls, sizes[size]),
3845
- children: /* @__PURE__ */ jsx(lib.m.div, {
3846
- ...presets.sheet("right"),
3847
- children: shell
3848
- })
3849
- })]
3850
- }, "drawer") }) : /* @__PURE__ */ jsxs(Dialog.Portal, { children: [/* @__PURE__ */ jsx(Dialog.Overlay, { className: cn(overlayCls, "data-[state=closed]:animate-out data-[state=closed]:duration-(--rendra-duration-fast) data-[state=closed]:fade-out-0 data-[state=open]:animate-in data-[state=open]:fade-in-0") }), /* @__PURE__ */ jsx(Dialog.Content, {
3851
- onEscapeKeyDown: keepOpenIfDirty,
3852
- onPointerDownOutside: keepOpenIfDirty,
3853
- "data-rendra": "GAV-001",
3854
- className: cn(panelCls, "data-[state=closed]:animate-out data-[state=closed]:duration-(--rendra-duration-fast) data-[state=closed]:slide-out-to-right data-[state=open]:animate-in data-[state=open]:slide-in-from-right", sizes[size]),
3855
- children: shell
3856
- })] })
3857
- }), /* @__PURE__ */ jsx(Modal, {
3858
- open: confirming,
3859
- onOpenChange: setConfirming,
3860
- type: "destructive",
3861
- title: discardTitle,
3862
- description: discardDescription,
3863
- confirmLabel: "Descartar",
3864
- cancelLabel: "Continuar editando",
3865
- onConfirm: () => onOpenChange(false)
3866
- })] });
3867
- }
3868
- //#endregion
3869
2630
  //#region src/components/ui/switch.tsx
3870
2631
  /** Switch único, com rótulo e descrição à esquerda e a chave à direita. */
3871
2632
  function Switch({ checked, defaultChecked, onCheckedChange, label, description, disabled, id, name, className, ...aria }) {
@@ -4087,121 +2848,6 @@ function DataToolbar({ search, filters, filterCount = 0, onClearFilters, chips =
4087
2848
  });
4088
2849
  }
4089
2850
  //#endregion
4090
- //#region src/components/layout/tokens.ts
4091
- var gapClass = {
4092
- "0": "gap-0",
4093
- "1": "gap-1",
4094
- "2": "gap-2",
4095
- "3": "gap-3",
4096
- "4": "gap-4",
4097
- "6": "gap-6",
4098
- "8": "gap-8",
4099
- "12": "gap-12",
4100
- "16": "gap-16",
4101
- "24": "gap-24",
4102
- section: "gap-8 md:gap-12",
4103
- fields: "gap-x-4 gap-y-4 md:gap-x-6"
4104
- };
4105
- /**
4106
- * Grade de formulário, pela largura do próprio bloco (container query), não da tela:
4107
- * 1 coluna estreito, 6 colunas a partir de 28rem, 12 colunas a partir de 48rem.
4108
- * No largo, o padrão é 3 campos por linha (md = 4/12). Nunca 2 por linha por padrão.
4109
- */
4110
- var fieldGridClass = "grid grid-cols-1 @md:grid-cols-6 @3xl:grid-cols-12";
4111
- /** Largura do Field na grade de formulário (no largo, em 12 colunas). */
4112
- var fieldSpanClass = {
4113
- /** 2/12, cerca de 17%: UF, número, DDD. */
4114
- xs: "@md:col-span-2 @3xl:col-span-2",
4115
- /** 3/12 = 25%: CEP, CNPJ, CPF, datas curtas. */
4116
- sm: "@md:col-span-2 @3xl:col-span-3",
4117
- /** 4/12 = 33%: o padrão, 3 campos por linha. */
4118
- md: "@md:col-span-3 @3xl:col-span-4",
4119
- /** 6/12 = 50%. */
4120
- lg: "@md:col-span-3 @3xl:col-span-6",
4121
- /** 8/12 = 67%: nome, logradouro longo. */
4122
- xl: "@md:col-span-6 @3xl:col-span-8",
4123
- /** Linha inteira. */
4124
- full: "@md:col-span-6 @3xl:col-span-12"
4125
- };
4126
- var alignClass = {
4127
- start: "items-start",
4128
- center: "items-center",
4129
- end: "items-end",
4130
- stretch: "items-stretch",
4131
- baseline: "items-baseline"
4132
- };
4133
- var justifyClass = {
4134
- start: "justify-start",
4135
- center: "justify-center",
4136
- end: "justify-end",
4137
- between: "justify-between"
4138
- };
4139
- //#endregion
4140
- //#region src/components/ui/field.tsx
4141
- function Label({ className, required, children, ...props }) {
4142
- return /* @__PURE__ */ jsxs(Label$1.Root, {
4143
- "data-rendra": "FLD-002",
4144
- className: cn("text-label text-label-foreground label-case", className),
4145
- ...props,
4146
- children: [
4147
- children,
4148
- required && /* @__PURE__ */ jsxs("span", {
4149
- className: "text-destructive",
4150
- "aria-hidden": true,
4151
- children: [" ", "*"]
4152
- }),
4153
- required && /* @__PURE__ */ jsx("span", {
4154
- className: "sr-only",
4155
- children: " (obrigatório)"
4156
- })
4157
- ]
4158
- });
4159
- }
4160
- var FieldContext = createContext(null);
4161
- /** Liga um controle ao Field mais próximo (id, aria-describedby, aria-invalid). */
4162
- function useFieldControl() {
4163
- return useContext(FieldContext);
4164
- }
4165
- function Field({ label, required, help, error, span = "md", newRow, reserveMessage = false, id, className, children }) {
4166
- const auto = useId();
4167
- const controlId = id ?? `campo${auto}`;
4168
- const messageId = `${controlId}-mensagem`;
4169
- const invalid = Boolean(error);
4170
- const message = error ?? help;
4171
- const child = isValidElement(children) && typeof children.type !== "string" ? cloneElement(children, {
4172
- id: children.props.id ?? controlId,
4173
- ...invalid ? { invalid: children.props.invalid ?? true } : {},
4174
- "aria-describedby": message ? messageId : void 0,
4175
- "aria-required": required || void 0
4176
- }) : children;
4177
- return /* @__PURE__ */ jsx(FieldContext.Provider, {
4178
- value: {
4179
- id: controlId,
4180
- describedBy: message ? messageId : "",
4181
- invalid
4182
- },
4183
- children: /* @__PURE__ */ jsxs("div", {
4184
- "data-slot": "field",
4185
- "data-rendra": "FLD-001",
4186
- className: cn("flex min-w-0 flex-col gap-2", fieldSpanClass[span === "half" ? "md" : span], newRow && "@md:col-start-1 @3xl:col-start-1", className),
4187
- children: [
4188
- label && /* @__PURE__ */ jsx(Label, {
4189
- htmlFor: controlId,
4190
- required,
4191
- children: label
4192
- }),
4193
- child,
4194
- (reserveMessage || message) && /* @__PURE__ */ jsx("p", {
4195
- id: messageId,
4196
- role: invalid ? "alert" : void 0,
4197
- className: cn("-mt-1 min-h-4 text-help", invalid ? "font-medium text-destructive" : "text-help-foreground"),
4198
- children: message
4199
- })
4200
- ]
4201
- })
4202
- });
4203
- }
4204
- //#endregion
4205
2851
  //#region src/components/ui/date-picker.tsx
4206
2852
  var fmtDate = (d) => format(d, "dd/MM/yyyy");
4207
2853
  var fmtTime = (d) => format(d, "HH:mm");
@@ -4584,318 +3230,6 @@ function Slider({ value, defaultValue = [50], onChange, min = 0, max = 100, step
4584
3230
  });
4585
3231
  }
4586
3232
  //#endregion
4587
- //#region src/components/ui/select.tsx
4588
- /** Acima deste número de opções, o "Selecionar todos" aparece sem a prop `selectAll`. */
4589
- var SELECT_ALL_AUTO_MIN = 5;
4590
- /**
4591
- * Select único do sistema. Busca, múltiplo, selecionar todos, contador, criar opção,
4592
- * busca remota e carregamento são props. No mobile abre como bottom sheet.
4593
- */
4594
- var Select = forwardRef(function Select(props, ref) {
4595
- const { options: staticOptions = [], placeholder = "Selecione", label, size, invalid, disabled, searchable, creatable, onCreate, loadOptions, loading, clearable, emptyText = "Nenhuma opção encontrada.", id, className } = props;
4596
- const multiple = props.multiple === true;
4597
- const { isMobile } = useBreakpoint();
4598
- const [open, setOpen] = useState(false);
4599
- const listId = `${useId()}-lista`;
4600
- const [query, setQuery] = useState("");
4601
- const [remote, setRemote] = useState(null);
4602
- const [remoteLoading, setRemoteLoading] = useState(false);
4603
- const [created, setCreated] = useState([]);
4604
- const [innerSingle, setInnerSingle] = useState(null);
4605
- const [innerMulti, setInnerMulti] = useState([]);
4606
- const [draft, setDraft] = useState([]);
4607
- const selectedSingle = multiple ? null : props.value ?? innerSingle;
4608
- const selectedMulti = multiple ? props.value ?? innerMulti : [];
4609
- const seq = useRef(0);
4610
- useEffect(() => {
4611
- if (!loadOptions || !open) return;
4612
- const n = ++seq.current;
4613
- setRemoteLoading(true);
4614
- const t = window.setTimeout(async () => {
4615
- const res = await loadOptions(query);
4616
- if (n === seq.current) {
4617
- setRemote(res);
4618
- setRemoteLoading(false);
4619
- }
4620
- }, 250);
4621
- return () => window.clearTimeout(t);
4622
- }, [
4623
- loadOptions,
4624
- query,
4625
- open
4626
- ]);
4627
- const all = useMemo(() => {
4628
- const base = remote ?? staticOptions;
4629
- const map = /* @__PURE__ */ new Map();
4630
- [...base, ...created].forEach((o) => map.set(o.value, o));
4631
- return [...map.values()];
4632
- }, [
4633
- remote,
4634
- staticOptions,
4635
- created
4636
- ]);
4637
- const byValue = (v) => all.find((o) => o.value === v);
4638
- const isSearchable = searchable || creatable || Boolean(loadOptions);
4639
- const busy = loading || remoteLoading;
4640
- const multiValue = isMobile && multiple ? draft : selectedMulti;
4641
- const commitSingle = (v) => {
4642
- setInnerSingle(v);
4643
- props.onChange?.(v);
4644
- };
4645
- const commitMulti = (v) => {
4646
- setInnerMulti(v);
4647
- props.onChange?.(v);
4648
- };
4649
- const toggle = (v) => {
4650
- if (!multiple) {
4651
- commitSingle(v);
4652
- setOpen(false);
4653
- return;
4654
- }
4655
- const next = multiValue.includes(v) ? multiValue.filter((x) => x !== v) : [...multiValue, v];
4656
- if (isMobile) setDraft(next);
4657
- else commitMulti(next);
4658
- };
4659
- const enabled = all.filter((o) => !o.disabled);
4660
- const allSelected = enabled.length > 0 && enabled.every((o) => multiValue.includes(o.value));
4661
- const showSelectAll = multiple && (props.selectAll ?? all.length > SELECT_ALL_AUTO_MIN);
4662
- const toggleAll = () => {
4663
- const next = allSelected ? [] : enabled.map((o) => o.value);
4664
- if (isMobile) setDraft(next);
4665
- else commitMulti(next);
4666
- };
4667
- const create = async () => {
4668
- const text = query.trim();
4669
- if (!text) return;
4670
- const opt = onCreate ? await onCreate(text) : {
4671
- value: text,
4672
- label: text
4673
- };
4674
- setCreated((c) => [...c, opt]);
4675
- setQuery("");
4676
- toggle(opt.value);
4677
- };
4678
- const onOpenChange = (o) => {
4679
- setOpen(o);
4680
- if (o) setDraft(selectedMulti);
4681
- else setQuery("");
4682
- };
4683
- const hasValue = multiple ? selectedMulti.length > 0 : selectedSingle != null;
4684
- const maxChips = props.maxChips ?? 2;
4685
- let display = /* @__PURE__ */ jsx("span", {
4686
- className: "truncate text-muted-foreground",
4687
- children: placeholder
4688
- });
4689
- if (!multiple && selectedSingle != null) {
4690
- const o = byValue(selectedSingle);
4691
- display = /* @__PURE__ */ jsxs("span", {
4692
- className: "flex min-w-0 items-center gap-2",
4693
- children: [o?.icon, /* @__PURE__ */ jsx("span", {
4694
- className: "truncate",
4695
- children: o?.label ?? selectedSingle
4696
- })]
4697
- });
4698
- } else if (multiple && selectedMulti.length > 0) display = props.showCount ? /* @__PURE__ */ jsxs("span", {
4699
- className: "truncate",
4700
- children: [
4701
- selectedMulti.length,
4702
- " ",
4703
- selectedMulti.length === 1 ? "selecionado" : "selecionados"
4704
- ]
4705
- }) : /* @__PURE__ */ jsxs("span", {
4706
- className: "flex min-w-0 items-center gap-1 overflow-hidden",
4707
- children: [selectedMulti.slice(0, maxChips).map((v) => /* @__PURE__ */ jsx("span", {
4708
- className: "max-w-3xs shrink-0 truncate rounded-item bg-primary-soft px-2 py-1 text-xs leading-none font-medium text-primary-soft-foreground",
4709
- children: byValue(v)?.label ?? v
4710
- }, v)), selectedMulti.length > maxChips && /* @__PURE__ */ jsxs("span", {
4711
- className: "shrink-0 rounded-item bg-muted px-2 py-1 text-xs leading-none font-medium",
4712
- children: ["+", selectedMulti.length - maxChips]
4713
- })]
4714
- });
4715
- const showClear = clearable && hasValue && !disabled;
4716
- const clear = showClear ? /* @__PURE__ */ jsx("button", {
4717
- type: "button",
4718
- "aria-label": "Limpar seleção",
4719
- className: cn(controlAdornmentButton, "absolute top-1/2 right-8 mr-0 -translate-y-1/2 md:mr-0"),
4720
- onClick: () => multiple ? commitMulti([]) : commitSingle(null),
4721
- children: /* @__PURE__ */ jsx(X, { "aria-hidden": true })
4722
- }) : void 0;
4723
- const trigger = /* @__PURE__ */ jsxs("button", {
4724
- ref,
4725
- id,
4726
- type: "button",
4727
- role: "combobox",
4728
- "aria-expanded": open,
4729
- "aria-controls": listId,
4730
- "aria-haspopup": "listbox",
4731
- "aria-invalid": invalid || void 0,
4732
- "aria-describedby": props["aria-describedby"],
4733
- "aria-label": id ? void 0 : label,
4734
- disabled,
4735
- "data-rendra": "SEL-001",
4736
- onKeyDown: (e) => e.stopPropagation(),
4737
- className: cn(controlFrame({
4738
- size,
4739
- invalid
4740
- }), "cursor-pointer text-left disabled:cursor-not-allowed disabled:opacity-60", className),
4741
- children: [
4742
- /* @__PURE__ */ jsx("span", {
4743
- className: "flex min-w-0 flex-1 items-center",
4744
- children: display
4745
- }),
4746
- showClear && /* @__PURE__ */ jsx("span", {
4747
- "aria-hidden": true,
4748
- className: cn("size-control-sm shrink-0 md:size-8", "-mr-1")
4749
- }),
4750
- /* @__PURE__ */ jsx(ChevronDown, {
4751
- "aria-hidden": true,
4752
- className: cn("size-icon-sm shrink-0 text-muted-foreground transition-transform duration-(--rendra-duration-base) ease-move", open && "rotate-180")
4753
- })
4754
- ]
4755
- });
4756
- const groups = all.reduce((acc, o) => {
4757
- (acc[o.group ?? ""] ??= []).push(o);
4758
- return acc;
4759
- }, {});
4760
- const q = query.trim().toLowerCase();
4761
- const showCreate = creatable && q && !all.some((o) => o.label.toLowerCase() === q);
4762
- const itemClass = "relative flex min-h-touch cursor-pointer items-center gap-3 rounded-item px-3 text-sm outline-none select-none data-[disabled=true]:pointer-events-none data-[disabled=true]:opacity-50 data-[selected=true]:bg-accent md:min-h-0 md:py-2";
4763
- const checkbox = (checked) => /* @__PURE__ */ jsx("span", {
4764
- "aria-hidden": true,
4765
- className: cn("flex size-icon-sm shrink-0 items-center justify-center rounded-item border transition-colors", checked ? "border-primary bg-primary text-primary-foreground" : "border-input bg-card"),
4766
- children: checked && /* @__PURE__ */ jsx(Check, {
4767
- className: "size-3",
4768
- strokeWidth: 3
4769
- })
4770
- });
4771
- const list = /* @__PURE__ */ jsxs(Command.List, {
4772
- id: listId,
4773
- "aria-label": label ?? placeholder,
4774
- children: [
4775
- busy && /* @__PURE__ */ jsx(Command.Loading, { children: /* @__PURE__ */ jsxs("div", {
4776
- className: "flex items-center gap-2 px-3 py-4 text-sm text-muted-foreground",
4777
- children: [/* @__PURE__ */ jsx(Spinner, { size: "sm" }), "Carregando opções..."]
4778
- }) }),
4779
- !busy && /* @__PURE__ */ jsx(Command.Empty, {
4780
- className: "px-3 py-6 text-center text-sm text-muted-foreground",
4781
- children: emptyText
4782
- }),
4783
- showCreate && /* @__PURE__ */ jsxs(Command.Item, {
4784
- value: `__criar__${query}`,
4785
- onSelect: create,
4786
- className: itemClass,
4787
- children: [/* @__PURE__ */ jsx(Plus, {
4788
- className: "size-icon-sm shrink-0 text-primary-text",
4789
- "aria-hidden": true
4790
- }), /* @__PURE__ */ jsxs("span", {
4791
- className: "truncate",
4792
- children: ["Criar ", /* @__PURE__ */ jsxs("strong", {
4793
- className: "font-semibold",
4794
- children: [
4795
- "“",
4796
- query.trim(),
4797
- "”"
4798
- ]
4799
- })]
4800
- })]
4801
- }),
4802
- showSelectAll && !q && enabled.length > 0 && /* @__PURE__ */ jsxs(Command.Item, {
4803
- value: "__todos__",
4804
- onSelect: toggleAll,
4805
- className: cn(itemClass, "font-medium"),
4806
- children: [checkbox(allSelected), allSelected ? "Desmarcar todos" : "Selecionar todos"]
4807
- }),
4808
- Object.entries(groups).map(([group, opts]) => /* @__PURE__ */ jsx(Command.Group, {
4809
- heading: group || void 0,
4810
- className: "[&_[cmdk-group-heading]]:px-3 [&_[cmdk-group-heading]]:py-2 [&_[cmdk-group-heading]]:text-xs [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group-heading]]:text-muted-foreground",
4811
- children: opts.map((o) => {
4812
- const checked = multiple ? multiValue.includes(o.value) : selectedSingle === o.value;
4813
- return /* @__PURE__ */ jsxs(Command.Item, {
4814
- value: `${o.label} ${o.description ?? ""} ${o.value}`,
4815
- disabled: o.disabled,
4816
- onSelect: () => toggle(o.value),
4817
- "aria-selected": checked,
4818
- className: itemClass,
4819
- children: [
4820
- multiple && checkbox(checked),
4821
- o.icon && /* @__PURE__ */ jsx("span", {
4822
- className: "flex shrink-0 [&_svg]:size-icon-sm",
4823
- children: o.icon
4824
- }),
4825
- /* @__PURE__ */ jsxs("span", {
4826
- className: "flex min-w-0 flex-1 flex-col",
4827
- children: [/* @__PURE__ */ jsx("span", {
4828
- className: cn("truncate", checked && !multiple && "font-medium"),
4829
- children: o.label
4830
- }), o.description && /* @__PURE__ */ jsx("span", {
4831
- className: "truncate text-xs text-muted-foreground",
4832
- children: o.description
4833
- })]
4834
- }),
4835
- !multiple && checked && /* @__PURE__ */ jsx(Check, {
4836
- className: "size-icon-sm shrink-0 text-primary-text",
4837
- "aria-hidden": true
4838
- })
4839
- ]
4840
- }, o.value);
4841
- })
4842
- }, group || "sem-grupo"))
4843
- ]
4844
- });
4845
- const search = isSearchable ? /* @__PURE__ */ jsxs("div", {
4846
- className: cn(controlFrame({ size: "md" }), "bg-background"),
4847
- children: [/* @__PURE__ */ jsx(Search, {
4848
- className: "size-icon-sm shrink-0 text-muted-foreground",
4849
- "aria-hidden": true
4850
- }), /* @__PURE__ */ jsx(Command.Input, {
4851
- value: query,
4852
- onValueChange: setQuery,
4853
- placeholder: creatable ? "Buscar ou criar..." : "Buscar...",
4854
- className: "h-full min-w-0 flex-1 bg-transparent outline-none placeholder:text-muted-foreground"
4855
- })]
4856
- }) : null;
4857
- const count = multiValue.length;
4858
- const footer = multiple && (isMobile || count > 0) ? /* @__PURE__ */ jsxs("div", {
4859
- className: "grid grid-actions-2 gap-3",
4860
- children: [/* @__PURE__ */ jsx(Button, {
4861
- variant: "outline",
4862
- onClick: () => isMobile ? setDraft([]) : commitMulti([]),
4863
- disabled: count === 0,
4864
- children: "Limpar"
4865
- }), isMobile ? /* @__PURE__ */ jsxs(Button, {
4866
- onClick: () => {
4867
- commitMulti(draft);
4868
- setOpen(false);
4869
- },
4870
- children: ["Aplicar", count ? ` (${count})` : ""]
4871
- }) : /* @__PURE__ */ jsxs(Button, {
4872
- variant: "secondary",
4873
- onClick: () => setOpen(false),
4874
- children: [
4875
- "Pronto (",
4876
- count,
4877
- ")"
4878
- ]
4879
- })]
4880
- }) : void 0;
4881
- return /* @__PURE__ */ jsx(Command, {
4882
- shouldFilter: !loadOptions,
4883
- loop: true,
4884
- className: "contents",
4885
- label: label ?? placeholder,
4886
- children: /* @__PURE__ */ jsx(PickerPanel, {
4887
- open,
4888
- onOpenChange,
4889
- trigger,
4890
- adornment: clear,
4891
- title: label ?? placeholder,
4892
- header: search,
4893
- footer,
4894
- children: list
4895
- })
4896
- });
4897
- });
4898
- //#endregion
4899
3233
  //#region src/components/ui/tabs.tsx
4900
3234
  /** Contador de instâncias, só para o `layoutId` do indicador (ver `indicatorId`). */
4901
3235
  var tabsCreated = 0;
@@ -5458,33 +3792,6 @@ function ImageViewer({ images, index, onIndexChange }) {
5458
3792
  });
5459
3793
  }
5460
3794
  //#endregion
5461
- //#region src/hooks/use-fill-height.ts
5462
- /**
5463
- * Mede o espaço que sobra na área de conteúdo (o <main>) abaixo do elemento e grava em
5464
- * --board-h. Com a classe h-board, o elemento ocupa exatamente essa altura: a página não
5465
- * rola e a rolagem acontece dentro dele (kanban, chat).
5466
- */
5467
- function useFillHeight() {
5468
- const ref = useRef(null);
5469
- useLayoutEffect(() => {
5470
- const el = ref.current;
5471
- if (!el) return;
5472
- const main = el.closest("main");
5473
- const measure = () => {
5474
- const h = el.getBoundingClientRect().height;
5475
- const page = main?.firstElementChild;
5476
- const room = main && page ? main.clientHeight - (page.getBoundingClientRect().height - h) : window.innerHeight - el.getBoundingClientRect().top;
5477
- el.style.setProperty("--board-h", `${Math.max(320, Math.floor(room))}px`);
5478
- };
5479
- measure();
5480
- const ro = new ResizeObserver(measure);
5481
- ro.observe(document.documentElement);
5482
- if (main) ro.observe(main);
5483
- return () => ro.disconnect();
5484
- }, []);
5485
- return ref;
5486
- }
5487
- //#endregion
5488
3795
  //#region src/components/ui/kanban.tsx
5489
3796
  /** Marca o fim da lista: ao aparecer na rolagem da etapa, pede mais cards. */
5490
3797
  function LoadMore({ onVisible }) {
@@ -8397,95 +6704,6 @@ var Textarea = forwardRef(function Textarea({ invalid, counter, value, defaultVa
8397
6704
  });
8398
6705
  });
8399
6706
  //#endregion
8400
- //#region src/components/ui/timeline.tsx
8401
- var dot = {
8402
- neutral: "bg-muted text-muted-foreground",
8403
- info: "bg-info-soft text-info-soft-foreground",
8404
- success: "bg-success-soft text-success-soft-foreground",
8405
- warning: "bg-warning-soft text-warning-soft-foreground",
8406
- error: "bg-destructive-soft text-destructive-soft-foreground"
8407
- };
8408
- var statusTone = {
8409
- succeeded: "success",
8410
- failed: "error",
8411
- skipped: "neutral"
8412
- };
8413
- var statusIcon = {
8414
- succeeded: CheckCircle2,
8415
- failed: XCircle,
8416
- skipped: SkipForward
8417
- };
8418
- var statusLabel$1 = {
8419
- succeeded: "Concluído",
8420
- failed: "Falhou",
8421
- skipped: "Ignorado"
8422
- };
8423
- var statusTextTone = {
8424
- succeeded: "text-success-soft-foreground",
8425
- failed: "text-destructive-soft-foreground",
8426
- skipped: "text-muted-foreground"
8427
- };
8428
- /** Linha do tempo única, com eventos em ordem e tom semântico por evento. */
8429
- function Timeline({ events, className }) {
8430
- const lib = useMotionLib();
8431
- const on = lib !== null;
8432
- const presets = useMotionPresets();
8433
- const Item = on ? lib.m.li : "li";
8434
- const enter = presets.slide("bottom", "short");
8435
- return /* @__PURE__ */ jsx("ol", {
8436
- "data-rendra": "TLN-001",
8437
- className: cn("@container flex flex-col", className),
8438
- children: events.map((e, i) => {
8439
- const StatusIcon = e.status ? statusIcon[e.status] : null;
8440
- const tone = e.tone ?? (e.status ? statusTone[e.status] : "neutral");
8441
- return /* @__PURE__ */ jsxs(Item, {
8442
- className: "relative flex gap-3 pb-6 last:pb-0",
8443
- ...on ? {
8444
- ...enter,
8445
- transition: {
8446
- ...enter.transition,
8447
- ...presets.stagger(i)
8448
- }
8449
- } : {},
8450
- children: [
8451
- i < events.length - 1 && /* @__PURE__ */ jsx("span", {
8452
- "aria-hidden": true,
8453
- className: "absolute top-8 bottom-0 left-4 w-px -translate-x-1/2 bg-border"
8454
- }),
8455
- /* @__PURE__ */ jsx("span", {
8456
- "aria-hidden": true,
8457
- className: cn("relative flex size-8 shrink-0 items-center justify-center rounded-full [&_svg]:size-icon-sm", dot[tone]),
8458
- children: e.icon ?? (StatusIcon && /* @__PURE__ */ jsx(StatusIcon, {})) ?? /* @__PURE__ */ jsx("span", { className: "size-2 rounded-full bg-current" })
8459
- }),
8460
- /* @__PURE__ */ jsxs("div", {
8461
- className: "flex min-w-0 flex-1 flex-col gap-1 pt-1",
8462
- children: [
8463
- /* @__PURE__ */ jsxs("div", {
8464
- className: "flex min-w-0 flex-col gap-1 @sm:flex-row @sm:items-baseline @sm:justify-between @sm:gap-3",
8465
- children: [/* @__PURE__ */ jsx("span", {
8466
- className: "text-sm font-medium wrap-break-word",
8467
- children: e.title
8468
- }), /* @__PURE__ */ jsx("time", {
8469
- className: "shrink-0 text-xs text-muted-foreground tabular-nums",
8470
- children: e.date
8471
- })]
8472
- }),
8473
- e.description && /* @__PURE__ */ jsx("p", {
8474
- className: "text-sm wrap-break-word text-muted-foreground",
8475
- children: e.description
8476
- }),
8477
- e.status && StatusIcon && /* @__PURE__ */ jsxs("span", {
8478
- className: cn("inline-flex w-fit items-center gap-1 text-xs font-medium [&_svg]:size-icon-sm", statusTextTone[e.status]),
8479
- children: [/* @__PURE__ */ jsx(StatusIcon, {}), statusLabel$1[e.status]]
8480
- })
8481
- ]
8482
- })
8483
- ]
8484
- }, e.id);
8485
- })
8486
- });
8487
- }
8488
- //#endregion
8489
6707
  //#region src/components/ui/toast.tsx
8490
6708
  var tone = {
8491
6709
  success: "border-success/25",