import * as React from 'react'; import { type Locale } from 'date-fns'; import type { ColumnDefinition } from './types'; import type { GetDynamicColumns } from './dynamic-columns-shim'; /** Host-supplied helpers consumed by avatar/image cell renderers. */ export interface DynamicColumnsHelpers { /** * Resolves a relative or absolute media path into a renderable URL. Hosts * typically prepend their CDN/storage base. If omitted, paths are passed * through verbatim. */ getImageUrl?: (path: string) => string; /** * API origin used to build avatar URLs when the row carries a bare filename * instead of an absolute URL or sibling `.avatar` field. Usually * `import.meta.env.VITE_API_URL.replace('/api', '')`. */ apiBaseUrl?: string; } /** * Resolves the active currency for a column: the column's explicit currency * style wins, then the org-level fallback (org config, like `timeZone`), then * 'USD' as a last resort. */ export declare const resolveCurrency: (col: ColumnDefinition, orgCurrency?: string) => string; /** * Reads the column's footer-aggregate opt-in. A column opts into the table * footer total via its manifest `display_config.aggregate` (mapped by the * kernel to `styleConfig.aggregate` at runtime). Returns the aggregate kind * (e.g. `'sum'`) or undefined when the column carries no footer total. */ export declare const aggregateOf: (col: ColumnDefinition) => string | undefined; /** * Formats a footer aggregate total with the SAME rules the body cells use: * currency columns render as the org currency (resolveCurrency), number * columns honour `styleConfig.decimals`, everything else falls back to a * locale-formatted number. Non-numeric/empty totals render as a dash so an * empty filtered set reads cleanly. */ export declare const formatAggregateTotal: (col: ColumnDefinition, value: unknown, currency?: string, locale?: string) => string; /** * State-machine gate for per-row actions. * * An action that declares a non-empty `requiresState` (camelCase) / `requires_state` * (snake_case, as served by some backends) is only surfaced for rows whose * lifecycle field (`status` or `state`) is contained in that array. This hides * e.g. "Recibir" (requiresState: ['confirmed','partial']) on a purchase order * still in `draft`. * * Null-safe & non-regressive: * - action without requiresState (or empty array) → always shown. * - row with neither `status` nor `state` → all actions shown. */ export declare const isActionAllowedForRowState: (action: any, row: any) => boolean; /** * Declarative `condition` gate for a per-row action: shows the action only when * the row's `field` satisfies the operator. Supports both the SDK dialect * (`eq` | `neq` | `in` | `not_in`) and the common host dialect * (`equals` | `notEquals` | `not_in`), plus the truthy/falsy family (same * operator set as the host's document print gate — services/document_gate.go * — kept in sync so a manifest author doesn't have to know which gate a given * contribution goes through). Nested paths (`user.verified`) are resolved via * `getNestedValue`. No condition → always shown. * * `default: return true` for a genuinely unknown operator is deliberate — an * addon shipped against a newer SDK than the host runs should degrade to * "always show" (worst case: an extra menu item), never to "always hide" * (worst case: a feature silently vanishes). That same permissiveness is why * `truthy`/`falsy` going unrecognized here was a real, silent bug rather * than a build error: confirmed live — a `condition: {field: "amount_due", * operator: "truthy"}` row action rendered on every row regardless of * amount_due, because the switch fell through to the default and nothing * ever signaled it wasn't actually gating anything. */ export declare const isActionConditionMet: (action: any, row: any) => boolean; /** * Whether a per-row action should appear for `row`: both the state-machine gate * (`requiresState`) AND the declarative `condition` must pass. Shared by the * table's action column and the kanban card menu so they hide/show identically. */ export declare const isRowActionVisible: (action: any, row: any) => boolean; /** * Resolves the relation sibling object a backend serves alongside an FK column. * For a column keyed `category_id` the data row also carries * `row.category = { value, label }` (the FK key with the trailing `_id` * stripped) — mirroring how `created_by` ships as a `{ name, avatar, email }` * sibling consumed by the `creator` renderer. Returns the relation key so the * cell can read `row[relationKeyFor(col)]`. */ export declare const relationKeyFor: (col: Pick) => string; /** Cell renderers (`cellStyle`/`type`) that resolve to the date renderer. */ export declare const DATE_CELL_TYPES: readonly ["date", "datetime", "timestamp", "timestamptz"]; /** * Pure formatter behind the date/datetime cell. Returns the display string and * an optional full-precision `title` (tooltip), or `null` when the value is * empty/invalid/the Go zero-time so the cell renders an em-dash. * - `date`: day only (`PPP`), no tooltip. * - `datetime`/`timestamp(tz)`: day + time (`Pp`) with a full-precision * tooltip (`PPpp`) — the 7Leguas pattern. * * When a `timeZone` (IANA, e.g. the org's `America/Mexico_City`) is provided, * instants are rendered in that zone via the native `Intl.DateTimeFormat` so * the displayed day/time never shifts with the viewer's browser timezone: * - instant (datetime/timestamp(tz)): `dateStyle:'medium' timeStyle:'short'` * in the org zone, with a `dateStyle:'long' timeStyle:'medium'` + * `timeZoneName:'short'` tooltip. * - `date` (pure calendar day): rendered pinned to UTC so it never rolls to * the previous/next day, no tooltip. * Without a `timeZone`, the exact date-fns behavior is preserved (back-compat). */ export declare function formatDateCell(value: unknown, renderAs: string | undefined, locale: Locale, timeZone?: string): { display: string; title?: string; } | null; /** * Reads the resolved relation/option label a backend serves for an FK or * option column, falling back to the raw value. Pure so the cell renderers and * tests share one resolution path: * - relation: prefer the sibling `{ value, label }` object's label. * - option: prefer the matched `options[].label` (value compared as string). * - else: the raw value coerced to string ('' when nullish). */ export declare const resolveRelationLabel: (col: ColumnDefinition, row: any) => string; /** * Reads the thumbnail URL a backend serves on a resolved FK sibling, when * present. The backend stamps `image` onto the `{ value, label }` relation * object when the referenced model carries an image column (brand logo, * product photo, customer avatar). Returns '' when there is no sibling image — * the chip then renders text-only, exactly as before. */ export declare const resolveRelationImage: (col: ColumnDefinition, row: any) => string; /** * Label when an actor cell has no resolved name. `creator` cells and the * auto-injected `created_by.*` avatar column (hosts ship it as `type: avatar` * with `tooltip: created_by.name`) mean "system-created" → "Sistema". Other * avatar/user/search empties stay "N/A" (unassigned person). */ export declare function resolveMissingActorLabel(renderAs: string | undefined, colKey: string | undefined, namePath: string | undefined, t?: (key: string, options?: { defaultValue?: string; }) => string): string; /** * Coerces a creator/user cell value into a display string. Backends often put * the whole `{name,avatar,email}` sibling at `created_by` (column key = * namePath), and `String(object)` leaked as `[object Object]` in the table. * Prefer `objectLabel`, then scalars; empty → undefined so the caller can fall * back to Sistema / N/A. */ export declare function resolveActorDisplayName(raw: unknown): string | undefined; /** * Resolves the image source for `avatar`/`search`/`creator`/`user` cells. * Priority: sibling `.avatar`/`.photo` next to a nested key (`user.name` → * `user.avatar`), then the cell's own value. Bare filenames (backends often * store just `"2.png"`) are prefixed with `apiBaseUrl` + the column's declared * basePath (`styleConfig.base_path` or `col.basePath`). * * Contract (applies to both branches, so hosts get one predictable rule): * 1. absolute `http(s)://` URL → untouched * 2. rooted `/path` → untouched; the host's `getImageUrl` prepends its origin * 3. bare filename → `apiBaseUrl + basePath + filename` * Previously the sibling branch returned bare filenames untouched (broken for * any backend that stores just `"2.png"` next to a nested key) and the value * branch injected basePath into already-rooted paths (junk URLs). */ export declare const resolveAvatarSrc: (col: ColumnDefinition, row: any, value: any, apiBaseUrl?: string) => string | undefined; /** * Reads a secondary identifier the backend stamps on a resolved FK sibling — a * product's SKU, a user's email — projected as `subtitle`/`description` (the * relational twin of `image` via the column's `label_description`). Rendered * muted under the label so a reference chip reads "Name / SKU". Domain-agnostic: * only the generic `subtitle`/`description` keys are read (never a hardcoded * `sku`/`code`), so the author picks the column declaratively. '' when absent. */ export declare const resolveRelationSubtitle: (col: ColumnDefinition, row: any) => string; /** * Builds the canonical column factory used by `` when the host * does not supply its own. Pass `{ getImageUrl, apiBaseUrl }` to wire avatar * URL resolution. */ /** * `image`-type cell body. A value that is a lucide icon name (PascalCase or * kebab slug, e.g. "Banknote" / "credit-card") — the convention the `icon` * form widget stores — renders the glyph instead of an that would 404 * into an empty grey box. Exported for tests. */ export declare const ImageCell: React.FC<{ value: unknown; getImageUrl: (path: string) => string; /** Optional caption under the image (display: image_stack). */ label?: string; stack?: boolean; }>; export declare function makeDefaultGetDynamicColumns(helpers?: DynamicColumnsHelpers): GetDynamicColumns; /** * Eager-built variant — equivalent to `makeDefaultGetDynamicColumns()`. Use * this when the host has no helpers to inject and a stable function reference * suffices. */ export declare const defaultGetDynamicColumns: GetDynamicColumns; //# sourceMappingURL=dynamic-columns.d.ts.map