@actionexec/dashboards 0.6.0 → 0.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.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ColorPaletteSelector-BSAe2YMH.js","sources":["../src/api/fetcher.ts","../src/palettes/index.ts","../src/types/index.ts","../src/utils/grid.ts","../src/utils/date.ts","../src/components/DashboardDatePicker.tsx","../src/components/SearchableSelect.tsx","../src/components/ColorPaletteSelector.tsx"],"sourcesContent":["// Purpose: Client HTTP interno da API Action (endpoints /external/dashboards).\n// Scope: Infraestrutura da lib — nao exportado no index publico. Consumidor\n// externo usa <Dashboard token /> que encapsula tudo.\n// Public API (interno): fetchLayout, fetchRender, ApiError, setApiUrl\n\nimport type { LayoutResponse, RenderResponse } from '../types';\n\nconst DEFAULT_API_URL = 'https://action-data-api-7mbrztperq-rj.a.run.app';\nconst ENDPOINT_PREFIX = '/external/dashboards';\n\n// URL efetiva — pode ser sobrescrita via `setApiUrl` (uso interno em dev).\nlet apiUrl = DEFAULT_API_URL;\n\n/** Sobrescreve a URL base da API. Destinado ao builder da plataforma em dev —\n * consumidores externos nao devem chamar (usam a URL de producao por default). */\nexport function setApiUrl(url: string): void {\n apiUrl = url.replace(/\\/$/, '');\n}\n\nexport class ApiError extends Error {\n constructor(\n message: string,\n public status?: number,\n public payload?: unknown,\n ) {\n super(message);\n this.name = 'ApiError';\n }\n}\n\nasync function get<T>(path: string, token: string, params?: Record<string, string>): Promise<T> {\n const url = new URL(`${apiUrl}${ENDPOINT_PREFIX}${path}`);\n if (params) {\n for (const [k, v] of Object.entries(params)) url.searchParams.set(k, v);\n }\n\n const res = await fetch(url.toString(), {\n headers: { Authorization: `Bearer ${token}` },\n });\n\n if (!res.ok) {\n let payload: unknown;\n try { payload = await res.json(); } catch { /* non-json */ }\n throw new ApiError(\n `Requisicao falhou (${res.status}) em ${path}`,\n res.status,\n payload,\n );\n }\n return (await res.json()) as T;\n}\n\nexport const fetchLayout = (token: string) =>\n get<LayoutResponse>('/layout', token);\n\nexport const fetchRender = (token: string, params?: Record<string, string>) =>\n get<RenderResponse>('/render', token, params);\n","// Purpose: Paletas de cores completas para dashboards (series de dados + cores de UI).\n// Scope: Define paletas com 13 slots semanticos (5 series + 8 cores de UI) e helpers\n// para extrair series e gerar CSS variables aplicaveis ao escopo do dashboard.\n// Public API: PALETTES, PaletteKey, Palette, getSeries, getPaletteCssVars,\n// SLOT_INDEX, SLOT_LABELS, DEFAULT_PALETTE_COLORS, ensurePaletteShape\n\nexport interface Palette {\n label: string;\n colors: string[]; // 13 cores ordenadas pelos slots semanticos\n}\n\nexport type PaletteKey = 'action' | 'westCoast' | 'mono' | 'ocean' | 'princess';\n\n// -------Slots semanticos (indices fixos no array de cores)-------\n//\n// Convencao posicional para manter o storage como string[] (compativel com schemas\n// Pydantic e o tipo `PaletteConfig.paletteColors`). Cada paleta deve ter 13 cores.\n\nexport const SLOT_INDEX = {\n series0: 0,\n series1: 1,\n series2: 2,\n series3: 3,\n series4: 4,\n bgDark: 5,\n bgPaper: 6,\n bgElevated: 7,\n textPrimary: 8,\n textMuted: 9,\n accent: 10,\n success: 11,\n error: 12,\n} as const;\n\nexport const SERIES_COUNT = 5;\nexport const TOTAL_SLOTS = 13;\n\nexport const SLOT_LABELS: Record<keyof typeof SLOT_INDEX, string> = {\n series0: 'Série 1',\n series1: 'Série 2',\n series2: 'Série 3',\n series3: 'Série 4',\n series4: 'Série 5',\n bgDark: 'Fundo Escuro',\n bgPaper: 'Fundo Cartão',\n bgElevated: 'Fundo Elevado',\n textPrimary: 'Texto Primário',\n textMuted: 'Texto Secundário',\n accent: 'Destaque',\n success: 'Sucesso',\n error: 'Erro',\n};\n\n// -------Presets-------\n\nexport const PALETTES: Record<PaletteKey, Palette> = {\n action: {\n label: 'Action',\n colors: [\n '#ff6b00', '#a3e635', '#e3f544', '#65ffd1', '#ff0404',\n '#1a1a1a',\n '#262626',\n '#333333',\n '#f5f5f5',\n '#999999',\n '#ff6b00',\n '#a3e635',\n '#ef4444',\n ],\n },\n westCoast: {\n label: 'West Coast',\n colors: [\n '#a3b86c', '#c89b3c', '#8b6f47', '#6b8e23', '#d2691e',\n '#1f1a14',\n '#2a241b',\n '#3a3225',\n '#e8dcc4',\n '#a89878',\n '#c89b3c',\n '#a3b86c',\n '#c44536',\n ],\n },\n mono: {\n label: 'Monocromático',\n colors: [\n '#f8fafc', '#cbd5e1', '#94a3b8', '#64748b', '#475569',\n '#0a0a0a',\n '#171717',\n '#262626',\n '#fafafa',\n '#a3a3a3',\n '#e5e5e5',\n '#cbd5e1',\n '#ef4444',\n ],\n },\n ocean: {\n label: 'Ocean',\n colors: [\n '#0ea5e9', '#06b6d4', '#0891b2', '#3b82f6', '#22d3ee',\n '#0a1929',\n '#0f2740',\n '#173554',\n '#e0f2fe',\n '#7dd3fc',\n '#22d3ee',\n '#10b981',\n '#f43f5e',\n ],\n },\n princess: {\n label: 'Cute Pink',\n colors: [\n '#ff79bc', '#a855f7', '#f472b6', '#d946ef', '#fb7185',\n '#fff0f6',\n '#ffe4ec',\n '#ffffff',\n '#ff4099',\n '#ffadd5',\n '#ec4899',\n '#10b981',\n '#e11d48',\n ],\n },\n};\n\nexport const DEFAULT_PALETTE: PaletteKey = 'action';\n\n// Array de cores default expandido (13 slots)\nexport const DEFAULT_PALETTE_COLORS: string[] = PALETTES.action.colors;\n\n// -------Helpers-------\n\n/** Garante que a paleta tem TOTAL_SLOTS cores. Preenche faltantes com fallback do default. */\nexport function ensurePaletteShape(colors?: string[]): string[] {\n const fallback = DEFAULT_PALETTE_COLORS;\n if (!colors || colors.length === 0) return [...fallback];\n if (colors.length >= TOTAL_SLOTS) return colors.slice(0, TOTAL_SLOTS);\n const result = [...colors];\n for (let i = colors.length; i < TOTAL_SLOTS; i++) result.push(fallback[i]);\n return result;\n}\n\n/** Extrai apenas as cores de series (uso em charts/gauge). */\nexport function getSeries(colors?: string[]): string[] {\n const full = ensurePaletteShape(colors);\n return full.slice(0, SERIES_COUNT);\n}\n\n/** Gera objeto de CSS variables para aplicar inline no escopo do dashboard. */\nexport function getPaletteCssVars(colors?: string[]): Record<string, string> {\n const c = ensurePaletteShape(colors);\n return {\n '--bg-dark': c[SLOT_INDEX.bgDark],\n '--bg-paper': c[SLOT_INDEX.bgPaper],\n '--bg-elevated': c[SLOT_INDEX.bgElevated],\n '--text-primary': c[SLOT_INDEX.textPrimary],\n '--text-secondary': c[SLOT_INDEX.textMuted],\n '--text-muted': c[SLOT_INDEX.textMuted],\n '--action-orange': c[SLOT_INDEX.accent],\n '--action-green': c[SLOT_INDEX.success],\n '--color-success': c[SLOT_INDEX.success],\n '--color-error': c[SLOT_INDEX.error],\n '--color-info': c[SLOT_INDEX.series2],\n '--color-warning': c[SLOT_INDEX.series3],\n };\n}\n","// Purpose: Tipos compartilhados entre backend Python (schemas Pydantic) e frontend.\r\n// Scope: Union discriminada de WidgetDefinition, configs por tipo, respostas da API.\r\n// Public API: Todos os tipos e interfaces exportados + defaults + labels.\r\n\r\nimport { DEFAULT_PALETTE_COLORS } from '../palettes';\r\n\r\n// -------Enums como string literals-------\r\n\r\nexport type AggregationType = 'sum' | 'avg' | 'count' | 'min' | 'max' | 'count_distinct';\r\nexport type ComparisonType = 'yoy' | 'mom' | 'target' | 'none';\r\nexport type FilterType = 'date_range' | 'select' | 'multi_select';\r\nexport type WidgetType = 'kpi_card' | 'gauge' | 'chart' | 'filter' | 'variable' | 'color_palette' | 'table';\r\nexport type DataWidgetType = 'kpi_card' | 'gauge' | 'chart' | 'table';\r\nexport type ControlWidgetType = 'filter' | 'variable' | 'color_palette';\r\nexport type ChartType = 'bar' | 'line' | 'area' | 'pie';\r\nexport type FormatType = 'currency' | 'number' | 'integer' | 'percentage' | 'date' | 'text';\r\nexport type DateFilterMode = 'range' | 'monthly' | 'weekly' | 'yearly';\r\nexport type Granularity = 'day' | 'week' | 'month' | 'year' | 'weekday';\r\n\r\n// -------Pedacos compartilhados pelos configs-------\r\n\r\nexport interface FilterDefinition {\r\n id: string;\r\n type: FilterType;\r\n label: string;\r\n column?: string | null;\r\n defaultValue?: unknown;\r\n}\r\n\r\nexport interface TargetDefinition {\r\n id: string;\r\n label: string;\r\n value: number;\r\n format: FormatType;\r\n}\r\n\r\nexport interface GridPosition {\r\n x: number;\r\n y: number;\r\n w: number;\r\n h: number;\r\n}\r\n\r\nexport interface ComparisonConfig {\r\n type: ComparisonType;\r\n targetId?: string;\r\n}\r\n\r\nexport interface AggregationStep {\r\n aggregation: AggregationType;\r\n groupBy: string;\r\n groupGranularity?: Granularity;\r\n}\r\n\r\nexport interface ColumnExpressionTerm {\r\n column: string;\r\n operator?: '+' | '-' | '*' | '/';\r\n}\r\n\r\nexport interface KpiOperand {\r\n column?: string;\r\n columnExpression?: ColumnExpressionTerm[];\r\n intermediateSteps?: AggregationStep[];\r\n finalAggregation?: AggregationType;\r\n constant?: number;\r\n}\r\n\r\nexport interface KpiTerm {\r\n operand: KpiOperand;\r\n operator?: '+' | '-' | '*' | '/'; // undefined apenas no primeiro termo\r\n}\r\n\r\nexport interface ChartSeriesConfig {\r\n label: string;\r\n // Formula simples\r\n column?: string;\r\n aggregation?: AggregationType;\r\n // Formula composta (pipeline identico ao KPI card, avaliado por grupo do eixo X)\r\n kpiTerms?: KpiTerm[];\r\n}\r\n\r\nexport interface ChartAxisConfig {\r\n column: string;\r\n granularity: Granularity;\r\n}\r\n\r\n// -------Config por tipo de widget-------\r\n\r\n// IDs de widgets de filtro que NAO se aplicam ao widget (default: todos aplicam).\r\n// Compartilhado pelos widgets de dados (kpi_card, gauge, chart).\r\nexport interface WidgetFilterTargeting {\r\n excludedFilters?: string[];\r\n}\r\n\r\nexport interface KpiCardConfig extends WidgetFilterTargeting {\r\n label: string;\r\n format?: FormatType;\r\n column?: string;\r\n aggregation?: AggregationType;\r\n groupBy?: string;\r\n groupGranularity?: Granularity;\r\n outerAggregation?: AggregationType;\r\n kpiTerms?: KpiTerm[];\r\n comparison?: ComparisonConfig;\r\n filterExpression?: Record<string, unknown>;\r\n}\r\n\r\nexport interface GaugeConfig extends WidgetFilterTargeting {\r\n label: string;\r\n format?: FormatType;\r\n column?: string;\r\n aggregation?: AggregationType;\r\n targetId?: string;\r\n comparison?: ComparisonConfig;\r\n kpiTerms?: KpiTerm[];\r\n groupBy?: string;\r\n groupGranularity?: Granularity;\r\n outerAggregation?: AggregationType;\r\n filterExpression?: Record<string, unknown>;\r\n}\r\n\r\nexport interface ChartConfig extends WidgetFilterTargeting {\r\n label: string;\r\n chartType?: ChartType;\r\n xAxis?: ChartAxisConfig;\r\n series?: ChartSeriesConfig[];\r\n categoryColumn?: string;\r\n format?: FormatType;\r\n filterExpression?: Record<string, unknown>;\r\n}\r\n\r\nexport interface TableColumnConfig {\r\n column: string; // chave da coluna no row_data\r\n label?: string; // rotulo do cabecalho (default: column)\r\n format?: FormatType; // formatacao da celula (default: text)\r\n}\r\n\r\nexport interface TableTabConfig {\r\n label: string; // rotulo da aba\r\n filterExpression?: Record<string, unknown>; // filtro proprio da aba (soma ao do widget)\r\n}\r\n\r\nexport interface TableConfig extends WidgetFilterTargeting {\r\n label: string;\r\n columns?: TableColumnConfig[]; // colunas a exibir (vazio = todas do dataset)\r\n tabs?: TableTabConfig[]; // abas que trocam o filtro (vazio = tabela unica)\r\n sortBy?: string; // coluna de ordenacao\r\n sortDir?: 'asc' | 'desc';\r\n limit?: number; // maximo de linhas\r\n filterExpression?: Record<string, unknown>;\r\n}\r\n\r\nexport interface FilterConfig {\r\n label: string;\r\n filterType: FilterType;\r\n filterColumn?: string;\r\n defaultValue?: unknown;\r\n dateFilterMode?: DateFilterMode;\r\n // Apresentacao categorica: true = lista com busca por digitacao; ausente = padrao\r\n // (select unico / checkboxes). Aplica-se a select e multi_select; nao afeta a query.\r\n searchable?: boolean;\r\n}\r\n\r\nexport interface VariableConfig {\r\n label: string;\r\n variableValue?: number;\r\n variableFormat?: FormatType;\r\n locked?: boolean;\r\n}\r\n\r\nexport interface PaletteConfig {\r\n paletteColors: string[];\r\n label?: string;\r\n locked?: boolean;\r\n}\r\n\r\nexport type AnyWidgetConfig =\r\n | KpiCardConfig | GaugeConfig | ChartConfig | TableConfig\r\n | FilterConfig | VariableConfig | PaletteConfig;\r\n\r\n// -------Union discriminada de WidgetDefinition-------\r\n\r\nexport type WidgetDefinition =\r\n | { id: string; type: 'kpi_card'; grid: GridPosition; config: KpiCardConfig }\r\n | { id: string; type: 'gauge'; grid: GridPosition; config: GaugeConfig }\r\n | { id: string; type: 'chart'; grid: GridPosition; config: ChartConfig }\r\n | { id: string; type: 'table'; grid: GridPosition; config: TableConfig }\r\n | { id: string; type: 'filter'; grid: GridPosition; config: FilterConfig }\r\n | { id: string; type: 'variable'; grid: GridPosition; config: VariableConfig }\r\n | { id: string; type: 'color_palette'; grid: GridPosition; config: PaletteConfig };\r\n\r\nexport type WidgetConfigOf<T extends WidgetType> = Extract<WidgetDefinition, { type: T }>['config'];\r\n\r\n// -------Layout completo-------\r\n\r\nexport interface DashboardLayout {\r\n gridColumns: number;\r\n gridRows: number;\r\n widgets: WidgetDefinition[];\r\n}\r\n\r\n// -------Respostas da API-------\r\n\r\nexport interface FilterValuesResponse {\r\n date_bounds: { min: string | null; max: string | null };\r\n filter_options: Record<string, string[]>;\r\n headers: string[];\r\n column_types: Record<string, string>;\r\n}\r\n\r\nexport interface RenderResponse {\r\n date_bounds: { min: string; max: string };\r\n applied: Record<string, unknown>;\r\n widgets: Record<string, Record<string, unknown>>;\r\n}\r\n\r\nexport interface LayoutResponse {\r\n name: string;\r\n palette: string[];\r\n gridColumns: number;\r\n gridRows: number;\r\n dateBounds: { min: string; max: string };\r\n widgets: WidgetDefinition[];\r\n}\r\n\r\n// -------Defaults-------\r\n\r\n// Re-export para compatibilidade com codigo existente que importa de dashboardLayout\r\nexport const DEFAULT_PALETTE = DEFAULT_PALETTE_COLORS;\r\n\r\nexport const DEFAULT_GRID_COLUMNS = 30;\r\nexport const DEFAULT_GRID_ROWS = 10;\r\n\r\nexport const EMPTY_LAYOUT: DashboardLayout = {\r\n gridColumns: DEFAULT_GRID_COLUMNS,\r\n gridRows: DEFAULT_GRID_ROWS,\r\n widgets: [],\r\n};\r\n\r\nexport const WIDGET_TYPE_LABELS: Record<WidgetType, string> = {\r\n kpi_card: 'KPI Card',\r\n gauge: 'Gauge',\r\n chart: 'Gráfico',\r\n table: 'Tabela',\r\n filter: 'Filtro',\r\n variable: 'Variável',\r\n color_palette: 'Paleta de Cores',\r\n};\r\n\r\nexport const DATA_WIDGET_TYPES: DataWidgetType[] = ['kpi_card', 'gauge', 'chart', 'table'];\r\nexport const CONTROL_WIDGET_TYPES: ControlWidgetType[] = ['filter', 'variable', 'color_palette'];\r\nexport const CONTROL_WIDGET_SET = new Set<WidgetType>(['filter', 'variable', 'color_palette']);\r\n\r\nexport const AGGREGATION_LABELS: Record<AggregationType, string> = {\r\n sum: 'Soma',\r\n avg: 'Média',\r\n count: 'Contagem',\r\n min: 'Mínimo',\r\n max: 'Máximo',\r\n count_distinct: 'Contagem Distinta',\r\n};\r\n\r\nexport const FORMAT_LABELS: Record<FormatType, string> = {\r\n currency: 'Moeda (R$)',\r\n number: 'Número',\r\n integer: 'Inteiro',\r\n percentage: 'Porcentagem',\r\n date: 'Data',\r\n text: 'Texto',\r\n};\r\n\r\n// Subset de formatos numericos — usado nos configs de KPI, Gauge, Variable\r\nexport const NUMERIC_FORMAT_OPTIONS = Object.entries(FORMAT_LABELS)\r\n .filter(([k]) => k !== 'date' && k !== 'text') as [FormatType, string][];\r\n\r\nexport const COMPARISON_LABELS: Record<ComparisonType, string> = {\r\n yoy: 'vs Ano Anterior',\r\n mom: 'vs Mês Anterior',\r\n target: 'vs Meta',\r\n none: 'Nenhuma',\r\n};\r\n\r\nexport const CHART_TYPE_LABELS: Record<ChartType, string> = {\r\n bar: 'Barras',\r\n line: 'Linhas',\r\n area: 'Área',\r\n pie: 'Pizza',\r\n};\r\n\r\nexport const FILTER_TYPE_LABELS: Record<FilterType, string> = {\r\n date_range: 'Periodo',\r\n select: 'Seleção Única',\r\n multi_select: 'Seleção Múltipla',\r\n};\r\n\r\n// Separador interno dos valores de filtros multi_select. Usa o caractere de controle\r\n// Unit Separator (U+001F), que nunca aparece em nomes de produtos — evita a colisao\r\n// que a virgula causava quando o proprio valor continha virgula.\r\n// DEVE ser identico ao separador usado no backend (filters.py).\r\nexport const MULTI_VALUE_SEPARATOR = '\\u001f';\r\n\r\n// -------Default grid sizes por tipo de widget-------\r\n\r\nexport const DEFAULT_GRID: Record<WidgetType, GridPosition> = {\r\n kpi_card: { x: 0, y: 0, w: 6, h: 3 },\r\n gauge: { x: 0, y: 0, w: 6, h: 5 },\r\n chart: { x: 0, y: 0, w: 6, h: 6 },\r\n table: { x: 0, y: 0, w: 12, h: 7 },\r\n filter: { x: 0, y: 0, w: 4, h: 2 },\r\n variable: { x: 0, y: 0, w: 4, h: 2 },\r\n color_palette: { x: 0, y: 0, w: 4, h: 2 },\r\n};\r\n\r\nexport const DEFAULT_CONFIG: { [K in WidgetType]: Partial<WidgetConfigOf<K>> } = {\r\n kpi_card: { label: 'Novo KPI', aggregation: 'sum', format: 'number' },\r\n gauge: { label: 'Novo Gauge', aggregation: 'sum' },\r\n chart: { label: 'Novo Grafico', chartType: 'bar', xAxis: { column: '', granularity: 'day' }, series: [] },\r\n table: { label: 'Nova Tabela', columns: [] },\r\n filter: { label: 'Novo Filtro', filterType: 'select' },\r\n variable: { label: 'Nova Variavel', variableValue: 0, variableFormat: 'number', locked: false },\r\n color_palette: { label: 'Paleta de Cores', paletteColors: DEFAULT_PALETTE, locked: false },\r\n};\r\n","// Purpose: Geometria do grid — fonte unica compartilhada pelo runtime (Dashboard)\n// e pelo editor de layout da plataforma Action (CanvasEditor).\n// Scope: Constantes de espacamento e funcoes puras que projetam celulas do grid\n// em pixels. Nenhuma dependencia de React ou DOM.\n// Public API: GRID_GAP_PX, GRID_PADDING_PX, CELL_ASPECT, MIN_CELL_HEIGHT_PX,\n// MAX_CELL_HEIGHT_PX, computeCellWidth, computeCellHeight,\n// computeGridHeight, computeWidgetAspect, computeStackThreshold,\n// DashboardGeometry.\n\n/** Espaco entre celulas, em px. Absoluto de proposito: ver nota de proporcao abaixo. */\nexport const GRID_GAP_PX = 6;\n\n/** Recuo interno do grid, em px. Deve espelhar --spacing-md dos tokens. */\nexport const GRID_PADDING_PX = 16;\n\n/**\n * Proporcao largura/altura da celula. 1 = celula quadrada.\n *\n * A largura da celula e sempre fluida (largura disponivel / numero de colunas).\n * Fixar a proporcao faz a altura acompanhar, de modo que o dashboard mantenha\n * a mesma forma em qualquer aplicacao que o embuta — que e o unico jeito de o\n * editor ser WYSIWYG.\n *\n * O valor 1 nao e arbitrario: com 30 colunas num container de 1440px a coluna\n * mede ~41px, praticamente a altura de linha fixa de 40px usada ate a v0.6.\n * Adotar celula quadrada preserva a aparencia dos dashboards ja montados.\n */\nexport const CELL_ASPECT = 1;\n\n/**\n * Trilhos de seguranca da altura da celula.\n *\n * Fora dessa faixa a proporcao deixa de valer de proposito: abaixo do minimo o\n * dashboard seria pequeno demais para ser lido (container estreito), acima do\n * maximo seria alto demais para caber na viewport (monitor ultrawide). Uma forma\n * levemente distorcida e preferivel a um dashboard inutilizavel.\n *\n * Com 30 colunas, os limites entram abaixo de ~930px e acima de ~2600px de\n * container — ou seja, a proporcao se mantem intacta em toda a faixa de desktop.\n */\nexport const MIN_CELL_HEIGHT_PX = 24;\nexport const MAX_CELL_HEIGHT_PX = 80;\n\nconst clamp = (value: number, min: number, max: number) => Math.min(Math.max(value, min), max);\n\n/**\n * Medida utilizavel: positiva e finita.\n *\n * `cellAspect` e prop publica tipada `number`, e o numero de colunas vem da API —\n * nenhum dos dois barra NaN ou Infinity. Sem esta guarda um NaN atravessa\n * `value <= 0` (que e falso para NaN) e contamina todo o calculo ate virar\n * `--dash-cell-h: NaNpx`, que invalida a declaracao e derruba o grid inteiro.\n */\nconst isUsable = (value: number) => Number.isFinite(value) && value > 0;\n\n/**\n * Largura de uma coluna do grid.\n *\n * `outerWidth` e a largura de borda do elemento do grid (inclui o recuo interno).\n * Identica a formula do react-grid-layout (calcGridColWidth), o que garante que\n * editor e runtime cheguem ao mesmo numero.\n */\nexport function computeCellWidth(\n outerWidth: number,\n columns: number,\n gap: number = GRID_GAP_PX,\n padding: number = GRID_PADDING_PX,\n): number {\n if (!isUsable(columns) || !Number.isFinite(outerWidth)) return 0;\n const available = outerWidth - padding * 2 - gap * (columns - 1);\n return Math.max(0, available / columns);\n}\n\n/** Altura de linha que preserva a proporcao da celula, respeitando os trilhos. */\nexport function computeCellHeight(cellWidth: number, aspect: number = CELL_ASPECT): number {\n if (!isUsable(cellWidth) || !isUsable(aspect)) return MIN_CELL_HEIGHT_PX;\n return clamp(cellWidth / aspect, MIN_CELL_HEIGHT_PX, MAX_CELL_HEIGHT_PX);\n}\n\n/** Altura total ocupada por `rows` linhas, incluindo gaps e recuo interno. */\nexport function computeGridHeight(\n rows: number,\n cellHeight: number,\n gap: number = GRID_GAP_PX,\n padding: number = GRID_PADDING_PX,\n): number {\n if (rows <= 0) return padding * 2;\n return rows * cellHeight + (rows - 1) * gap + padding * 2;\n}\n\n/**\n * Proporcao largura/altura de um widget de `w` x `h` celulas.\n *\n * Ignora o gap interno do widget de proposito: incluir o termo tornaria a\n * proporcao dependente da largura da celula, e portanto nao seria constante.\n * O desvio e o mesmo ~2% que a celula quadrada ja tem, e em troca a proporcao\n * pode ser expressa em CSS puro (`aspect-ratio`), sem medicao.\n */\nexport function computeWidgetAspect(w: number, h: number, aspect: number = CELL_ASPECT): number {\n if (!isUsable(w) || !isUsable(h) || !isUsable(aspect)) return 1;\n return (w * aspect) / h;\n}\n\n/**\n * Largura de container abaixo da qual a proporcao deixa de ser respeitada —\n * o ponto em que a celula bateria em MIN_CELL_HEIGHT_PX.\n *\n * E o limiar natural para trocar de modo: abaixo dele o layout em colunas ja\n * esta distorcido, e empilhar passa a ser a apresentacao mais fiel.\n *\n * Depende da proporcao: como a altura e `cellWidth / aspect`, o piso e atingido\n * quando a largura da celula chega a `MIN_CELL_HEIGHT_PX * aspect`, nao a\n * MIN_CELL_HEIGHT_PX. Ignorar o aspect erraria o limiar para qualquer valor\n * diferente de 1 — com aspect 2 e 30 colunas, por 720px.\n */\nexport function computeStackThreshold(\n columns: number,\n aspect: number = CELL_ASPECT,\n gap: number = GRID_GAP_PX,\n padding: number = GRID_PADDING_PX,\n): number {\n if (!isUsable(columns) || !isUsable(aspect)) return 0;\n return MIN_CELL_HEIGHT_PX * aspect * columns + gap * (columns - 1) + padding * 2;\n}\n\n/** Geometria corrente do grid, reportada ao consumidor via `onGeometryChange`. */\nexport interface DashboardGeometry {\n /** Largura de borda do container do dashboard, em px. */\n containerWidth: number;\n /** Largura da celula do grid. Sem efeito enquanto `stacked` for true. */\n cellWidth: number;\n /** Altura da celula do grid. Sem efeito enquanto `stacked` for true. */\n cellHeight: number;\n /** Altura renderizada do grid, em px — o que o host precisa acomodar. */\n gridHeight: number;\n /** Se o dashboard esta renderizando em coluna unica. */\n stacked: boolean;\n}\n","// Purpose: Utilitarios de data para filtros temporais de dashboards.\n// Scope: Calculo de intervalos anuais/mensais/semanais, parse de ranges, ISO week.\n// Public API: MONTH_NAMES_*, getFullYearRange, getMonthRange, getWeekRange, getISOWeek,\n// getWeeksInMonth, parseYearFromRange, parseMonthFromRange, parseWeekFromRange,\n// getYearRange, getMonthWeeks, MonthWeek\n\nexport const MONTH_NAMES_SHORT = [\n 'Jan', 'Fev', 'Mar', 'Abr', 'Mai', 'Jun',\n 'Jul', 'Ago', 'Set', 'Out', 'Nov', 'Dez',\n];\n\nexport const MONTH_NAMES_FULL = [\n 'Janeiro', 'Fevereiro', 'Marco', 'Abril', 'Maio', 'Junho',\n 'Julho', 'Agosto', 'Setembro', 'Outubro', 'Novembro', 'Dezembro',\n];\n\nexport function getFullYearRange(year: number): { start: string; end: string } {\n return { start: `${year}-01-01`, end: `${year}-12-31` };\n}\n\nexport function parseYearFromRange(start: string): { year: number } | null {\n if (!start) return null;\n const m = start.match(/^(\\d{4})/);\n return m ? { year: parseInt(m[1]) } : null;\n}\n\nexport function getMonthRange(year: number, month: number): { start: string; end: string } {\n const lastDay = new Date(year, month, 0).getDate();\n const pad = (n: number) => String(n).padStart(2, '0');\n return {\n start: `${year}-${pad(month)}-01`,\n end: `${year}-${pad(month)}-${pad(lastDay)}`,\n };\n}\n\nexport function getISOWeek(dt: Date): number {\n const d = new Date(Date.UTC(dt.getFullYear(), dt.getMonth(), dt.getDate()));\n d.setUTCDate(d.getUTCDate() + 4 - (d.getUTCDay() || 7));\n const yearStart = new Date(Date.UTC(d.getUTCFullYear(), 0, 1));\n return Math.ceil(((d.getTime() - yearStart.getTime()) / 86400000 + 1) / 7);\n}\n\nexport function getWeekRange(year: number, week: number): { start: string; end: string } {\n const jan4 = new Date(year, 0, 4);\n const dayOfWeek = (jan4.getDay() + 6) % 7;\n const firstMonday = new Date(jan4.getTime() - dayOfWeek * 86400000);\n const start = new Date(firstMonday.getTime() + (week - 1) * 7 * 86400000);\n const end = new Date(start.getTime() + 6 * 86400000);\n const pad = (n: number) => String(n).padStart(2, '0');\n const fmt = (d: Date) => `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}`;\n return { start: fmt(start), end: fmt(end) };\n}\n\nexport function getWeeksInMonth(year: number, month: number): number[] {\n const weeks: Set<number> = new Set();\n const daysInMonth = new Date(year, month, 0).getDate();\n for (let d = 1; d <= daysInMonth; d++) {\n weeks.add(getISOWeek(new Date(year, month - 1, d)));\n }\n return Array.from(weeks).sort((a, b) => a - b);\n}\n\nexport interface MonthWeek {\n index: number;\n startDay: number;\n endDay: number;\n start: string;\n end: string;\n label: string;\n}\n\nexport function getMonthWeeks(year: number, month: number): MonthWeek[] {\n const daysInMonth = new Date(year, month, 0).getDate();\n const pad = (n: number) => String(n).padStart(2, '0');\n const weeks: MonthWeek[] = [];\n let day = 1;\n let index = 1;\n\n while (day <= daysInMonth) {\n const startDay = day;\n const endDay = Math.min(day + 6, daysInMonth);\n const start = `${year}-${pad(month)}-${pad(startDay)}`;\n const end = `${year}-${pad(month)}-${pad(endDay)}`;\n const label = `${index}° Semana (${pad(startDay)}/${pad(month)} - ${pad(endDay)}/${pad(month)})`;\n weeks.push({ index, startDay, endDay, start, end, label });\n day = endDay + 1;\n index++;\n }\n\n return weeks;\n}\n\nexport function parseMonthWeekFromRange(start: string, year: number, month: number): number {\n if (!start) return 1;\n const pad = (n: number) => String(n).padStart(2, '0');\n const dayMatch = start.match(new RegExp(`^${year}-${pad(month)}-(\\\\d{2})`));\n if (!dayMatch) return 1;\n const day = parseInt(dayMatch[1]);\n return Math.ceil(day / 7);\n}\n\nexport function parseMonthFromRange(start: string): { year: number; month: number } | null {\n if (!start) return null;\n const m = start.match(/^(\\d{4})-(\\d{2})/);\n return m ? { year: parseInt(m[1]), month: parseInt(m[2]) } : null;\n}\n\nexport function parseWeekFromRange(start: string): { year: number; week: number } | null {\n if (!start) return null;\n const d = new Date(start + 'T00:00:00');\n if (isNaN(d.getTime())) return null;\n return { year: d.getFullYear(), week: getISOWeek(d) };\n}\n\nexport function getYearRange(dateBounds?: { min: string | null; max: string | null } | null): number[] {\n const now = new Date();\n const minYear = dateBounds?.min ? parseInt(dateBounds.min.slice(0, 4)) : now.getFullYear() - 2;\n const maxYear = dateBounds?.max ? parseInt(dateBounds.max.slice(0, 4)) : now.getFullYear();\n const years: number[] = [];\n for (let y = maxYear; y >= minYear; y--) years.push(y);\n return years;\n}\n","// Purpose: Wrapper react-datepicker para dashboards.\n// Scope: Converte YYYY-MM-DD <-> Date, aplica estilos escopados via .ddp-field.\n// Public API: DashboardDatePicker, isoToDate, dateToIso\n\nimport DatePicker from 'react-datepicker';\nimport 'react-datepicker/dist/react-datepicker.css';\n\n// -------Helpers ISO <-> Date-------\n// Usam local-time para evitar timezone shift (toISOString() converte para UTC).\n\nexport function isoToDate(iso?: string | null): Date | null {\n if (!iso) return null;\n const [y, m, d] = iso.split('-').map(Number);\n if (!y || !m || !d) return null;\n return new Date(y, m - 1, d);\n}\n\nexport function dateToIso(date?: Date | null): string {\n if (!date) return '';\n const y = date.getFullYear();\n const m = String(date.getMonth() + 1).padStart(2, '0');\n const d = String(date.getDate()).padStart(2, '0');\n return `${y}-${m}-${d}`;\n}\n\n// -------Componente-------\n\ninterface Props {\n value: string; // 'YYYY-MM-DD' ou ''\n onChange: (iso: string) => void; // emite '' quando limpo\n minIso?: string | null;\n maxIso?: string | null;\n placeholder?: string;\n selectsStart?: boolean;\n selectsEnd?: boolean;\n startIso?: string | null;\n endIso?: string | null;\n className?: string;\n disabled?: boolean;\n}\n\nexport function DashboardDatePicker({\n value, onChange, minIso, maxIso, placeholder,\n selectsStart, selectsEnd, startIso, endIso, className, disabled,\n}: Props) {\n return (\n <div className={`ddp-field ${className ?? ''}`}>\n <DatePicker\n selected={isoToDate(value)}\n onChange={(d: Date | null) => onChange(dateToIso(d))}\n selectsStart={selectsStart}\n selectsEnd={selectsEnd}\n startDate={isoToDate(startIso) ?? undefined}\n endDate={isoToDate(endIso) ?? undefined}\n minDate={isoToDate(minIso) ?? undefined}\n maxDate={isoToDate(maxIso) ?? undefined}\n dateFormat=\"dd/MM/yyyy\"\n placeholderText={placeholder ?? 'Selecione...'}\n disabled={disabled}\n portalId=\"ddp-portal\"\n popperPlacement=\"bottom-start\"\n popperModifiers={[\n {\n name: 'flip',\n options: { fallbackPlacements: ['bottom-end', 'top-start', 'top-end'] },\n fn: (state) => state,\n },\n ]}\n />\n </div>\n );\n}\n","// Purpose: Seletor categorico com busca por digitacao (selecao unica e multipla).\r\n// Scope: Reaproveitado pelo FilterWidget (runtime) e pelo builder (valor padrao do filtro).\r\n// O proprio campo e a barra de busca (combobox): digitar filtra; a lista abre\r\n// abaixo em portal no document.body (escapa de overflow:hidden e nao rola o widget).\r\n// Formato de valor: unica = string da opcao ('' = Todos); multipla = csv das opcoes.\r\n// Public API: SearchableSelect\r\n\r\nimport { useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react';\r\nimport { createPortal } from 'react-dom';\r\nimport { MULTI_VALUE_SEPARATOR } from '../types';\r\n\r\ninterface Props {\r\n options: string[];\r\n value: string;\r\n multi: boolean;\r\n onChange: (value: string) => void;\r\n}\r\n\r\n// Posicao da lista em coordenadas de viewport (position: fixed)\r\ninterface PanelPos {\r\n left: number;\r\n width: number;\r\n top?: number;\r\n bottom?: number;\r\n maxHeight: number;\r\n}\r\n\r\nexport function SearchableSelect({ options, value, multi, onChange }: Props) {\r\n const [open, setOpen] = useState(false);\r\n const [query, setQuery] = useState('');\r\n const [pos, setPos] = useState<PanelPos | null>(null);\r\n const inputRef = useRef<HTMLInputElement>(null);\r\n const panelRef = useRef<HTMLDivElement>(null);\r\n\r\n const selected = useMemo(\r\n () => (value ? value.split(MULTI_VALUE_SEPARATOR).filter(Boolean) : []),\r\n [value],\r\n );\r\n\r\n const filtered = useMemo(() => {\r\n const q = query.trim().toLowerCase();\r\n if (!q) return options;\r\n return options.filter((opt) => opt.toLowerCase().includes(q));\r\n }, [options, query]);\r\n\r\n // Recalcula a posicao da lista a partir do retangulo do campo.\r\n // Abre para cima quando nao ha espaco suficiente abaixo.\r\n const reposition = () => {\r\n const el = inputRef.current;\r\n if (!el) return;\r\n const r = el.getBoundingClientRect();\r\n const gap = 4;\r\n const spaceBelow = window.innerHeight - r.bottom - gap;\r\n const spaceAbove = r.top - gap;\r\n const openUp = spaceBelow < 200 && spaceAbove > spaceBelow;\r\n const maxHeight = Math.max(150, Math.min(360, openUp ? spaceAbove : spaceBelow));\r\n setPos({\r\n left: r.left,\r\n width: r.width,\r\n maxHeight,\r\n ...(openUp\r\n ? { bottom: window.innerHeight - r.top + gap }\r\n : { top: r.bottom + gap }),\r\n });\r\n };\r\n\r\n useLayoutEffect(() => {\r\n if (!open) return;\r\n reposition();\r\n const handler = () => reposition();\r\n window.addEventListener('scroll', handler, true);\r\n window.addEventListener('resize', handler);\r\n return () => {\r\n window.removeEventListener('scroll', handler, true);\r\n window.removeEventListener('resize', handler);\r\n };\r\n // eslint-disable-next-line react-hooks/exhaustive-deps\r\n }, [open]);\r\n\r\n // Fecha ao clicar fora — checa o campo e a lista (que vive no portal)\r\n useEffect(() => {\r\n if (!open) return;\r\n const onPointerDown = (e: MouseEvent) => {\r\n const target = e.target as Node;\r\n if (inputRef.current?.contains(target) || panelRef.current?.contains(target)) return;\r\n setOpen(false);\r\n };\r\n document.addEventListener('mousedown', onPointerDown);\r\n return () => document.removeEventListener('mousedown', onPointerDown);\r\n }, [open]);\r\n\r\n const closePanel = () => {\r\n setOpen(false);\r\n setQuery('');\r\n };\r\n\r\n const commitSingle = (opt: string) => {\r\n onChange(opt);\r\n setQuery('');\r\n setOpen(false);\r\n inputRef.current?.blur();\r\n };\r\n\r\n const toggleMulti = (opt: string) => {\r\n const next = selected.includes(opt)\r\n ? selected.filter((s) => s !== opt)\r\n : [...selected, opt];\r\n onChange(next.join(MULTI_VALUE_SEPARATOR));\r\n };\r\n\r\n const handleFocus = () => {\r\n setOpen(true);\r\n // Selecao unica: limpa para digitar; o valor atual volta a aparecer ao fechar\r\n if (!multi) setQuery('');\r\n };\r\n\r\n const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {\r\n if (e.key === 'Escape') {\r\n closePanel();\r\n inputRef.current?.blur();\r\n } else if (e.key === 'Enter' && filtered.length > 0) {\r\n e.preventDefault();\r\n if (multi) {\r\n toggleMulti(filtered[0]);\r\n setQuery('');\r\n } else {\r\n commitSingle(filtered[0]);\r\n }\r\n }\r\n };\r\n\r\n // Texto do campo: multi sempre mostra a busca; unica mostra o valor quando fechado.\r\n const inputValue = multi ? query : (open ? query : (value || ''));\r\n // Multi vazio = todos (sem filtro). Fechado mostra o estado; aberto convida a buscar.\r\n const placeholder = multi\r\n ? (selected.length > 0 ? `${selected.length} selecionado(s)` : (open ? 'Buscar...' : 'Todos'))\r\n : (open ? 'Buscar...' : 'Todos');\r\n\r\n const panel = open && pos ? createPortal(\r\n <div\r\n ref={panelRef}\r\n className=\"widget-filter__search-panel\"\r\n style={{\r\n position: 'fixed',\r\n left: pos.left,\r\n width: pos.width,\r\n top: pos.top,\r\n bottom: pos.bottom,\r\n maxHeight: pos.maxHeight,\r\n }}\r\n >\r\n <div className=\"widget-filter__search-list\">\r\n {/* Selecao multipla: limpar toda a selecao (vazio = todos) */}\r\n {multi && selected.length > 0 && (\r\n <button\r\n type=\"button\"\r\n className=\"widget-filter__search-clear\"\r\n onClick={() => onChange('')}\r\n >\r\n Limpar seleção\r\n </button>\r\n )}\r\n\r\n {/* Selecao unica: opcao explicita para limpar o filtro */}\r\n {!multi && (\r\n <button\r\n type=\"button\"\r\n className={`widget-filter__search-option${value ? '' : ' is-selected'}`}\r\n onClick={() => commitSingle('')}\r\n >\r\n <span className=\"widget-filter__search-check\" aria-hidden>{value ? '' : '✓'}</span>\r\n Todos\r\n </button>\r\n )}\r\n\r\n {filtered.length === 0 ? (\r\n <span className=\"widget-filter__search-empty\">Nenhuma opção</span>\r\n ) : (\r\n filtered.map((opt) =>\r\n multi ? (\r\n <label\r\n key={opt}\r\n className={`widget-filter__search-option${selected.includes(opt) ? ' is-selected' : ''}`}\r\n >\r\n <input\r\n type=\"checkbox\"\r\n checked={selected.includes(opt)}\r\n onChange={() => toggleMulti(opt)}\r\n />\r\n {opt}\r\n </label>\r\n ) : (\r\n <button\r\n key={opt}\r\n type=\"button\"\r\n className={`widget-filter__search-option${value === opt ? ' is-selected' : ''}`}\r\n onClick={() => commitSingle(opt)}\r\n >\r\n <span className=\"widget-filter__search-check\" aria-hidden>{value === opt ? '✓' : ''}</span>\r\n {opt}\r\n </button>\r\n ),\r\n )\r\n )}\r\n </div>\r\n </div>,\r\n document.body,\r\n ) : null;\r\n\r\n return (\r\n <div className=\"widget-filter__search\">\r\n <input\r\n ref={inputRef}\r\n type=\"text\"\r\n className=\"widget-filter__search-field\"\r\n value={inputValue}\r\n placeholder={placeholder}\r\n onFocus={handleFocus}\r\n onClick={() => setOpen(true)}\r\n onChange={(e) => { setQuery(e.target.value); setOpen(true); }}\r\n onKeyDown={handleKeyDown}\r\n />\r\n {panel}\r\n </div>\r\n );\r\n}\r\n","// Purpose: Seletor de paleta de cores (13 slots semanticos).\n// Scope: Presets pre-definidos + modo customizado com color pickers nomeados por slot.\n// Public API: ColorPaletteSelector\n\nimport {\n PALETTES, ensurePaletteShape, getSeries, SLOT_INDEX, SLOT_LABELS, TOTAL_SLOTS,\n type PaletteKey,\n} from '../palettes';\n\n// Slots de tema usados para a segunda barra de preview do preset\nconst THEME_PREVIEW_SLOTS = [\n SLOT_INDEX.bgDark,\n SLOT_INDEX.bgPaper,\n SLOT_INDEX.bgElevated,\n SLOT_INDEX.accent,\n SLOT_INDEX.success,\n];\n\ninterface Props {\n selected?: string[];\n onSelect: (colors: string[]) => void;\n customMode?: boolean;\n onCustomModeChange?: (custom: boolean) => void;\n disabled?: boolean;\n}\n\nfunction isPreset(colors?: string[]): boolean {\n if (!colors) return true;\n const normalized = ensurePaletteShape(colors);\n return Object.values(PALETTES).some(\n (p) => JSON.stringify(p.colors) === JSON.stringify(normalized)\n );\n}\n\n// Slots agrupados por categoria para a UI customizada\nconst SLOT_ROWS: { label: string; slots: (keyof typeof SLOT_INDEX)[] }[] = [\n { label: 'Series', slots: ['series0', 'series1', 'series2', 'series3', 'series4'] },\n { label: 'Tema', slots: ['bgDark', 'bgPaper', 'bgElevated', 'textPrimary', 'textMuted'] },\n { label: 'Estados', slots: ['accent', 'success', 'error'] },\n];\n\nexport function ColorPaletteSelector({\n selected, onSelect, customMode, onCustomModeChange, disabled,\n}: Props) {\n const isCustom = customMode ?? !isPreset(selected);\n const colors = ensurePaletteShape(selected);\n\n const selectedKey = !isCustom\n ? (Object.entries(PALETTES).find(\n ([, p]) => JSON.stringify(p.colors) === JSON.stringify(colors)\n )?.[0] as PaletteKey | undefined)\n : undefined;\n\n const handleSlotChange = (slotIdx: number, color: string) => {\n const updated = [...colors];\n while (updated.length < TOTAL_SLOTS) updated.push('#000000');\n updated[slotIdx] = color;\n onSelect(updated);\n };\n\n return (\n <div className={`palette-selector ${disabled ? 'palette-selector--disabled' : ''}`}>\n {onCustomModeChange && (\n <label className=\"config-panel__checkbox\">\n <input\n type=\"checkbox\"\n checked={isCustom}\n onChange={(e) => onCustomModeChange(e.target.checked)}\n disabled={disabled}\n />\n Customizar\n </label>\n )}\n\n {isCustom ? (\n <div className=\"palette-selector__custom\">\n {SLOT_ROWS.map((row) => (\n <div key={row.label} className=\"palette-selector__row\">\n <span className=\"palette-selector__row-label\">{row.label}</span>\n <div className=\"palette-selector__row-slots\">\n {row.slots.map((slotName) => {\n const slotIdx = SLOT_INDEX[slotName];\n return (\n <input\n key={slotName}\n type=\"color\"\n className=\"palette-selector__color-input\"\n value={colors[slotIdx] || '#000000'}\n onChange={(e) => handleSlotChange(slotIdx, e.target.value)}\n disabled={disabled}\n title={SLOT_LABELS[slotName]}\n />\n );\n })}\n </div>\n </div>\n ))}\n </div>\n ) : (\n <div className=\"palette-selector__options\">\n {(Object.entries(PALETTES) as [PaletteKey, typeof PALETTES[PaletteKey]][]).map(([key, palette]) => {\n const fullColors = ensurePaletteShape(palette.colors);\n return (\n <button\n key={key}\n className={`palette-selector__option ${selectedKey === key ? 'palette-selector__option--active' : ''}`}\n onClick={() => onSelect(palette.colors)}\n disabled={disabled}\n >\n <div className=\"palette-selector__bar\">\n {getSeries(palette.colors).map((color, i) => (\n <span\n key={i}\n className=\"palette-selector__swatch\"\n style={{ backgroundColor: color }}\n />\n ))}\n </div>\n <div className=\"palette-selector__bar palette-selector__bar--theme\">\n {THEME_PREVIEW_SLOTS.map((slotIdx, i) => (\n <span\n key={i}\n className=\"palette-selector__swatch\"\n style={{ backgroundColor: fullColors[slotIdx] }}\n />\n ))}\n </div>\n <span className=\"palette-selector__label\">{palette.label}</span>\n </button>\n );\n })}\n </div>\n )}\n </div>\n );\n}\n"],"names":["DEFAULT_API_URL","ENDPOINT_PREFIX","apiUrl","setApiUrl","url","ApiError","message","status","payload","get","path","token","params","k","v","res","fetchLayout","fetchRender","SLOT_INDEX","SERIES_COUNT","TOTAL_SLOTS","SLOT_LABELS","PALETTES","DEFAULT_PALETTE_COLORS","ensurePaletteShape","colors","fallback","result","i","getSeries","getPaletteCssVars","c","DEFAULT_PALETTE","DEFAULT_GRID_COLUMNS","DEFAULT_GRID_ROWS","EMPTY_LAYOUT","WIDGET_TYPE_LABELS","DATA_WIDGET_TYPES","CONTROL_WIDGET_TYPES","CONTROL_WIDGET_SET","AGGREGATION_LABELS","FORMAT_LABELS","NUMERIC_FORMAT_OPTIONS","COMPARISON_LABELS","CHART_TYPE_LABELS","FILTER_TYPE_LABELS","MULTI_VALUE_SEPARATOR","DEFAULT_GRID","DEFAULT_CONFIG","GRID_GAP_PX","GRID_PADDING_PX","CELL_ASPECT","MIN_CELL_HEIGHT_PX","MAX_CELL_HEIGHT_PX","clamp","value","min","max","isUsable","computeCellWidth","outerWidth","columns","gap","padding","available","computeCellHeight","cellWidth","aspect","computeGridHeight","rows","cellHeight","computeWidgetAspect","w","h","computeStackThreshold","MONTH_NAMES_SHORT","MONTH_NAMES_FULL","getFullYearRange","year","parseYearFromRange","start","m","getMonthRange","month","lastDay","pad","getISOWeek","dt","d","yearStart","getWeekRange","week","jan4","dayOfWeek","firstMonday","end","n","fmt","getWeeksInMonth","weeks","daysInMonth","a","b","getMonthWeeks","day","index","startDay","endDay","label","parseMonthWeekFromRange","dayMatch","parseMonthFromRange","parseWeekFromRange","getYearRange","dateBounds","now","minYear","maxYear","years","y","isoToDate","iso","dateToIso","date","DashboardDatePicker","onChange","minIso","maxIso","placeholder","selectsStart","selectsEnd","startIso","endIso","className","disabled","jsx","DatePicker","state","SearchableSelect","options","multi","open","setOpen","useState","query","setQuery","pos","setPos","inputRef","useRef","panelRef","selected","useMemo","filtered","q","opt","reposition","el","r","spaceBelow","spaceAbove","openUp","maxHeight","useLayoutEffect","handler","useEffect","onPointerDown","e","target","_a","_b","closePanel","commitSingle","toggleMulti","next","s","handleFocus","handleKeyDown","inputValue","panel","createPortal","jsxs","THEME_PREVIEW_SLOTS","isPreset","normalized","p","SLOT_ROWS","ColorPaletteSelector","onSelect","customMode","onCustomModeChange","isCustom","selectedKey","handleSlotChange","slotIdx","color","updated","row","slotName","key","palette","fullColors"],"mappings":"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"}
@@ -1,12 +1,31 @@
1
- interface DashboardProps {
1
+ import type { DashboardGeometry } from './utils/grid';
2
+ export interface DashboardProps {
2
3
  /** Token Bearer de acesso ao dashboard. */
3
4
  token: string;
4
- /** Altura de cada linha do grid em rem. Default 2.5 (40px no base 16). */
5
- rowHeight?: number;
6
- /** Gap entre widgets em rem. Default 0.375 (6px no base 16). */
7
- gridGap?: number;
5
+ /**
6
+ * Proporcao largura/altura da celula do grid. Default 1 (celula quadrada).
7
+ *
8
+ * A largura da celula vem da largura do container dividida pelo numero de
9
+ * colunas do layout; a altura e derivada desta proporcao. E o que mantem o
10
+ * dashboard com a mesma forma em qualquer aplicacao que o embuta.
11
+ */
12
+ cellAspect?: number;
13
+ /**
14
+ * Largura de container, em px, abaixo da qual os widgets sao empilhados em
15
+ * coluna unica, cada um preservando a propria proporcao. `'auto'` usa o
16
+ * limiar natural do layout — o ponto em que a celula ficaria estreita demais
17
+ * e a proporcao ja nao seria respeitada. Ausente: nunca empilha.
18
+ */
19
+ stackBelow?: number | 'auto';
20
+ /**
21
+ * Notificado a cada mudanca de geometria. A altura do dashboard varia com a
22
+ * largura, entao um host de altura fixa deve usar `gridHeight` para se
23
+ * dimensionar.
24
+ */
25
+ onGeometryChange?: (geometry: DashboardGeometry) => void;
26
+ /** Desliga o aviso de corte emitido no console. */
27
+ silenceWarnings?: boolean;
8
28
  /** Classe CSS adicional no container raiz. */
9
29
  className?: string;
10
30
  }
11
- export declare function Dashboard({ token, rowHeight, gridGap, className, }: DashboardProps): import("react/jsx-runtime").JSX.Element;
12
- export {};
31
+ export declare function Dashboard({ token, cellAspect, stackBelow, onGeometryChange, silenceWarnings, className, }: DashboardProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,22 @@
1
+ import type { DashboardGeometry } from '../utils/grid';
2
+ export interface UseGridGeometryOptions {
3
+ /** Numero de colunas do layout. 0 enquanto o layout nao carregou. */
4
+ columns: number;
5
+ /** Proporcao largura/altura da celula. */
6
+ cellAspect: number;
7
+ /** Largura de container abaixo da qual empilhar. `auto` deriva do limiar natural. */
8
+ stackBelow?: number | 'auto';
9
+ /** Notificado quando qualquer medida do grid muda. */
10
+ onGeometryChange?: (geometry: DashboardGeometry) => void;
11
+ /** Desliga o aviso de corte no console. */
12
+ silenceWarnings?: boolean;
13
+ }
14
+ export interface UseGridGeometryResult {
15
+ /** Ref da raiz — elemento medido e portador das custom properties. */
16
+ rootRef: (element: HTMLDivElement | null) => void;
17
+ /** Ref do grid — medido apenas para reportar a altura ocupada. */
18
+ gridRef: (element: HTMLDivElement | null) => void;
19
+ /** True quando o container e estreito demais para a grade de colunas. */
20
+ stacked: boolean;
21
+ }
22
+ export declare function useGridGeometry(options: UseGridGeometryOptions): UseGridGeometryResult;
package/dist/index.d.ts CHANGED
@@ -1,3 +1,5 @@
1
1
  import './styles/index.css';
2
2
  export { Dashboard } from './Dashboard';
3
+ export type { DashboardProps } from './Dashboard';
4
+ export type { DashboardGeometry } from './utils/grid';
3
5
  export { ApiError } from './api/fetcher';