@rendra-ui/web 2.2.2 → 2.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +94 -68
- package/bin/rendra.mjs +19 -7
- package/dist/base.css +1 -1
- package/dist/{button-BgSglLWN.js → button-C6rjowQi.js} +4 -4
- package/dist/{button-BgSglLWN.js.map → button-C6rjowQi.js.map} +1 -1
- package/dist/chart.js +5 -5
- package/dist/cli/auditar.js +66 -16
- package/dist/cli/auditar.js.map +1 -1
- package/dist/cli/codigos.js +2 -2
- package/dist/cli/executar-auditar.js +634 -0
- package/dist/cli/executar-auditar.js.map +1 -0
- package/dist/cli/help.js +7 -2
- package/dist/cli/help.js.map +1 -1
- package/dist/cli/trocar.js +2 -2
- package/dist/cli/typescript-loader.js +1 -1
- package/dist/{cn-Bo1YMupg.js → cn-DXDpTGsu.js} +2 -2
- package/dist/{cn-Bo1YMupg.js.map → cn-DXDpTGsu.js.map} +1 -1
- package/dist/{components-Dl15AjD-.js → components-hp7iWioq.js} +21 -4
- package/dist/components-hp7iWioq.js.map +1 -0
- package/dist/components.css +107 -1
- package/dist/document-viewer.js +4 -4
- package/dist/{empty-state-Be_tReTU.js → empty-state-CdaDLcsB.js} +50 -30
- package/dist/empty-state-CdaDLcsB.js.map +1 -0
- package/dist/index.js +135 -67
- package/dist/index.js.map +1 -1
- package/dist/{rendra-provider-DPulIoQB.js → rendra-provider-7jUgUHzR.js} +2 -2
- package/dist/{rendra-provider-DPulIoQB.js.map → rendra-provider-7jUgUHzR.js.map} +1 -1
- package/dist/rich-text-editor.js +3 -3
- package/dist/router-bridge.js +2 -2
- package/dist/tokens.css +11 -1
- package/dist/{tooltip-dC9gqkuv.js → tooltip-bdmbX6vC.js} +3 -3
- package/dist/{tooltip-dC9gqkuv.js.map → tooltip-bdmbX6vC.js.map} +1 -1
- package/dist/types/components/app-shell/app-shell.d.ts +22 -2
- package/dist/types/components/app-shell/shell-context.d.ts +7 -1
- package/dist/types/components/app-shell/types.d.ts +23 -0
- package/dist/types/components/layout/page-header.d.ts +17 -1
- package/dist/types/components/ui/brand-feedback-icon.d.ts +20 -3
- package/dist/types/components/ui/button-group.d.ts +8 -1
- package/dist/types/components/ui/empty-state.d.ts +4 -0
- package/dist/types/components/ui/error-page.d.ts +6 -1
- package/dist/types/components/ui/modal.d.ts +4 -0
- package/dist/types/components/ui/select.d.ts +4 -1
- package/dist/types/components/ui/wizard.d.ts +14 -1
- package/dist/types/lib/initials.d.ts +2 -0
- package/dist/{use-breakpoint-BUHd0Cbz.js → use-breakpoint-Dyp-0E_c.js} +2 -2
- package/dist/{use-breakpoint-BUHd0Cbz.js.map → use-breakpoint-Dyp-0E_c.js.map} +1 -1
- package/dist/widget-grid.js +2 -2
- package/package.json +7 -1
- package/dist/components-Dl15AjD-.js.map +0 -1
- package/dist/empty-state-Be_tReTU.js.map +0 -1
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
/*! Rendra Design System v2.
|
|
2
|
-
import { t as cn } from "./cn-
|
|
1
|
+
/*! Rendra Design System v2.4.0 | MIT | © 2026 Bruno Magalhaes | brunomagalhaes.me */
|
|
2
|
+
import { t as cn } from "./cn-DXDpTGsu.js";
|
|
3
|
+
import { CircleCheck, CircleX, Info, TriangleAlert } from "lucide-react";
|
|
3
4
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
4
5
|
import { createContext, useContext } from "react";
|
|
5
6
|
import { cva } from "class-variance-authority";
|
|
@@ -14,27 +15,39 @@ function useBrand() {
|
|
|
14
15
|
}
|
|
15
16
|
//#endregion
|
|
16
17
|
//#region src/components/ui/brand-feedback-icon.tsx
|
|
18
|
+
var sizes = {
|
|
19
|
+
sm: "size-icon-sm",
|
|
20
|
+
md: "size-icon-md",
|
|
21
|
+
lg: "size-icon-lg",
|
|
22
|
+
xl: "size-12",
|
|
23
|
+
"2xl": "size-16"
|
|
24
|
+
};
|
|
17
25
|
var iconVariants = cva("relative inline-flex shrink-0", {
|
|
18
|
-
variants: {
|
|
19
|
-
|
|
20
|
-
success: "text-success",
|
|
21
|
-
error: "text-destructive",
|
|
22
|
-
warning: "text-warning",
|
|
23
|
-
info: "text-info"
|
|
24
|
-
},
|
|
25
|
-
size: {
|
|
26
|
-
sm: "size-icon-sm",
|
|
27
|
-
md: "size-icon-md",
|
|
28
|
-
lg: "size-icon-lg",
|
|
29
|
-
xl: "size-12",
|
|
30
|
-
"2xl": "size-16"
|
|
31
|
-
}
|
|
32
|
-
},
|
|
33
|
-
defaultVariants: {
|
|
34
|
-
type: "info",
|
|
35
|
-
size: "md"
|
|
36
|
-
}
|
|
26
|
+
variants: { size: sizes },
|
|
27
|
+
defaultVariants: { size: "md" }
|
|
37
28
|
});
|
|
29
|
+
/** Cor do estado (tinge o símbolo e, em statusBadge, o ícone ao lado). */
|
|
30
|
+
var stateText = {
|
|
31
|
+
success: "text-success",
|
|
32
|
+
error: "text-destructive",
|
|
33
|
+
warning: "text-warning",
|
|
34
|
+
info: "text-info"
|
|
35
|
+
};
|
|
36
|
+
/** Ícone Lucide do selo ao lado do símbolo (statusBadge). */
|
|
37
|
+
var badgeIcons = {
|
|
38
|
+
success: CircleCheck,
|
|
39
|
+
error: CircleX,
|
|
40
|
+
warning: TriangleAlert,
|
|
41
|
+
info: Info
|
|
42
|
+
};
|
|
43
|
+
/** Tamanho do ícone ao lado, proporcional ao do símbolo. */
|
|
44
|
+
var badgeIconSize = {
|
|
45
|
+
sm: "size-3",
|
|
46
|
+
md: "size-icon-sm",
|
|
47
|
+
lg: "size-icon-md",
|
|
48
|
+
xl: "size-icon-lg",
|
|
49
|
+
"2xl": "size-icon-lg"
|
|
50
|
+
};
|
|
38
51
|
var badgeTone = {
|
|
39
52
|
success: "bg-success text-success-foreground",
|
|
40
53
|
error: "bg-destructive text-destructive-foreground",
|
|
@@ -100,7 +113,7 @@ function StatusGlyph({ type, animated, ...props }) {
|
|
|
100
113
|
* semântica, com um selo de status para que o significado não dependa só da cor.
|
|
101
114
|
* Cada tipo pode ser substituído por um SVG próprio em brand.config.ts (feedbackIcons).
|
|
102
115
|
*/
|
|
103
|
-
function BrandFeedbackIcon({ type, size, label, animated = false, className }) {
|
|
116
|
+
function BrandFeedbackIcon({ type, size, label, animated = false, symbolTone = "state", statusBadge = false, animation = "pop", className }) {
|
|
104
117
|
const { brand } = useBrand();
|
|
105
118
|
const Custom = brand.feedbackIcons?.[type];
|
|
106
119
|
const Symbol = brand.symbol;
|
|
@@ -108,19 +121,26 @@ function BrandFeedbackIcon({ type, size, label, animated = false, className }) {
|
|
|
108
121
|
role: "img",
|
|
109
122
|
"aria-label": label
|
|
110
123
|
} : { "aria-hidden": true };
|
|
124
|
+
const encaixe = animation === "encaixe";
|
|
125
|
+
const rootTone = symbolTone === "state" ? stateText[type] : void 0;
|
|
126
|
+
const symbolTonal = symbolTone === "brand" && "text-primary-text";
|
|
127
|
+
const symbolAnim = animated && (encaixe ? "animate-encaixe" : "animate-pop");
|
|
128
|
+
const badgeAnim = animated && (encaixe ? "animate-encaixe" : "animate-pop anim-delay-1");
|
|
129
|
+
const BadgeIcon = badgeIcons[type];
|
|
130
|
+
const sideBadge = statusBadge && !Custom;
|
|
111
131
|
return /* @__PURE__ */ jsx("span", {
|
|
112
132
|
"data-slot": "feedback-icon",
|
|
113
133
|
"data-rendra": "BFI-001",
|
|
114
|
-
className: cn(iconVariants({
|
|
115
|
-
type,
|
|
116
|
-
size
|
|
117
|
-
}), animated && type === "error" && "animate-shake", className),
|
|
134
|
+
className: cn(sideBadge ? "relative inline-flex shrink-0 items-center gap-1" : iconVariants({ size }), rootTone, animated && !encaixe && type === "error" && "animate-shake", className),
|
|
118
135
|
...a11y,
|
|
119
|
-
children: Custom ? /* @__PURE__ */ jsx(Custom, { className: cn("size-full",
|
|
120
|
-
|
|
136
|
+
children: Custom ? /* @__PURE__ */ jsx(Custom, { className: cn("size-full", symbolTonal, symbolAnim) }) : sideBadge ? /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(Symbol, { className: cn(sizes[size ?? "md"], symbolTonal, symbolAnim) }), /* @__PURE__ */ jsx(BadgeIcon, {
|
|
137
|
+
"aria-hidden": true,
|
|
138
|
+
className: cn("shrink-0", badgeIconSize[size ?? "md"], stateText[type], badgeAnim)
|
|
139
|
+
})] }) : /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(Symbol, { className: cn("size-full mask-status-cutout", symbolTonal, symbolAnim) }), /* @__PURE__ */ jsx("span", {
|
|
140
|
+
className: cn("absolute right-0 bottom-0 flex size-1/2 items-center justify-center rounded-full", badgeTone[type], badgeAnim),
|
|
121
141
|
children: /* @__PURE__ */ jsx(StatusGlyph, {
|
|
122
142
|
type,
|
|
123
|
-
animated,
|
|
143
|
+
animated: animated && !encaixe,
|
|
124
144
|
className: "size-full"
|
|
125
145
|
})
|
|
126
146
|
})] })
|
|
@@ -165,4 +185,4 @@ function EmptyState({ title, description, type = "info", actions, size = "defaul
|
|
|
165
185
|
//#endregion
|
|
166
186
|
export { BrandContext as a, useBrand as i, BrandFeedbackIcon as n, feedbackLabels as r, EmptyState as t };
|
|
167
187
|
|
|
168
|
-
//# sourceMappingURL=empty-state-
|
|
188
|
+
//# sourceMappingURL=empty-state-CdaDLcsB.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"empty-state-CdaDLcsB.js","names":[],"sources":["../src/brand/brand-context.ts","../src/brand/use-brand.ts","../src/components/ui/brand-feedback-icon.tsx","../src/components/ui/empty-state.tsx"],"sourcesContent":["import { createContext } from 'react'\nimport type { Shape } from '@/lib/shape'\nimport type { BrandConfig, PaletteConfig } from './types'\n\nexport type ColorMode = 'light' | 'dark' | 'system'\n\nexport interface BrandContextValue {\n brand: BrandConfig\n brands: BrandConfig[]\n setBrandId: (id: string) => void\n mode: ColorMode\n resolvedMode: 'light' | 'dark'\n setMode: (mode: ColorMode) => void\n /** Formato do template ativo (fixo por template). */\n shape: Shape\n /** Paleta de cores em uso (por padrão, a do próprio modelo). */\n palette: PaletteConfig\n palettes: PaletteConfig[]\n /** Usa a paleta de outro template; null volta às cores do próprio modelo. */\n setPaletteId: (id: string | null) => void\n /** Logotipo adequado para a sidebar com a paleta atual. */\n sidebarLogoVariant: 'light' | 'dark'\n}\n\nexport const BrandContext = createContext<BrandContextValue | null>(null)\n","import { useContext } from 'react'\nimport { BrandContext } from './brand-context'\n\nexport function useBrand() {\n const ctx = useContext(BrandContext)\n if (!ctx) throw new Error('useBrand precisa estar dentro de <BrandProvider>.')\n return ctx\n}\n","import { cva, type VariantProps } from 'class-variance-authority'\nimport { CircleCheck, CircleX, Info, TriangleAlert, type LucideIcon } from 'lucide-react'\nimport type { SVGProps } from 'react'\nimport { useBrand } from '@/brand/use-brand'\nimport type { FeedbackType } from '@/brand/types'\nimport { cn } from '@/lib/cn'\n\nconst sizes = {\n sm: 'size-icon-sm',\n md: 'size-icon-md',\n lg: 'size-icon-lg',\n xl: 'size-12',\n '2xl': 'size-16',\n} as const\n\nconst iconVariants = cva('relative inline-flex shrink-0', {\n variants: { size: sizes },\n defaultVariants: { size: 'md' },\n})\n\n/** Cor do estado (tinge o símbolo e, em statusBadge, o ícone ao lado). */\nconst stateText: Record<FeedbackType, string> = {\n success: 'text-success',\n error: 'text-destructive',\n warning: 'text-warning',\n info: 'text-info',\n}\n\n/** Ícone Lucide do selo ao lado do símbolo (statusBadge). */\nconst badgeIcons: Record<FeedbackType, LucideIcon> = {\n success: CircleCheck,\n error: CircleX,\n warning: TriangleAlert,\n info: Info,\n}\n\n/** Tamanho do ícone ao lado, proporcional ao do símbolo. */\nconst badgeIconSize: Record<keyof typeof sizes, string> = {\n sm: 'size-3',\n md: 'size-icon-sm',\n lg: 'size-icon-md',\n xl: 'size-icon-lg',\n '2xl': 'size-icon-lg',\n}\n\nconst badgeTone: Record<FeedbackType, string> = {\n success: 'bg-success text-success-foreground',\n error: 'bg-destructive text-destructive-foreground',\n warning: 'bg-warning text-warning-foreground',\n info: 'bg-info text-info-foreground',\n}\n\nexport const feedbackLabels: Record<FeedbackType, string> = {\n success: 'Sucesso',\n error: 'Erro',\n warning: 'Atenção',\n info: 'Informação',\n}\n\n/** Glifos universais de status desenhados em traço, herdando currentColor. */\nfunction StatusGlyph({\n type,\n animated,\n ...props\n}: { type: FeedbackType; animated?: boolean } & SVGProps<SVGSVGElement>) {\n // pathLength=1 normaliza o traço: o desenho anima de 1 a 0 em qualquer glifo.\n const draw = animated\n ? ({ pathLength: 1, strokeDasharray: 1, className: 'animate-draw' } as const)\n : {}\n const common = {\n viewBox: '0 0 12 12',\n fill: 'none',\n stroke: 'currentColor',\n strokeWidth: 2,\n strokeLinecap: 'round' as const,\n strokeLinejoin: 'round' as const,\n 'aria-hidden': true,\n ...props,\n }\n switch (type) {\n case 'success':\n return (\n <svg {...common}>\n <path d=\"M3 6.2 5.1 8.2 9 4\" {...draw} />\n </svg>\n )\n case 'error':\n return (\n <svg {...common}>\n <path d=\"M4 4l4 4M8 4 4 8\" {...draw} />\n </svg>\n )\n case 'warning':\n return (\n <svg {...common}>\n <path d=\"M6 3.2v3.3M6 8.8v0\" {...draw} />\n </svg>\n )\n case 'info':\n return (\n <svg {...common}>\n <path d=\"M6 3.2v0M6 5.5v3.3\" {...draw} />\n </svg>\n )\n }\n}\n\nexport interface BrandFeedbackIconProps extends VariantProps<typeof iconVariants> {\n type: FeedbackType\n /** Texto para leitores de tela. Sem ele o ícone é decorativo (o texto ao lado informa). */\n label?: string\n /**\n * Anima a entrada: o símbolo entra com mola e o glifo se desenha (check se formando,\n * X se riscando). O erro treme ao final. Respeita reduzir movimento.\n * Troque a key do componente para repetir a animação.\n */\n animated?: boolean\n /**\n * Cor do símbolo. `state` (padrão): a cor do estado (verde, vermelho, amarelo, azul).\n * `brand`: a cor primária da marca (`text-primary-text`); o selo de estado mantém a cor do\n * estado, para o significado não depender só da cor.\n */\n symbolTone?: 'state' | 'brand'\n /**\n * `false` (padrão): selo de estado sobreposto ao símbolo. `true`: o ícone do estado\n * (Lucide, na cor do estado) fica ao lado do símbolo, no lugar do selo sobreposto. Com um\n * SVG próprio em `brand.feedbackIcons[type]`, o SVG vence e nenhum selo é desenhado.\n */\n statusBadge?: boolean\n /**\n * Só vale com `animated`. `pop` (padrão): entra com mola, o glifo se desenha e o erro\n * treme. `encaixe`: entra em 240 ms, curva de saída suave, sem quique, sem desenho e sem\n * tremor. Com \"reduzir movimento\" do sistema, nenhuma animação roda.\n */\n animation?: 'pop' | 'encaixe'\n className?: string\n}\n\n/**\n * Ícone de feedback da marca: o símbolo da marca em currentColor, tingido pela cor\n * semântica, com um selo de status para que o significado não dependa só da cor.\n * Cada tipo pode ser substituído por um SVG próprio em brand.config.ts (feedbackIcons).\n */\nexport function BrandFeedbackIcon({\n type,\n size,\n label,\n animated = false,\n symbolTone = 'state',\n statusBadge = false,\n animation = 'pop',\n className,\n}: BrandFeedbackIconProps) {\n const { brand } = useBrand()\n const Custom = brand.feedbackIcons?.[type]\n const Symbol = brand.symbol\n const a11y = label\n ? ({ role: 'img', 'aria-label': label } as const)\n : ({ 'aria-hidden': true } as const)\n const encaixe = animation === 'encaixe'\n // Com `symbolTone=\"state\"` o texto do estado fica na raiz (como sempre); com `brand` sai da raiz.\n const rootTone = symbolTone === 'state' ? stateText[type] : undefined\n const symbolTonal = symbolTone === 'brand' && 'text-primary-text'\n const symbolAnim = animated && (encaixe ? 'animate-encaixe' : 'animate-pop')\n const badgeAnim = animated && (encaixe ? 'animate-encaixe' : 'animate-pop anim-delay-1')\n const BadgeIcon = badgeIcons[type]\n const sideBadge = statusBadge && !Custom\n\n return (\n <span\n data-slot=\"feedback-icon\"\n data-rendra=\"BFI-001\"\n className={cn(\n sideBadge ? 'relative inline-flex shrink-0 items-center gap-1' : iconVariants({ size }),\n rootTone,\n animated && !encaixe && type === 'error' && 'animate-shake',\n className,\n )}\n {...a11y}\n >\n {Custom ? (\n <Custom className={cn('size-full', symbolTonal, symbolAnim)} />\n ) : sideBadge ? (\n <>\n <Symbol className={cn(sizes[size ?? 'md'], symbolTonal, symbolAnim)} />\n <BadgeIcon\n aria-hidden\n className={cn('shrink-0', badgeIconSize[size ?? 'md'], stateText[type], badgeAnim)}\n />\n </>\n ) : (\n <>\n <Symbol className={cn('size-full mask-status-cutout', symbolTonal, symbolAnim)} />\n <span\n className={cn(\n 'absolute right-0 bottom-0 flex size-1/2 items-center justify-center rounded-full',\n badgeTone[type],\n badgeAnim,\n )}\n >\n <StatusGlyph type={type} animated={animated && !encaixe} className=\"size-full\" />\n </span>\n </>\n )}\n </span>\n )\n}\n","import type { ReactNode } from 'react'\nimport type { FeedbackType } from '@/brand/types'\nimport { BrandFeedbackIcon } from '@/components/ui/brand-feedback-icon'\nimport { cn } from '@/lib/cn'\n\nexport interface EmptyStateProps {\n title: string\n description?: ReactNode\n /** Tipo do ícone de feedback da marca. info para \"sem dados\", error para falha. */\n type?: FeedbackType\n /** Ações: no máximo uma principal e uma secundária. */\n actions?: ReactNode\n /** compact: dentro de tabela ou card pequeno. */\n size?: 'default' | 'compact'\n /**\n * Classes extras, que vencem as do componente. Para zerar o respiro vertical (por exemplo,\n * dentro de um card que já tem o seu) use `className=\"py-0 md:py-0\"`.\n */\n className?: string\n}\n\n/** Estado vazio (e de erro) com o ícone de feedback da marca. */\nexport function EmptyState({\n title,\n description,\n type = 'info',\n actions,\n size = 'default',\n className,\n}: EmptyStateProps) {\n return (\n <div\n data-rendra=\"VAZ-001\"\n className={cn(\n 'flex flex-col items-center justify-center gap-4 text-center',\n size === 'compact' ? 'px-4 py-8' : 'px-4 py-12 md:py-16',\n className,\n )}\n >\n <span className=\"relative flex items-center justify-center\">\n <span aria-hidden className=\"absolute size-16 rounded-full bg-gradient-soft\" />\n <BrandFeedbackIcon\n type={type}\n size={size === 'compact' ? 'xl' : '2xl'}\n className=\"relative\"\n />\n </span>\n <div className=\"flex w-full flex-col gap-1\">\n <p className=\"text-base font-semibold\">{title}</p>\n {description && <p className=\"text-sm text-muted-foreground\">{description}</p>}\n </div>\n {actions && <div className=\"flex flex-wrap justify-center gap-3\">{actions}</div>}\n </div>\n )\n}\n"],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
/*! Rendra Design System v2.
|
|
2
|
-
import { t as cn } from "./cn-
|
|
3
|
-
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-
|
|
4
|
-
import { i as usePrefersReducedMotion, n as buttonVariants, r as Spinner, t as Button } from "./button-
|
|
5
|
-
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-
|
|
6
|
-
import { a as BrandContext, i as useBrand, n as BrandFeedbackIcon, r as feedbackLabels, t as EmptyState } from "./empty-state-
|
|
7
|
-
import { a as useRendraNavigate, i as useRendraLink, n as useCurrentPath, r as useRendraBreadcrumbs, t as RendraProvider } from "./rendra-provider-
|
|
8
|
-
import { n as useBreakpoint, t as breakpoints } from "./use-breakpoint-
|
|
1
|
+
/*! Rendra Design System v2.4.0 | MIT | © 2026 Bruno Magalhaes | brunomagalhaes.me */
|
|
2
|
+
import { t as cn } from "./cn-DXDpTGsu.js";
|
|
3
|
+
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-hp7iWioq.js";
|
|
4
|
+
import { i as usePrefersReducedMotion, n as buttonVariants, r as Spinner, t as Button } from "./button-C6rjowQi.js";
|
|
5
|
+
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-bdmbX6vC.js";
|
|
6
|
+
import { a as BrandContext, i as useBrand, n as BrandFeedbackIcon, r as feedbackLabels, t as EmptyState } from "./empty-state-CdaDLcsB.js";
|
|
7
|
+
import { a as useRendraNavigate, i as useRendraLink, n as useCurrentPath, r as useRendraBreadcrumbs, t as RendraProvider } from "./rendra-provider-7jUgUHzR.js";
|
|
8
|
+
import { n as useBreakpoint, t as breakpoints } from "./use-breakpoint-Dyp-0E_c.js";
|
|
9
9
|
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";
|
|
10
10
|
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";
|
|
11
11
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
@@ -182,6 +182,13 @@ function Alert({ type, title, description, action, onDismiss, animated = false,
|
|
|
182
182
|
});
|
|
183
183
|
}
|
|
184
184
|
//#endregion
|
|
185
|
+
//#region src/lib/initials.ts
|
|
186
|
+
/** Iniciais de um nome: primeira letra do primeiro e do último nome, em maiúsculas. */
|
|
187
|
+
function initials(name) {
|
|
188
|
+
const parts = name.trim().split(/\s+/);
|
|
189
|
+
return ((parts[0]?.charAt(0) ?? "") + (parts.length > 1 ? parts[parts.length - 1]?.charAt(0) ?? "" : "")).toUpperCase();
|
|
190
|
+
}
|
|
191
|
+
//#endregion
|
|
185
192
|
//#region src/components/ui/avatar.tsx
|
|
186
193
|
var avatarVariants = cva("relative inline-flex shrink-0 items-center justify-center overflow-hidden rounded-avatar bg-primary-soft font-medium text-primary-soft-foreground select-none", {
|
|
187
194
|
variants: { size: {
|
|
@@ -191,10 +198,6 @@ var avatarVariants = cva("relative inline-flex shrink-0 items-center justify-cen
|
|
|
191
198
|
} },
|
|
192
199
|
defaultVariants: { size: "md" }
|
|
193
200
|
});
|
|
194
|
-
function initials(name) {
|
|
195
|
-
const parts = name.trim().split(/\s+/);
|
|
196
|
-
return ((parts[0]?.charAt(0) ?? "") + (parts.length > 1 ? parts[parts.length - 1]?.charAt(0) ?? "" : "")).toUpperCase();
|
|
197
|
-
}
|
|
198
201
|
function Avatar({ name, src, size, className }) {
|
|
199
202
|
return /* @__PURE__ */ jsxs(Avatar$1.Root, {
|
|
200
203
|
"data-rendra": "AVT-001",
|
|
@@ -362,13 +365,17 @@ function BrandLogo({ on = "surface", symbolOnly, size = "md", className }) {
|
|
|
362
365
|
}),
|
|
363
366
|
!symbolOnly && /* @__PURE__ */ jsxs("span", {
|
|
364
367
|
className: "truncate text-lg leading-none tracking-tight",
|
|
365
|
-
children: [
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
368
|
+
children: [
|
|
369
|
+
/* @__PURE__ */ jsx("span", {
|
|
370
|
+
className: cn("font-semibold", strong),
|
|
371
|
+
children: first
|
|
372
|
+
}),
|
|
373
|
+
rest.length > 0 && " ",
|
|
374
|
+
rest.length > 0 && /* @__PURE__ */ jsx("span", {
|
|
375
|
+
className: cn("font-normal", soft),
|
|
376
|
+
children: rest.join(" ")
|
|
377
|
+
})
|
|
378
|
+
]
|
|
372
379
|
}),
|
|
373
380
|
symbolOnly && /* @__PURE__ */ jsx("span", {
|
|
374
381
|
className: "sr-only",
|
|
@@ -468,11 +475,11 @@ function Breadcrumb({ items, variant = "responsive", className }) {
|
|
|
468
475
|
* ButtonGroup único: agrupa botões de ação (children) ou funciona como controle
|
|
469
476
|
* segmentado de escolha única (options + value).
|
|
470
477
|
*/
|
|
471
|
-
function ButtonGroup({ children, options, value, onChange, size = "md", fullWidth, className, ...aria }) {
|
|
478
|
+
function ButtonGroup({ children, options, value, onChange, size = "md", fullWidth, orientation = "horizontal", className, ...aria }) {
|
|
472
479
|
if (options) return /* @__PURE__ */ jsx("div", {
|
|
473
480
|
role: "radiogroup",
|
|
474
481
|
"aria-label": aria["aria-label"],
|
|
475
|
-
"data-rendra": "
|
|
482
|
+
"data-rendra": resolveCatalogCode("ButtonGroup", { orientation: "horizontal" }),
|
|
476
483
|
className: cn("inline-flex max-w-full flex-wrap gap-1 rounded-control border bg-muted p-1", fullWidth && "flex w-full", className),
|
|
477
484
|
children: options.map((o) => {
|
|
478
485
|
const active = o.value === value;
|
|
@@ -487,18 +494,34 @@ function ButtonGroup({ children, options, value, onChange, size = "md", fullWidt
|
|
|
487
494
|
}, o.value);
|
|
488
495
|
})
|
|
489
496
|
});
|
|
497
|
+
const vertical = orientation === "vertical";
|
|
498
|
+
const responsive = orientation === "responsive";
|
|
490
499
|
return /* @__PURE__ */ jsx("div", {
|
|
491
500
|
role: "group",
|
|
492
501
|
"aria-label": aria["aria-label"],
|
|
493
|
-
"data-rendra": "
|
|
494
|
-
className: cn("inline-flex max-w-full", "[&>*]:rounded-none [&>*]:shadow-none [&>*:first-child]:rounded-l-control [&>*:
|
|
502
|
+
"data-rendra": resolveCatalogCode("ButtonGroup", { orientation }),
|
|
503
|
+
className: cn("inline-flex max-w-full", "[&>*]:rounded-none [&>*]:shadow-none [&>*:focus-visible]:z-10", orientation === "horizontal" && "[&>*:first-child]:rounded-l-control [&>*:last-child]:rounded-r-control [&>*:not(:first-child)]:-ml-px", vertical && "flex-col [&>*]:w-full [&>*:first-child]:rounded-t-control [&>*:last-child]:rounded-b-control [&>*:not(:first-child)]:-mt-px", responsive && "flex-col md:flex-row [&>*]:w-full md:[&>*]:w-auto [&>*:first-child]:rounded-t-control md:[&>*:first-child]:rounded-l-control md:[&>*:first-child]:rounded-tr-none [&>*:last-child]:rounded-b-control md:[&>*:last-child]:rounded-r-control md:[&>*:last-child]:rounded-bl-none [&>*:not(:first-child)]:-mt-px md:[&>*:not(:first-child)]:mt-0 md:[&>*:not(:first-child)]:-ml-px", fullWidth && (vertical ? "flex w-full" : "flex w-full [&>*]:flex-1"), className),
|
|
495
504
|
children
|
|
496
505
|
});
|
|
497
506
|
}
|
|
498
507
|
//#endregion
|
|
499
508
|
//#region src/components/ui/overlay-shell.tsx
|
|
500
509
|
function OverlayShell({ title, description, icon, children, footer, hideHeader, onRequestClose, bodyClassName }) {
|
|
510
|
+
const closeButton = /* @__PURE__ */ jsx("button", {
|
|
511
|
+
type: "button",
|
|
512
|
+
onClick: onRequestClose,
|
|
513
|
+
"aria-label": "Fechar",
|
|
514
|
+
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"),
|
|
515
|
+
children: /* @__PURE__ */ jsx(X, {
|
|
516
|
+
className: "size-icon-md",
|
|
517
|
+
"aria-hidden": true
|
|
518
|
+
})
|
|
519
|
+
});
|
|
501
520
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
521
|
+
hideHeader && /* @__PURE__ */ jsx("div", {
|
|
522
|
+
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",
|
|
523
|
+
children: closeButton
|
|
524
|
+
}),
|
|
502
525
|
/* @__PURE__ */ jsxs("header", {
|
|
503
526
|
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"),
|
|
504
527
|
children: [
|
|
@@ -520,16 +543,7 @@ function OverlayShell({ title, description, icon, children, footer, hideHeader,
|
|
|
520
543
|
children: title
|
|
521
544
|
})]
|
|
522
545
|
}),
|
|
523
|
-
|
|
524
|
-
type: "button",
|
|
525
|
-
onClick: onRequestClose,
|
|
526
|
-
"aria-label": "Fechar",
|
|
527
|
-
className: "-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",
|
|
528
|
-
children: /* @__PURE__ */ jsx(X, {
|
|
529
|
-
className: "size-icon-md",
|
|
530
|
-
"aria-hidden": true
|
|
531
|
-
})
|
|
532
|
-
})
|
|
546
|
+
!hideHeader && closeButton
|
|
533
547
|
]
|
|
534
548
|
}),
|
|
535
549
|
/* @__PURE__ */ jsx("div", {
|
|
@@ -554,7 +568,7 @@ var feedback = {
|
|
|
554
568
|
destructive: "error",
|
|
555
569
|
info: "info"
|
|
556
570
|
};
|
|
557
|
-
function Modal({ open, onOpenChange, title, description, type = "confirm", size = "sm", children, confirmLabel = type === "destructive" ? "Excluir" : type === "info" ? "Entendi" : "Confirmar", cancelLabel
|
|
571
|
+
function Modal({ open, onOpenChange, title, description, type = "confirm", size = "sm", children, confirmLabel = type === "destructive" ? "Excluir" : type === "info" ? "Entendi" : "Confirmar", cancelLabel, onConfirm, formId, loading }) {
|
|
558
572
|
const [busy, setBusy] = useState(false);
|
|
559
573
|
const close = () => onOpenChange(false);
|
|
560
574
|
const confirm = async () => {
|
|
@@ -590,8 +604,8 @@ function Modal({ open, onOpenChange, title, description, type = "confirm", size
|
|
|
590
604
|
form: isForm ? formId : void 0,
|
|
591
605
|
onClick: isForm && formId ? void 0 : confirm
|
|
592
606
|
},
|
|
593
|
-
cancel: type === "info" ? void 0 : {
|
|
594
|
-
label: cancelLabel,
|
|
607
|
+
cancel: type === "info" && cancelLabel === void 0 ? void 0 : {
|
|
608
|
+
label: cancelLabel ?? "Cancelar",
|
|
595
609
|
onClick: close
|
|
596
610
|
}
|
|
597
611
|
}),
|
|
@@ -1488,6 +1502,12 @@ var Input = forwardRef(function Input({ size, mask, icon, suffix, clearable, inv
|
|
|
1488
1502
|
const [showPassword, setShowPassword] = useState(false);
|
|
1489
1503
|
const [inner, setInner] = useState(String(value ?? defaultValue ?? ""));
|
|
1490
1504
|
const current = value ?? inner;
|
|
1505
|
+
const [secretDraft, setSecretDraft] = useState("");
|
|
1506
|
+
const [lastIsEditing, setLastIsEditing] = useState(isEditing);
|
|
1507
|
+
if (isEditing !== lastIsEditing) {
|
|
1508
|
+
setLastIsEditing(isEditing);
|
|
1509
|
+
if (isEditing) setSecretDraft("");
|
|
1510
|
+
}
|
|
1491
1511
|
const cb = useRef({
|
|
1492
1512
|
onChange,
|
|
1493
1513
|
onValueChange,
|
|
@@ -1536,6 +1556,7 @@ var Input = forwardRef(function Input({ size, mask, icon, suffix, clearable, inv
|
|
|
1536
1556
|
const resetValue = () => {
|
|
1537
1557
|
if (maskRef.current) maskRef.current.value = "";
|
|
1538
1558
|
setInner("");
|
|
1559
|
+
setSecretDraft("");
|
|
1539
1560
|
onChange?.("");
|
|
1540
1561
|
onValueChange?.("", "");
|
|
1541
1562
|
onCentsChange?.(null);
|
|
@@ -1639,8 +1660,9 @@ var Input = forwardRef(function Input({ size, mask, icon, suffix, clearable, inv
|
|
|
1639
1660
|
"aria-busy": searching || void 0,
|
|
1640
1661
|
className: cn(controlInput, inputClassName),
|
|
1641
1662
|
...isSecret ? {
|
|
1642
|
-
|
|
1663
|
+
value: secretDraft,
|
|
1643
1664
|
onChange: (e) => {
|
|
1665
|
+
setSecretDraft(e.target.value);
|
|
1644
1666
|
onChange?.(e.target.value);
|
|
1645
1667
|
onValueChange?.(e.target.value, e.target.value);
|
|
1646
1668
|
}
|
|
@@ -1688,7 +1710,7 @@ var Input = forwardRef(function Input({ size, mask, icon, suffix, clearable, inv
|
|
|
1688
1710
|
className: "shrink-0 text-sm text-muted-foreground",
|
|
1689
1711
|
children: suffix
|
|
1690
1712
|
}),
|
|
1691
|
-
clearable && current && !disabled && /* @__PURE__ */ jsx("button", {
|
|
1713
|
+
clearable && (isSecret ? secretDraft : current) && !disabled && /* @__PURE__ */ jsx("button", {
|
|
1692
1714
|
type: "button",
|
|
1693
1715
|
onClick: clear,
|
|
1694
1716
|
"aria-label": "Limpar campo",
|
|
@@ -4009,10 +4031,11 @@ var content = {
|
|
|
4009
4031
|
* Tela de erro única (404 e 500), com o ícone de feedback da marca animado.
|
|
4010
4032
|
* Ações seguem a regra 30/70: secundária à esquerda, principal à direita.
|
|
4011
4033
|
*/
|
|
4012
|
-
function ErrorPage({ code, title, description, fullScreen = false }) {
|
|
4034
|
+
function ErrorPage({ code, title, description, fullScreen = false, back = true }) {
|
|
4013
4035
|
const Link = useRendraLink();
|
|
4014
4036
|
const { goBack } = useRendraNavigate();
|
|
4015
4037
|
const c = content[code];
|
|
4038
|
+
const principal = back ? "col-span-7" : "col-span-10";
|
|
4016
4039
|
return /* @__PURE__ */ jsx("div", {
|
|
4017
4040
|
"data-rendra": "ERRO-001",
|
|
4018
4041
|
className: cn("flex w-full items-center justify-center px-4 py-12", fullScreen ? "min-h-dvh" : "min-h-full"),
|
|
@@ -4050,7 +4073,7 @@ function ErrorPage({ code, title, description, fullScreen = false }) {
|
|
|
4050
4073
|
}),
|
|
4051
4074
|
/* @__PURE__ */ jsxs("div", {
|
|
4052
4075
|
className: "grid w-full grid-cols-10 gap-3",
|
|
4053
|
-
children: [/* @__PURE__ */ jsx(Button, {
|
|
4076
|
+
children: [back && /* @__PURE__ */ jsx(Button, {
|
|
4054
4077
|
variant: "outline",
|
|
4055
4078
|
icon: /* @__PURE__ */ jsx(ArrowLeft, {}),
|
|
4056
4079
|
className: "col-span-3",
|
|
@@ -4062,12 +4085,12 @@ function ErrorPage({ code, title, description, fullScreen = false }) {
|
|
|
4062
4085
|
})
|
|
4063
4086
|
}), code === 500 ? /* @__PURE__ */ jsx(Button, {
|
|
4064
4087
|
icon: /* @__PURE__ */ jsx(RotateCw, {}),
|
|
4065
|
-
className:
|
|
4088
|
+
className: principal,
|
|
4066
4089
|
onClick: () => location.reload(),
|
|
4067
4090
|
children: "Tentar de novo"
|
|
4068
4091
|
}) : /* @__PURE__ */ jsx(Button, {
|
|
4069
4092
|
asChild: true,
|
|
4070
|
-
className:
|
|
4093
|
+
className: principal,
|
|
4071
4094
|
children: /* @__PURE__ */ jsxs(Link, {
|
|
4072
4095
|
to: "/",
|
|
4073
4096
|
children: [/* @__PURE__ */ jsx(Home, { "aria-hidden": true }), "Ir para o painel"]
|
|
@@ -4165,6 +4188,8 @@ function Slider({ value, defaultValue = [50], onChange, min = 0, max = 100, step
|
|
|
4165
4188
|
}
|
|
4166
4189
|
//#endregion
|
|
4167
4190
|
//#region src/components/ui/select.tsx
|
|
4191
|
+
/** Acima deste número de opções, o "Selecionar todos" aparece sem a prop `selectAll`. */
|
|
4192
|
+
var SELECT_ALL_AUTO_MIN = 5;
|
|
4168
4193
|
/**
|
|
4169
4194
|
* Select único do sistema. Busca, múltiplo, selecionar todos, contador, criar opção,
|
|
4170
4195
|
* busca remota e carregamento são props. No mobile abre como bottom sheet.
|
|
@@ -4236,6 +4261,7 @@ var Select = forwardRef(function Select(props, ref) {
|
|
|
4236
4261
|
};
|
|
4237
4262
|
const enabled = all.filter((o) => !o.disabled);
|
|
4238
4263
|
const allSelected = enabled.length > 0 && enabled.every((o) => multiValue.includes(o.value));
|
|
4264
|
+
const showSelectAll = multiple && (props.selectAll ?? all.length > SELECT_ALL_AUTO_MIN);
|
|
4239
4265
|
const toggleAll = () => {
|
|
4240
4266
|
const next = allSelected ? [] : enabled.map((o) => o.value);
|
|
4241
4267
|
if (isMobile) setDraft(next);
|
|
@@ -4376,11 +4402,11 @@ var Select = forwardRef(function Select(props, ref) {
|
|
|
4376
4402
|
})]
|
|
4377
4403
|
})]
|
|
4378
4404
|
}),
|
|
4379
|
-
|
|
4405
|
+
showSelectAll && !q && enabled.length > 0 && /* @__PURE__ */ jsxs(Command.Item, {
|
|
4380
4406
|
value: "__todos__",
|
|
4381
4407
|
onSelect: toggleAll,
|
|
4382
4408
|
className: cn(itemClass, "font-medium"),
|
|
4383
|
-
children: [checkbox(allSelected), "Selecionar todos"]
|
|
4409
|
+
children: [checkbox(allSelected), allSelected ? "Desmarcar todos" : "Selecionar todos"]
|
|
4384
4410
|
}),
|
|
4385
4411
|
Object.entries(groups).map(([group, opts]) => /* @__PURE__ */ jsx(Command.Group, {
|
|
4386
4412
|
heading: group || void 0,
|
|
@@ -8318,7 +8344,7 @@ function Stepper({ steps, current, errors = [], orientation = "horizontal", onSt
|
|
|
8318
8344
|
});
|
|
8319
8345
|
}
|
|
8320
8346
|
/** Cadastro em etapas, com validação por etapa e rodapé Voltar / Avançar. */
|
|
8321
|
-
function Wizard({ steps, children, onValidateStep, onFinish, onCancel, finishLabel = "Concluir", orientation = "horizontal", stickyFooter = false }) {
|
|
8347
|
+
function Wizard({ steps, children, onValidateStep, onFinish, onCancel, cancelLabel = "Cancelar", backLabel = "Voltar", nextLabel = "Avançar", finishLabel = "Concluir", onSkip, skipLabel = "Pular", orientation = "horizontal", stickyFooter = false }) {
|
|
8322
8348
|
const [current, setCurrent] = useState(0);
|
|
8323
8349
|
const [errors, setErrors] = useState([]);
|
|
8324
8350
|
const [busy, setBusy] = useState(false);
|
|
@@ -8337,6 +8363,11 @@ function Wizard({ steps, children, onValidateStep, onFinish, onCancel, finishLab
|
|
|
8337
8363
|
setBusy(false);
|
|
8338
8364
|
}
|
|
8339
8365
|
};
|
|
8366
|
+
const skip = () => {
|
|
8367
|
+
setErrors((e) => e.filter((x) => x !== current));
|
|
8368
|
+
setCurrent((c) => c + 1);
|
|
8369
|
+
onSkip?.();
|
|
8370
|
+
};
|
|
8340
8371
|
const body = /* @__PURE__ */ jsx("div", {
|
|
8341
8372
|
className: "flex min-w-0 flex-col gap-6",
|
|
8342
8373
|
children: children[current]
|
|
@@ -8356,15 +8387,19 @@ function Wizard({ steps, children, onValidateStep, onFinish, onCancel, finishLab
|
|
|
8356
8387
|
children: [body, /* @__PURE__ */ jsx(ActionBar, {
|
|
8357
8388
|
sticky: stickyFooter,
|
|
8358
8389
|
cancel: current > 0 ? {
|
|
8359
|
-
label:
|
|
8390
|
+
label: backLabel,
|
|
8360
8391
|
icon: /* @__PURE__ */ jsx(ArrowLeft, {}),
|
|
8361
8392
|
onClick: () => setCurrent((c) => c - 1)
|
|
8362
8393
|
} : onCancel ? {
|
|
8363
|
-
label:
|
|
8394
|
+
label: cancelLabel,
|
|
8364
8395
|
onClick: onCancel
|
|
8365
8396
|
} : void 0,
|
|
8397
|
+
secondary: onSkip && !last ? [{
|
|
8398
|
+
label: skipLabel,
|
|
8399
|
+
onClick: skip
|
|
8400
|
+
}] : void 0,
|
|
8366
8401
|
primary: {
|
|
8367
|
-
label: last ? finishLabel :
|
|
8402
|
+
label: last ? finishLabel : nextLabel,
|
|
8368
8403
|
icon: last ? /* @__PURE__ */ jsx(Check, {}) : /* @__PURE__ */ jsx(ArrowRight, {}),
|
|
8369
8404
|
onClick: next,
|
|
8370
8405
|
loading: busy,
|
|
@@ -8537,7 +8572,7 @@ function Section({ title, description, actions, level = 2, gap = "4", className,
|
|
|
8537
8572
|
* O título fica no header (com a trilha); aqui ele só é lido por leitores de tela,
|
|
8538
8573
|
* para que cada página tenha um único título principal (h1).
|
|
8539
8574
|
*/
|
|
8540
|
-
function PageHeader({ title, showTitle = false, description, help, breadcrumb, actions, children, className }) {
|
|
8575
|
+
function PageHeader({ title, showTitle = false, description, help, breadcrumb, actions, bodyTitle = false, titleSpace = "reserve", children, className }) {
|
|
8541
8576
|
const shell = useContext(ShellContext);
|
|
8542
8577
|
const setPageHelp = shell?.setPageHelp;
|
|
8543
8578
|
useEffect(() => {
|
|
@@ -8546,18 +8581,24 @@ function PageHeader({ title, showTitle = false, description, help, breadcrumb, a
|
|
|
8546
8581
|
return () => setPageHelp(null);
|
|
8547
8582
|
}, [help, setPageHelp]);
|
|
8548
8583
|
const inlineHelp = help && !shell;
|
|
8584
|
+
const visible = showTitle || bodyTitle || description || actions || breadcrumb || children || inlineHelp;
|
|
8585
|
+
const collapseTitle = titleSpace === "none" && !showTitle && !bodyTitle && !inlineHelp && !description;
|
|
8586
|
+
const titleClass = showTitle || inlineHelp ? "text-2xl md:text-3xl" : bodyTitle ? "text-base md:sr-only" : "sr-only";
|
|
8549
8587
|
return /* @__PURE__ */ jsxs("header", {
|
|
8550
|
-
className: cn("-mb-2 flex min-w-0 flex-col gap-4 md:-mb-4", !
|
|
8588
|
+
className: cn("-mb-2 flex min-w-0 flex-col gap-4 md:-mb-4", !visible && "sr-only", className),
|
|
8551
8589
|
children: [
|
|
8552
8590
|
breadcrumb && /* @__PURE__ */ jsx(Breadcrumb, { items: breadcrumb }),
|
|
8553
8591
|
/* @__PURE__ */ jsxs("div", {
|
|
8554
8592
|
className: "flex min-w-0 flex-col gap-4 md:flex-row md:items-center md:justify-between md:gap-6",
|
|
8555
|
-
children: [/* @__PURE__ */
|
|
8593
|
+
children: [collapseTitle ? /* @__PURE__ */ jsx("h1", {
|
|
8594
|
+
className: "sr-only",
|
|
8595
|
+
children: title
|
|
8596
|
+
}) : /* @__PURE__ */ jsxs("div", {
|
|
8556
8597
|
className: "flex min-w-0 flex-col gap-1",
|
|
8557
8598
|
children: [/* @__PURE__ */ jsxs("div", {
|
|
8558
8599
|
className: "flex min-w-0 items-center gap-1",
|
|
8559
8600
|
children: [/* @__PURE__ */ jsx("h1", {
|
|
8560
|
-
className:
|
|
8601
|
+
className: titleClass,
|
|
8561
8602
|
children: title
|
|
8562
8603
|
}), inlineHelp && /* @__PURE__ */ jsx(InfoHint, {
|
|
8563
8604
|
title: typeof title === "string" ? title : "Sobre esta tela",
|
|
@@ -9014,14 +9055,18 @@ function LayoutItems() {
|
|
|
9014
9055
|
}
|
|
9015
9056
|
function UserMenu() {
|
|
9016
9057
|
const Link = useRendraLink();
|
|
9017
|
-
const { user, userMenuItems, onLogout } = useShell();
|
|
9058
|
+
const { user, userMenuItems, onLogout, userMenu, workspaces } = useShell();
|
|
9018
9059
|
const { brand, brands, setBrandId, palette, palettes, setPaletteId } = useBrand();
|
|
9060
|
+
const showTheme = userMenu?.theme !== false;
|
|
9061
|
+
const showTemplate = userMenu?.template !== false;
|
|
9062
|
+
const showLayout = userMenu?.layout !== false;
|
|
9063
|
+
const showPreferences = showTheme || showTemplate || showLayout;
|
|
9019
9064
|
return /* @__PURE__ */ jsxs(DropdownMenu, { children: [/* @__PURE__ */ jsx(DropdownMenuTrigger, {
|
|
9020
9065
|
asChild: true,
|
|
9021
9066
|
children: /* @__PURE__ */ jsx(Button, {
|
|
9022
9067
|
variant: "ghost",
|
|
9023
9068
|
iconOnly: true,
|
|
9024
|
-
"aria-label":
|
|
9069
|
+
"aria-label": `${initials(user.name)}, menu de ${user.name}`,
|
|
9025
9070
|
children: /* @__PURE__ */ jsx(Avatar, {
|
|
9026
9071
|
name: user.name,
|
|
9027
9072
|
src: user.avatarUrl
|
|
@@ -9040,6 +9085,18 @@ function UserMenu() {
|
|
|
9040
9085
|
children: user.email
|
|
9041
9086
|
})]
|
|
9042
9087
|
}),
|
|
9088
|
+
workspaces && workspaces.items.length > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
9089
|
+
/* @__PURE__ */ jsx(DropdownMenuSeparator, {}),
|
|
9090
|
+
/* @__PURE__ */ jsx(DropdownMenuLabel, { children: workspaces.label ?? "Espaço" }),
|
|
9091
|
+
/* @__PURE__ */ jsx(DropdownMenuRadioGroup, {
|
|
9092
|
+
value: workspaces.activeId,
|
|
9093
|
+
onValueChange: workspaces.onSelect,
|
|
9094
|
+
children: workspaces.items.map((w) => /* @__PURE__ */ jsx(DropdownMenuRadioItem, {
|
|
9095
|
+
value: w.id,
|
|
9096
|
+
children: w.label
|
|
9097
|
+
}, w.id))
|
|
9098
|
+
})
|
|
9099
|
+
] }),
|
|
9043
9100
|
userMenuItems.length > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(DropdownMenuSeparator, {}), userMenuItems.map((item) => {
|
|
9044
9101
|
const Icon = item.icon;
|
|
9045
9102
|
return item.to ? /* @__PURE__ */ jsx(DropdownMenuItem, {
|
|
@@ -9053,9 +9110,9 @@ function UserMenu() {
|
|
|
9053
9110
|
children: [Icon && /* @__PURE__ */ jsx(Icon, { "aria-hidden": true }), item.label]
|
|
9054
9111
|
}, item.label);
|
|
9055
9112
|
})] }),
|
|
9056
|
-
/* @__PURE__ */ jsx(DropdownMenuSeparator, {}),
|
|
9057
|
-
/* @__PURE__ */ jsxs(DropdownMenuSub, { children: [/* @__PURE__ */ jsxs(DropdownMenuSubTrigger, { children: [/* @__PURE__ */ jsx(Sun, { "aria-hidden": true }), "Tema"] }), /* @__PURE__ */ jsx(DropdownMenuSubContent, { children: /* @__PURE__ */ jsx(ModeItems, {}) })] }),
|
|
9058
|
-
/* @__PURE__ */ jsxs(DropdownMenuSub, { children: [/* @__PURE__ */ jsxs(DropdownMenuSubTrigger, { children: [/* @__PURE__ */ jsx(Palette, { "aria-hidden": true }), "Template"] }), /* @__PURE__ */ jsxs(DropdownMenuSubContent, { children: [
|
|
9113
|
+
showPreferences && /* @__PURE__ */ jsx(DropdownMenuSeparator, {}),
|
|
9114
|
+
showTheme && /* @__PURE__ */ jsxs(DropdownMenuSub, { children: [/* @__PURE__ */ jsxs(DropdownMenuSubTrigger, { children: [/* @__PURE__ */ jsx(Sun, { "aria-hidden": true }), "Tema"] }), /* @__PURE__ */ jsx(DropdownMenuSubContent, { children: /* @__PURE__ */ jsx(ModeItems, {}) })] }),
|
|
9115
|
+
showTemplate && /* @__PURE__ */ jsxs(DropdownMenuSub, { children: [/* @__PURE__ */ jsxs(DropdownMenuSubTrigger, { children: [/* @__PURE__ */ jsx(Palette, { "aria-hidden": true }), "Template"] }), /* @__PURE__ */ jsxs(DropdownMenuSubContent, { children: [
|
|
9059
9116
|
/* @__PURE__ */ jsx(DropdownMenuLabel, { children: "Modelo" }),
|
|
9060
9117
|
/* @__PURE__ */ jsx(DropdownMenuRadioGroup, {
|
|
9061
9118
|
value: brand.id,
|
|
@@ -9085,7 +9142,7 @@ function UserMenu() {
|
|
|
9085
9142
|
}, b.id))
|
|
9086
9143
|
})
|
|
9087
9144
|
] })] }),
|
|
9088
|
-
/* @__PURE__ */ jsxs(DropdownMenuSub, { children: [/* @__PURE__ */ jsxs(DropdownMenuSubTrigger, { children: [/* @__PURE__ */ jsx(LayoutTemplate, { "aria-hidden": true }), "Layout"] }), /* @__PURE__ */ jsx(DropdownMenuSubContent, { children: /* @__PURE__ */ jsx(LayoutItems, {}) })] }),
|
|
9145
|
+
showLayout && /* @__PURE__ */ jsxs(DropdownMenuSub, { children: [/* @__PURE__ */ jsxs(DropdownMenuSubTrigger, { children: [/* @__PURE__ */ jsx(LayoutTemplate, { "aria-hidden": true }), "Layout"] }), /* @__PURE__ */ jsx(DropdownMenuSubContent, { children: /* @__PURE__ */ jsx(LayoutItems, {}) })] }),
|
|
9089
9146
|
/* @__PURE__ */ jsx(DropdownMenuSeparator, {}),
|
|
9090
9147
|
/* @__PURE__ */ jsxs(DropdownMenuItem, {
|
|
9091
9148
|
destructive: true,
|
|
@@ -9206,7 +9263,7 @@ function TopNav() {
|
|
|
9206
9263
|
});
|
|
9207
9264
|
}
|
|
9208
9265
|
function Header() {
|
|
9209
|
-
const { layout, setLayout, setMobileNavOpen, setSearchOpen, pageHelp, homeLabel, notifications } = useShell();
|
|
9266
|
+
const { layout, setLayout, setMobileNavOpen, setSearchOpen, pageHelp, homeLabel, notifications, headerLogo } = useShell();
|
|
9210
9267
|
const { brand, resolvedMode } = useBrand();
|
|
9211
9268
|
const Link = useRendraLink();
|
|
9212
9269
|
const crumbs = useRendraBreadcrumbs();
|
|
@@ -9218,12 +9275,16 @@ function Header() {
|
|
|
9218
9275
|
const topbar = layout.navigation === "topbar";
|
|
9219
9276
|
const hasParent = Boolean(crumbs.length >= 2 && crumbs[crumbs.length - 2]?.to);
|
|
9220
9277
|
const menuInFooter = layout.bottomNav || hasParent;
|
|
9221
|
-
const pageTitle = /* @__PURE__ */ jsxs("
|
|
9222
|
-
|
|
9278
|
+
const pageTitle = /* @__PURE__ */ jsxs(Fragment, { children: [headerLogo && /* @__PURE__ */ jsx("span", {
|
|
9279
|
+
"aria-hidden": true,
|
|
9280
|
+
className: "flex min-w-0 flex-1 items-center md:hidden",
|
|
9281
|
+
children: headerLogo
|
|
9282
|
+
}), /* @__PURE__ */ jsxs("div", {
|
|
9283
|
+
className: cn("flex min-w-0 flex-1 flex-col justify-center", headerLogo && "max-md:flex-none"),
|
|
9223
9284
|
children: [/* @__PURE__ */ jsxs("span", {
|
|
9224
9285
|
className: "flex min-w-0 items-center gap-1",
|
|
9225
9286
|
children: [/* @__PURE__ */ jsx("p", {
|
|
9226
|
-
className: "truncate text-sm leading-tight font-semibold md:text-base",
|
|
9287
|
+
className: cn("truncate text-sm leading-tight font-semibold md:text-base", headerLogo && "max-md:sr-only"),
|
|
9227
9288
|
children: crumbs[crumbs.length - 1]?.label ?? brand.productName
|
|
9228
9289
|
}), pageHelp && /* @__PURE__ */ jsx(InfoHint, {
|
|
9229
9290
|
title: crumbs[crumbs.length - 1]?.label ?? brand.productName,
|
|
@@ -9232,9 +9293,10 @@ function Header() {
|
|
|
9232
9293
|
})]
|
|
9233
9294
|
}), /* @__PURE__ */ jsx(Breadcrumb, {
|
|
9234
9295
|
items: trail,
|
|
9235
|
-
variant: "trail"
|
|
9296
|
+
variant: "trail",
|
|
9297
|
+
className: cn(headerLogo && "max-md:hidden")
|
|
9236
9298
|
})]
|
|
9237
|
-
});
|
|
9299
|
+
})] });
|
|
9238
9300
|
const collapsed = layout.sidebar === "collapsed";
|
|
9239
9301
|
return /* @__PURE__ */ jsxs("header", {
|
|
9240
9302
|
className: "relative z-30 flex h-header shrink-0 items-center gap-1 border-b bg-card px-2 md:gap-2 md:px-4",
|
|
@@ -9798,7 +9860,7 @@ function BottomNav({ onMenu }) {
|
|
|
9798
9860
|
* Título da aba e meta description (SEO) não são responsabilidade do AppShell: o
|
|
9799
9861
|
* boilerplate (src/app/app-layout.tsx) aplica isso com useRouteMeta, que lê @/config/seo.
|
|
9800
9862
|
*/
|
|
9801
|
-
function AppShell({ navigation, layout: layoutProp, user = defaultUser, userMenuItems = [], onLogout, homeLabel = "Início", quickActions = [], notifications, userConfigurable = true, children }) {
|
|
9863
|
+
function AppShell({ navigation, layout: layoutProp, user = defaultUser, userMenuItems = [], onLogout, homeLabel = "Início", quickActions = [], notifications, userMenu, workspaces, headerLogo, userConfigurable = true, children }) {
|
|
9802
9864
|
const [userLayout, setUserLayout] = useState(() => userConfigurable ? readUserLayout() : {});
|
|
9803
9865
|
const [mobileNavOpen, setMobileNavOpen] = useState(false);
|
|
9804
9866
|
const [searchOpen, setSearchOpen] = useState(false);
|
|
@@ -9861,7 +9923,10 @@ function AppShell({ navigation, layout: layoutProp, user = defaultUser, userMenu
|
|
|
9861
9923
|
onLogout,
|
|
9862
9924
|
homeLabel,
|
|
9863
9925
|
quickActions,
|
|
9864
|
-
notifications
|
|
9926
|
+
notifications,
|
|
9927
|
+
userMenu,
|
|
9928
|
+
workspaces,
|
|
9929
|
+
headerLogo
|
|
9865
9930
|
};
|
|
9866
9931
|
}, [
|
|
9867
9932
|
layout,
|
|
@@ -9878,7 +9943,10 @@ function AppShell({ navigation, layout: layoutProp, user = defaultUser, userMenu
|
|
|
9878
9943
|
onLogout,
|
|
9879
9944
|
homeLabel,
|
|
9880
9945
|
quickActions,
|
|
9881
|
-
notifications
|
|
9946
|
+
notifications,
|
|
9947
|
+
userMenu,
|
|
9948
|
+
workspaces,
|
|
9949
|
+
headerLogo
|
|
9882
9950
|
]);
|
|
9883
9951
|
return /* @__PURE__ */ jsx(ShellContext.Provider, {
|
|
9884
9952
|
value,
|