# DataGrid Formatting - User Guide ## Introduction The DataGrid Formatting system provides a powerful way to apply conditional styling and value formatting to your data grids. It allows you to create rich, readable data presentations with minimal code. **Key features:** - Apply styles (colors, fonts, decorations) based on cell values - Format values for display (currencies, dates, percentages, text transformations) - Create conditional rules that respond to data - Reference other cells for cross-column/row comparisons - Define formatting at multiple levels (cell, row, column, table, or globally) **Common use cases:** - Highlight negative values in financial reports - Format currency and percentage values - Color-code status indicators - Display custom labels for enumerated values - Apply different styles based on data thresholds - Create visual hierarchies with conditional formatting ## Quick Start Here's a simple example to highlight negative values in red: ```python column amount: style("error") if value < 0 format("EUR") ``` This creates a formatting rule that: - Applies to all cells in the "amount" column - Colors negative values with the "error" style (red background) - Formats all values as Euro currency ## Understanding Formatting ### Formatting Levels Formatting can be applied at five different levels, each with its own specificity: | Level | Cells Targeted | Condition Evaluated On | Specificity | |------------|-----------------------------------|------------------------|-------------| | **Cell** | 1 specific cell | The cell value | Highest (1) | | **Row** | All cells in the row | Each cell value | High (2) | | **Column** | All cells in the column | Each cell value | Medium (3) | | **Table** | All cells in a specific table | Each cell value | Low (4) | | **Tables** | All cells in all tables (global) | Each cell value | Lowest (5) | **Visual hierarchy:** ``` Cell (amount, 5) ← Highest priority ↓ Row 5 ← Overridden by cell ↓ Column amount ← Overridden by row and cell ↓ Table "products" ← Overridden by column, row, and cell ↓ Tables (global) ← Lowest priority, applies everywhere ``` ### How Rules Are Evaluated Rules are processed from **highest to lowest specificity**. When multiple rules match: 1. **Cell-level rules** win over all others 2. **Row-level rules** win over column, table, and global rules 3. **Column-level rules** win over table and global rules 4. **Table-level rules** win over global rules 5. **Global rules** apply only if no other rules match ### Conflict Resolution When multiple rules at the **same level** match a cell, style and formatter are resolved **independently**: **Style rules compete among themselves:** 1. **Specificity** = number of conditions in the rule (0 or 1) 2. **Higher specificity wins** 3. **At equal specificity, last rule wins** **Formatter rules compete among themselves:** 1. Same specificity logic as styles 2. Resolved independently from styles **Style and formatter can fuse:** - If one rule provides the style and another provides the formatter, **both are applied** - This allows separating concerns (e.g., unconditional formatting + conditional styling) **Example 1: Style competition** ```python column amount: style(color="gray") # Specificity: 0 (no condition) style("error") if value < 0 # Specificity: 1 style("success", bold=True) if value > 0 # Specificity: 1 ``` - For `value = -10`: "error" style wins (specificity 1 > 0) - For `value = 50`: "success" style wins (specificity 1 > 0) - For `value = 0`: gray color applies (no other rules match) **Example 2: Style and formatter fusion** ```python column amount: format("EUR") # Unconditional formatter style("error") if value < 0 # Conditional style ``` - For `value = -100`: - ✅ Style "error" applied (from conditional rule) - ✅ Format "EUR" applied (from unconditional rule) - Result: `-100,00 €` with red background - For `value = 100`: - ❌ No style (condition not met) - ✅ Format "EUR" applied - Result: `100,00 €` with default style **Example 3: Multiple styles and formatters** ```python column amount: style("neutral") # Unconditional style format("EUR") # Unconditional formatter style("error") if value < 0 # Conditional style (higher specificity) format.number(precision=0, suffix=" €") if value < 0 # Conditional formatter (higher specificity) ``` - For `value = -5.67`: - Style: "error" wins (specificity 1 > 0) - Formatter: precision=0 wins (specificity 1 > 0) - Result: `-6 €` with red background - For `value = 1234.56`: - Style: "neutral" applies (no conditional matches) - Formatter: "EUR" applies (no conditional matches) - Result: `1 234,56 €` with neutral background ### How Rules Work A formatting rule consists of three optional parts: ``` [style(...)] [format(...)] [if ] ``` **Rules:** - At least one of `style()` or `format()` must be present - `condition` is optional - If a condition is present, the rule applies only when the condition is met - Multiple rules can be defined for the same scope **Examples:** ```python # Style only style("error") # Format only format("EUR") # Style + Format style("error") format("EUR") # With condition style("error") if value < 0 # All combined style("error") format("EUR") if value < 0 ``` ## Writing Formatting Rules ### Basic Syntax A DSL document consists of **scopes**, each containing one or more **rules**: ```python : ... : ... ``` **Scopes define which cells a rule applies to:** | Scope Syntax | Applies To | Example | |--------------|------------|---------| | `column :` | All cells in the column | `column amount:` | | `column "":` | Column with spaces | `column "total amount":` | | `row :` | All cells in the row | `row 0:` | | `cell (, ):` | Single cell by coordinates | `cell (amount, 3):` | | `cell :` | Single cell by ID | `cell tcell_grid1-3-2:` | | `table "":` | All cells in a specific table | `table "products":` | | `tables:` | All cells in all tables | `tables:` | **Indentation and comments:** ```python # This is a comment column amount: # Rules must be indented under their scope style("error") if value < 0 format("EUR") # Column names with spaces need quotes column "total amount": style("neutral", bold=True) ``` ### Styling Cells The `style()` function applies visual formatting to cells. **Syntax:** ```python style() style(, ) style() ``` **Available style presets (DaisyUI 5):** | Preset | Background | Text | Use Case | |--------|------------|------|----------| | `primary` | Primary theme color | Primary content | Main highlights | | `secondary` | Secondary theme color | Secondary content | Secondary highlights | | `accent` | Accent theme color | Accent content | Accent highlights | | `neutral` | Neutral theme color | Neutral content | Headers, totals | | `info` | Info (blue) | Info content | Information | | `success` | Success (green) | Success content | Positive values | | `warning` | Warning (yellow) | Warning content | Warnings | | `error` | Error (red) | Error content | Negative values, errors | **Style properties:** | Property | Type | Description | Example | |----------|------|-------------|---------| | `background_color` | string | Background color | `"#ffeeee"`, `"red"`, `"var(--color-primary)"` | | `color` | string | Text color | `"#cc0000"`, `"white"` | | `bold` | boolean | Bold text | `True`, `False` | | `italic` | boolean | Italic text | `True`, `False` | | `underline` | boolean | Underlined text | `True`, `False` | | `strikethrough` | boolean | Strikethrough text | `True`, `False` | | `font_size` | string | Font size | `"12px"`, `"0.9em"` | **Examples:** ```python # Preset only column status: style("error") # Preset with overrides column total: style("neutral", bold=True) # Multiple properties column name: style("success", italic=True, underline=True) # No preset, direct properties column notes: style(color="red", bold=True) style(background_color="#ffeeee", color="#cc0000") ``` ### Formatting Values The `format()` function transforms cell values for display without changing the underlying data. **Using presets:** ```python # Preset only format("EUR") # Preset with overrides format("EUR", precision=3) ``` **Available formatter presets:** | Preset | Type | Description | Example Output | |--------|------|-------------|----------------| | `EUR` | number | Euro currency | 1 234,56 € | | `USD` | number | US Dollar | $1,234.56 | | `percentage` | number | Percentage (×100) | 45.2% | | `short_date` | date | DD/MM/YYYY | 29/01/2026 | | `iso_date` | date | YYYY-MM-DD | 2026-01-29 | | `yes_no` | boolean | Yes/No | Yes | **Using explicit types:** When not using a preset, specify the type explicitly: ```python format.number(precision=2, suffix=" €", thousands_sep=" ") format.date(format="%d/%m/%Y") format.boolean(true_value="Oui", false_value="Non") format.text(max_length=50, ellipsis="...") format.enum(source={"draft": "Draft", "published": "Published"}) format.constant(value="N/A") ``` #### Number Formatter Formats numbers, currencies, and percentages. **Parameters:** | Parameter | Type | Default | Description | |-----------|------|---------|-------------| | `prefix` | string | `""` | Text before value (e.g., "$") | | `suffix` | string | `""` | Text after value (e.g., " €", "%") | | `thousands_sep` | string | `""` | Thousands separator (e.g., ",", " ") | | `decimal_sep` | string | `"."` | Decimal separator (e.g., ".", ",") | | `precision` | int | `0` | Number of decimal places | | `multiplier` | number | `1` | Multiply value before display (e.g., 100 for %) | | `absolute` | boolean | `False` | Display absolute value (no sign) | **Examples:** ```python # Euro currency column amount: format.number(suffix=" €", thousands_sep=" ", decimal_sep=",", precision=2) # US Dollar column price: format.number(prefix="$", thousands_sep=",", precision=2) # Percentage column rate: format.number(suffix="%", multiplier=100, precision=1) # Large numbers with thousands separator column population: format.number(thousands_sep=",", precision=0) # Absolute value - display variance without sign column variance: format.number(absolute=True, suffix=" €", precision=2) ``` #### Date Formatter Formats dates and datetimes using strftime patterns. **Parameters:** | Parameter | Type | Default | Description | |-----------|------|---------|-------------| | `format` | string | `"%Y-%m-%d"` | strftime format pattern | **Common format patterns:** | Pattern | Description | Example | |---------|-------------|---------| | `"%Y-%m-%d"` | ISO format | 2026-01-29 | | `"%d/%m/%Y"` | European | 29/01/2026 | | `"%m/%d/%Y"` | US format | 01/29/2026 | | `"%d %b %Y"` | Short month | 29 Jan 2026 | | `"%d %B %Y"` | Full month | 29 January 2026 | | `"%Y-%m-%d %H:%M"` | With time | 2026-01-29 14:30 | **Examples:** ```python # European format column created_at: format.date(format="%d/%m/%Y") # Full date with month name column updated_at: format.date(format="%d %B %Y") # ISO format with time column timestamp: format.date(format="%Y-%m-%d %H:%M:%S") ``` #### Boolean Formatter Formats boolean and binary values. **Parameters:** | Parameter | Type | Default | Description | |-----------|------|---------|-------------| | `true_value` | string | `"true"` | Display for true/1 | | `false_value` | string | `"false"` | Display for false/0 | | `null_value` | string | `""` | Display for null/None | **Examples:** ```python # Yes/No column active: format.boolean(true_value="Yes", false_value="No") # Checked/Unchecked column completed: format.boolean(true_value="✓", false_value="✗") # Custom labels column status: format.boolean(true_value="Enabled", false_value="Disabled", null_value="Unknown") ``` #### Text Formatter Formats and transforms text values. **Parameters:** | Parameter | Type | Default | Description | |-----------|------|---------|-------------| | `transform` | string | - | `"uppercase"`, `"lowercase"`, `"capitalize"` | | `max_length` | int | - | Truncate if exceeded | | `ellipsis` | string | `"..."` | Suffix when truncated | **Examples:** ```python # Uppercase column code: format.text(transform="uppercase") # Truncate long text column description: format.text(max_length=50, ellipsis="...") # Capitalize first letter column name: format.text(transform="capitalize") ``` #### Enum Formatter Maps values to display labels. Useful for status codes, categories, and dropdown lists. **Parameters:** | Parameter | Type | Default | Description | |-----------|------|---------|-------------| | `source` | object | - | Mapping or datagrid reference | | `default` | string | `""` | Label for unknown values | **Source types:** **Static mapping:** ```python column status: format.enum( source={ "draft": "Draft", "pending": "Pending Review", "approved": "Approved", "rejected": "Rejected" }, default="Unknown" ) ``` **From another DataGrid:** ```python column category_id: format.enum( source={ "type": "datagrid", "value": "categories_grid", "value_column": "id", "display_column": "name" } ) ``` This looks up the `category_id` value in the "categories_grid", finds the matching row by "id", and displays the "name" column. #### Constant Formatter Displays a fixed value regardless of the cell's actual value. Useful for placeholder text or fixed labels. **Parameters:** | Parameter | Type | Default | Description | |-----------|------|---------|-------------| | `value` | string | - | The constant text to display | **Examples:** ```python # Display "N/A" for all cells column placeholder: format.constant(value="N/A") # Display fixed label column type: format.constant(value="Product") # Combined with condition column optional_field: format.constant(value="—") if value isempty ``` ### Conditional Formatting Conditions determine when a rule applies. They use the syntax: ```python if if ``` #### Comparison Operators | Operator | Description | Example | |----------|-------------|---------| | `==` | Equal | `value == 0` | | `!=` | Not equal | `value != ""` | | `<` | Less than | `value < 0` | | `<=` | Less or equal | `value <= 100` | | `>` | Greater than | `value > 1000` | | `>=` | Greater or equal | `value >= 0` | **Examples:** ```python column amount: style("error") if value < 0 style("success") if value > 1000 style("warning") if value == 0 ``` #### String Operators | Operator | Description | Example | |----------|-------------|---------| | `contains` | String contains | `value contains "error"` | | `startswith` | String starts with | `value startswith "ERR"` | | `endswith` | String ends with | `value endswith ".pdf"` | **Examples:** ```python column message: style("error") if value contains "error" style("info") if value startswith "INFO" column filename: style("accent") if value endswith ".pdf" ``` **Note:** String comparisons are **case-insensitive by default**. See "Case Sensitivity" below for case-sensitive matching. #### List Operators | Operator | Description | Example | |----------|-------------|---------| | `in` | Value in list | `value in ["A", "B", "C"]` | | `between` | Value in range | `value between 0 and 100` | **Examples:** ```python column status: style("success") if value in ["approved", "completed"] style("warning") if value in ["pending", "review"] column score: style("error") if value between 0 and 30 style("warning") if value between 31 and 70 style("success") if value between 71 and 100 ``` #### Empty and NaN Checks | Operator | Description | Example | |----------|-------------|---------| | `isempty` | Is null or empty string | `value isempty` | | `isnotempty` | Is not null or empty | `value isnotempty` | | `isnan` | Is NaN (Not a Number) | `value isnan` | **Examples:** ```python column notes: style("neutral") if value isempty format.constant(value="—") if value isempty column calculation: style("error") if value isnan format.constant(value="Error") if value isnan column required_field: style("warning") if value isempty ``` **Note:** `isempty` checks for `None` or empty string (`""`). `isnan` specifically checks for invalid float values (NaN). #### Cell References References allow comparing a cell's value with values from other cells. | Reference | Description | Example | |-----------|-------------|---------| | `value` | Current cell value | `value < 0` | | `col.` | Value from another column (same row) | `value > col.budget` | | `col.""` | Column with spaces | `value > col."max amount"` | | `row.` | Value from another row (same column) | `value != row.0` | | `cell.-` | Specific cell by coordinates | `value == cell.status-0` | **Examples:** ```python # Compare with another column column actual: style("error") if value > col.budget style("warning") if value > col.budget * 0.9 # Compare with header row column total: style("neutral", bold=True) if value == row.0 # Compare with specific cell column status: style("success") if value == cell.status-0 ``` **Arithmetic in references:** You can perform simple arithmetic with column references: ```python column spending: style("warning") if value > col.budget * 0.8 style("error") if value > col.budget * 1.1 ``` #### Negation Use `not` to negate any condition: ```python column status: style("error") if not value in ["valid", "approved"] style("warning") if not value contains "OK" column amount: style("success") if not value < 0 ``` #### Case Sensitivity String comparisons are **case-insensitive by default**. Use the `(case)` modifier for case-sensitive matching: ```python column code: style("error") if value == "Error" (case) style("warning") if value contains "WARN" (case) column status: # This matches "approved", "APPROVED", "Approved" style("success") if value == "approved" # This matches only "APPROVED" style("info") if value == "APPROVED" (case) ``` ### Complete Examples #### Example 1: Highlight Negative Values Simple financial data with negative values highlighted: ```python column amount: style("error") if value < 0 format("EUR") ``` **Result:** - Negative values: red background, formatted as Euro - Positive values: normal display, formatted as Euro #### Example 2: Status Indicators with Color Coding Map status codes to colors and labels: ```python column status: format.enum( source={ "draft": "Draft", "pending": "Pending Review", "approved": "Approved", "rejected": "Rejected" }, default="Unknown" ) style("neutral") if value == "draft" style("warning") if value == "pending" style("success") if value == "approved" style("error") if value == "rejected" ``` **Result:** - "draft" → "Draft" with neutral background - "pending" → "Pending Review" with yellow background - "approved" → "Approved" with green background - "rejected" → "Rejected" with red background #### Example 3: Budget vs Actual with Thresholds Compare actual spending against budget with warning thresholds: ```python column actual: format("EUR") style("success") if value <= col.budget * 0.8 style("warning") if value > col.budget * 0.8 style("error") if value > col.budget column budget: format("EUR") ``` **Result:** - Actual ≤ 80% of budget: green background - Actual > 80% but ≤ 100%: yellow background - Actual > 100%: red background #### Example 4: Financial Report with Multiple Rules Complete financial report with headers, formatting, and conditional highlighting: ```python # Global styling for all tables tables: style(font_size="14px") # Header row row 0: style("neutral", bold=True) # Amount column column amount: format.number(precision=2, suffix=" €", thousands_sep=" ") style("error") if value < 0 style("success") if value > col.target # Percentage column column progress: format("percentage") style("error") if value < 0.5 style("warning") if value between 0.5 and 0.8 style("success") if value > 0.8 # Status column column status: format.enum( source={ "draft": "Draft", "review": "In Review", "approved": "Approved", "rejected": "Rejected" } ) style("neutral") if value == "draft" style("info") if value == "review" style("success") if value == "approved" style("error") if value == "rejected" # Date column column created_at: format.date(format="%d %b %Y") # Highlight specific important cell cell (amount, 10): style("accent", bold=True) ``` **Result:** A fully formatted financial report with: - Bold headers with neutral background - Euro amounts with conditional coloring - Progress percentages with traffic light colors - Status labels with appropriate colors - Formatted dates - Highlighted total row ## Using the DSL Editor ### Editor Features The DSL editor provides a comfortable writing experience with: **Syntax highlighting:** - Keywords (column, row, if, not) are highlighted - Functions (style, format) are colored differently - Strings, numbers, and operators have distinct colors **Line numbers:** - Easy reference for error messages - Quick navigation in large documents **Auto-indentation:** - Automatic indentation after scope declarations - Tab key for manual indentation - Maintains Python-style indentation ### Autocompletion The editor provides context-aware suggestions to help you write rules quickly and correctly. **How to trigger:** - **Ctrl+Space** - Manual trigger at any time - **Automatic** - Triggers after typing `.`, `(`, `"`, or space in certain contexts **What can be autocompleted:** | Context | Suggestions | |---------|-------------| | Start of line | `column`, `row`, `cell`, `table`, `tables` | | After `column ` | Column names from your DataGrid | | After `row ` | Row indices (0, 1, 2, ...) | | After `table ` | Table name from current DataGrid | | Indented line | `style(`, `format(`, `format.` | | Inside `style("` | Style presets (primary, error, success, ...) | | After `style(` | Preset names and parameters (bold=, color=, ...) | | Inside `format("` | Format presets (EUR, USD, percentage, ...) | | After `format.` | Format types (number, date, boolean, text, enum, constant) | | After `if ` | `value`, `col.`, `row.`, `not` | | After operand | Operators (==, <, >, contains, in, ...) | | After `col.` | Column names | | After operator | `col.`, literal values, `True`, `False` | **Example workflow:** ``` User types │ Suggestions ───────────────┼──────────────────────────────────── col │ column column │ [column names from grid] column amount: │ (new line, indent) st │ style style( │ "error", "warning", "success", ... style("e │ "error" style("error", │ bold=, italic=, color=, ... style("error", bold=│ True, False style("error") │ format(, format., if style("error") if │ value, col., not style("error") if value │ ==, !=, <, >, contains, in, ... style("error") if value < │ [number input] ``` ### Syntax Validation The editor provides real-time syntax checking as you type. **Error indicators:** ``` ┌─────────────────────────────────────────────────────┐ │ 1 column amount: │ │ 2 style("error" if value < 0 │ │ ▲▲▲▲▲▲▲▲▲▲▲▲▲ │ │ ╰─ Missing closing parenthesis │ │ 3 │ └─────────────────────────────────────────────────────┘ ``` **Visual feedback:** - **Red underline** - Syntax error at that position - **Gutter marker** - Error icon in the line number area - **Tooltip** - Hover over the error for details **Common errors and fixes:** | Error | Cause | Fix | |-------|-------|-----| | `Expected ':'` | Missing colon after scope | Add `:` after scope name | | `Expected indentation` | Rule not indented | Indent rule under scope | | `Unexpected token` | Typo or invalid syntax | Check spelling, operators | | `Missing closing quote` | Unclosed string | Add closing `"` or `'` | | `Missing closing parenthesis` | Unclosed function call | Add closing `)` | | `Unknown column` | Column doesn't exist | Check column name spelling | **Example - Before and after fixing:** **Before (error):** ```python column amount style("error") if value < 0 ``` Error: `Expected ':' after column name` **After (fixed):** ```python column amount: style("error") if value < 0 ``` ## Managing Presets ### Using Built-in Presets **Style presets (DaisyUI 5):** | Preset | Background | Text | Typical Use | |--------|------------|------|-------------| | `primary` | Primary theme color | Primary content | Main highlights, important data | | `secondary` | Secondary theme color | Secondary content | Secondary highlights | | `accent` | Accent theme color | Accent content | Accent highlights, special items | | `neutral` | Neutral theme color | Neutral content | Headers, totals, summaries | | `info` | Info (blue) | Info content | Information, notes | | `success` | Success (green) | Success content | Positive values, completed items | | `warning` | Warning (yellow) | Warning content | Warnings, thresholds exceeded | | `error` | Error (red) | Error content | Negative values, errors, failures | **Formatter presets:** | Preset | Type | Configuration | Example Output | |--------|------|---------------|----------------| | `EUR` | number | suffix: " €", thousands_sep: " ", decimal_sep: ",", precision: 2 | 1 234,56 € | | `USD` | number | prefix: "$", thousands_sep: ",", decimal_sep: ".", precision: 2 | $1,234.56 | | `percentage` | number | suffix: "%", precision: 1, multiplier: 100 | 45.2% | | `short_date` | date | format: "%d/%m/%Y" | 29/01/2026 | | `iso_date` | date | format: "%Y-%m-%d" | 2026-01-29 | | `yes_no` | boolean | true_value: "Yes", false_value: "No" | Yes | ### Creating Custom Presets You can add your own presets to use across all DataGrids. **Adding a custom style preset:** ```python from myfasthtml.controls.DataGridsManager import DataGridsManager # Get the global manager manager = DataGridsManager.get_instance() # Add custom style preset manager.add_style_preset("highlight", { "background_color": "yellow", "color": "black", "font_weight": "bold" }) # Use in DSL column important: style("highlight") ``` **Adding a custom formatter preset:** ```python # Swiss Franc currency manager.add_formatter_preset("CHF", { "type": "number", "prefix": "CHF ", "thousands_sep": "'", "decimal_sep": ".", "precision": 2 }) # Use in DSL column price: format("CHF") ``` **Adding multiple presets:** ```python # Custom style presets manager.add_style_preset("urgent", { "background_color": "#ff6b6b", "color": "white", "font_weight": "bold" }) manager.add_style_preset("completed", { "background_color": "#51cf66", "color": "white", "text_decoration": "line-through" }) # Custom formatter presets manager.add_formatter_preset("GBP", { "type": "number", "prefix": "£", "thousands_sep": ",", "precision": 2 }) manager.add_formatter_preset("compact_date", { "type": "date", "format": "%d/%m/%y" }) ``` **Removing presets:** ```python # Remove style preset manager.remove_style_preset("highlight") # Remove formatter preset manager.remove_formatter_preset("CHF") ``` ## Reference ### Style Properties Complete reference of all style properties: | Property | Type | Values | Description | |----------|------|--------|-------------| | `preset` | string | See Style Presets below | Preset name (applied first) | | `background_color` | string | Hex, CSS name, or variable | Background color | | `color` | string | Hex, CSS name, or variable | Text color | | `bold` | boolean | `True`, `False` | Bold text | | `italic` | boolean | `True`, `False` | Italic text | | `underline` | boolean | `True`, `False` | Underlined text | | `strikethrough` | boolean | `True`, `False` | Strikethrough text | | `font_size` | string | CSS size value | Font size (e.g., "12px", "0.9em") | **Color values:** ```python # Hex colors style(color="#cc0000") # CSS color names style(color="red") # DaisyUI CSS variables style(color="var(--color-primary)") style(background_color="var(--color-base-200)") ``` **Combining properties:** ```python # Preset + overrides style("error", bold=True, font_size="16px") # Multiple properties style(background_color="#fffacd", color="#856404", bold=True, italic=True) ``` ### Style Presets DaisyUI 5 color presets: | Preset | Background CSS Variable | Text CSS Variable | |--------|------------------------|-------------------| | `primary` | `var(--color-primary)` | `var(--color-primary-content)` | | `secondary` | `var(--color-secondary)` | `var(--color-secondary-content)` | | `accent` | `var(--color-accent)` | `var(--color-accent-content)` | | `neutral` | `var(--color-neutral)` | `var(--color-neutral-content)` | | `info` | `var(--color-info)` | `var(--color-info-content)` | | `success` | `var(--color-success)` | `var(--color-success-content)` | | `warning` | `var(--color-warning)` | `var(--color-warning-content)` | | `error` | `var(--color-error)` | `var(--color-error-content)` | **Note:** All presets use `font_weight: "normal"`, `font_style: "normal"`, `text_decoration: "none"` by default. ### Formatter Types Possible formatter types : - `number` - `date` - `boolean` - `text` - `enum` - `constant` #### Number Formatter | Parameter | Type | Default | Description | |-----------|------|---------|-------------| | `prefix` | string | `""` | Text before value | | `suffix` | string | `""` | Text after value | | `thousands_sep` | string | `""` | Thousands separator | | `decimal_sep` | string | `"."` | Decimal separator | | `precision` | int | `0` | Decimal places | | `multiplier` | number | `1` | Multiply before display | | `absolute` | boolean | `False` | Display absolute value (no sign) | #### Date Formatter | Parameter | Type | Default | Description | |-----------|------|---------|-------------| | `format` | string | `"%Y-%m-%d"` | strftime pattern | #### Boolean Formatter | Parameter | Type | Default | Description | |-----------|------|---------|-------------| | `true_value` | string | `"true"` | Display for true/1 | | `false_value` | string | `"false"` | Display for false/0 | | `null_value` | string | `""` | Display for null/None | #### Text Formatter | Parameter | Type | Default | Description | |-----------|------|---------|-------------| | `transform` | string | - | `"uppercase"`, `"lowercase"`, `"capitalize"` | | `max_length` | int | - | Truncate if exceeded | | `ellipsis` | string | `"..."` | Suffix when truncated | #### Enum Formatter | Parameter | Type | Default | Description | |-----------|------|---------|-------------| | `source` | object | - | Mapping or datagrid reference | | `default` | string | `""` | Label for unknown values | #### Constant Formatter | Parameter | Type | Default | Description | |-----------|------|---------|-------------| | `value` | string | - | The constant text to display | ### Formatter Presets | Preset | Type | Configuration | |--------|------|---------------| | `EUR` | number | `suffix: " €", thousands_sep: " ", decimal_sep: ",", precision: 2` | | `USD` | number | `prefix: "$", thousands_sep: ",", decimal_sep: ".", precision: 2` | | `percentage` | number | `suffix: "%", precision: 1, multiplier: 100` | | `short_date` | date | `format: "%d/%m/%Y"` | | `iso_date` | date | `format: "%Y-%m-%d"` | | `yes_no` | boolean | `true_value: "Yes", false_value: "No"` | ### Operators Reference #### Comparison Operators | Operator | Description | Value Type | Example | |----------|-------------|------------|---------| | `==` | Equal | Any | `value == 0` | | `!=` | Not equal | Any | `value != ""` | | `<` | Less than | Number, Date | `value < 0` | | `<=` | Less or equal | Number, Date | `value <= 100` | | `>` | Greater than | Number, Date | `value > 1000` | | `>=` | Greater or equal | Number, Date | `value >= 0` | #### String Operators | Operator | Description | Value Type | Example | |----------|-------------|------------|---------| | `contains` | String contains | String | `value contains "error"` | | `startswith` | String starts with | String | `value startswith "ERR"` | | `endswith` | String ends with | String | `value endswith ".pdf"` | **Note:** String operators are case-insensitive by default. Use `(case)` modifier for case-sensitive matching. #### List Operators | Operator | Description | Value Type | Example | |----------|-------------|------------|---------| | `in` | Value in list | List | `value in ["A", "B", "C"]` | | `between` | Value in range | List [min, max] | `value between 0 and 100` | #### Unary Operators | Operator | Description | Example | |----------|-------------|---------| | `isempty` | Is null or empty string | `value isempty` | | `isnotempty` | Is not null or empty | `value isnotempty` | | `isnan` | Is NaN (Not a Number) | `value isnan` | ### DSL Grammar (EBNF) Formal syntax reference for the DSL: ```ebnf // Top-level structure program : scope+ // Scopes scope : scope_header NEWLINE INDENT rule+ DEDENT scope_header : column_scope | row_scope | cell_scope | table_scope | tables_scope column_scope : "column" column_name ":" row_scope : "row" INTEGER ":" cell_scope : "cell" cell_ref ":" table_scope : "table" QUOTED_STRING ":" tables_scope : "tables" ":" column_name : NAME | QUOTED_STRING cell_ref : "(" column_name "," INTEGER ")" | CELL_ID // Rules rule : (style_expr format_expr? | format_expr style_expr?) condition? NEWLINE condition : "if" comparison // Comparisons comparison : "not"? (binary_comp | unary_comp) case_modifier? binary_comp : operand operator operand | operand "in" list | operand "between" operand "and" operand unary_comp : operand ("isempty" | "isnotempty" | "isnan") case_modifier : "(" "case" ")" // Operators operator : "==" | "!=" | "<" | "<=" | ">" | ">=" | "contains" | "startswith" | "endswith" // Operands operand : value_ref | column_ref | row_ref | cell_ref_expr | literal | arithmetic value_ref : "value" column_ref : "col." (NAME | QUOTED_STRING) row_ref : "row." INTEGER cell_ref_expr : "cell." NAME "-" INTEGER literal : STRING | NUMBER | BOOLEAN arithmetic : operand ("*" | "/" | "+" | "-") operand list : "[" (literal ("," literal)*)? "]" // Style expression style_expr : "style" "(" style_args ")" style_args : (QUOTED_STRING ("," style_kwargs)?) | style_kwargs style_kwargs : style_kwarg ("," style_kwarg)* style_kwarg : NAME "=" (QUOTED_STRING | BOOLEAN | NUMBER) // Format expression format_expr : format_preset | format_typed format_preset : "format" "(" QUOTED_STRING ("," format_kwargs)? ")" format_typed : "format" "." FORMAT_TYPE "(" format_kwargs? ")" format_kwargs : format_kwarg ("," format_kwarg)* format_kwarg : NAME "=" (QUOTED_STRING | BOOLEAN | NUMBER | dict) dict : "{" (dict_entry ("," dict_entry)*)? "}" dict_entry : QUOTED_STRING ":" QUOTED_STRING // Tokens FORMAT_TYPE : "number" | "date" | "boolean" | "text" | "enum" | "constant" NAME : /[a-zA-Z_][a-zA-Z0-9_]*/ QUOTED_STRING : /"[^"]*"/ | /'[^']*'/ INTEGER : /[0-9]+/ NUMBER : /[0-9]+(\.[0-9]+)?/ BOOLEAN : "True" | "False" | "true" | "false" CELL_ID : /tcell_[a-zA-Z0-9_-]+/ NEWLINE : /\n/ COMMENT : /#.*/ ``` --- **End of User Guide** For technical details about the implementation, see the developer documentation.