/** * Shared types + design-system constants for the Table Properties drawer * and related data-table primitives (filter chips, sort cards, * conditional formatting rules). * * Product-specific seed data (`FILTER_FIELDS` and `COLUMNS` arrays * tailored to the Placements hub) intentionally stays in * `apps/web/components/table-properties/types.ts` — those values are * **product data**, not design-system primitives, and the package must * not know about Placement specializations, supervisor labels, etc. * * Consumers compose their own `FilterFieldDef[]` / `ColDef[]` arrays * tailored to their entity (Team members, Compliance items, Question * bank rows, …) and pass them into the drawer through props. */ /** Comparison operator vocabulary used by every filter row + conditional rule. */ export type FilterOperator = "is" | "is_not" | "contains" | "not_contains" /** * Input mask for `type: "text"` filters. Maps to a * [Shadcn Studio input-mask](https://shadcnstudio.com/docs/components/input-mask) * pattern key. Add new keys here (and in your concrete `exxatMaskPatterns` * map) when a new column needs a structured text format. */ export type FilterTextMask = "phone" | "zip" | "dateMDY" /** Persistent format helper for masked text filters (SC 3.3.2). */ export const FILTER_TEXT_MASK_FORMAT_HINT: Record = { phone: "+1 (555) 555-0100", zip: "12345 or 12345-6789", dateMDY: "MM/DD/YYYY", } export interface FilterFieldDef { key: string label: string icon: string type: "select" | "text" | "date" | "date-range" | "range" operators: FilterOperator[] selectVariant?: "default" | "person" dataBounds?: boolean /** Select options, or for `date` fields used by conditional rules (exact row strings). */ options?: { value: string; label: string }[] /** When `type` is `text`, optional `use-mask-input` pattern for the value field. */ textMask?: FilterTextMask rangeMin?: number rangeMax?: number rangeStep?: number rangeUnit?: string } export interface ActiveFilter { id: string fieldKey: string operator: FilterOperator values: string[] } export interface SortRule { id: string fieldKey: string direction: "asc" | "desc" } /** Operator → human-readable label map (centralized so chips, drawer, and CSV exports stay aligned). */ export const OPERATOR_LABELS: Record = { is: "is", is_not: "is not", contains: "contains", not_contains: "does not contain", } /** Column descriptor for `TableProperties` views (Columns / Sort / Group panels). */ export interface ColDef { key: string label: string sortable: boolean sortKey?: string minWidth: number } /* ─── Conditional formatting ──────────────────────────────────────────── */ /** * Where a rule's background came from. `bgColor` stays the single resolved CSS * value every consumer paints, so this only records the picker the user chose, * which is what the editor needs to reopen on the right tab. * * - `palette` — the six `RULE_COLORS` tints (default) * - `status` — the status badge fills, so a highlight reads as the same colour * the status chip already uses (theme + high-contrast aware) * - `custom` — a colour the user picked, stored as a tint of the same strength * as the palette so label text keeps its contrast in both themes */ export type ConditionalRuleColorSource = "palette" | "status" | "custom" export interface ConditionalRule { id: string /** Column key to evaluate */ fieldKey: string operator: FilterOperator /** Selected option values (select) or text (single entry) when operator needs values */ values: string[] /** Resolved CSS background color string */ bgColor: string /** Which picker produced `bgColor`. Absent on rules saved before colour sources. */ colorSource?: ConditionalRuleColorSource /** The raw colour behind a `custom` tint, so the picker reopens on it. */ customColor?: string } /** * Predefined palette for conditional rule backgrounds. * * Backgrounds are exposed as CSS custom properties so theming swaps the * palette per brand without code edits (`--conditional-rule-green`, * `--conditional-rule-yellow`, etc., declared in * `packages/ui/src/globals.css`). */ export const RULE_COLORS: { name: string; bg: string }[] = [ { name: "Green", bg: "var(--conditional-rule-green)" }, { name: "Yellow", bg: "var(--conditional-rule-yellow)" }, { name: "Blue", bg: "var(--conditional-rule-blue)" }, { name: "Red", bg: "var(--conditional-rule-red)" }, { name: "Purple", bg: "var(--conditional-rule-purple)" }, { name: "Orange", bg: "var(--conditional-rule-orange)" }, ]