Metadata-Version: 2.4
Name: st-selectable-grid
Version: 2.0.1
Summary: A Streamlit component for a selectable grid
Home-page: https://github.com/hoggatt/st-selectable-grid
Author: Luke Hoggatt
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: License :: OSI Approved :: GNU General Public License v2 (GPLv2)
Classifier: Operating System :: OS Independent
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: streamlit>=1.51
Provides-Extra: devel
Requires-Dist: build; extra == "devel"
Requires-Dist: twine; extra == "devel"
Requires-Dist: wheel; extra == "devel"
Requires-Dist: pytest==7.4.0; extra == "devel"
Requires-Dist: playwright==1.48.0; extra == "devel"
Requires-Dist: requests==2.31.0; extra == "devel"
Requires-Dist: pytest-playwright-snapshot==1.0; extra == "devel"
Requires-Dist: pytest-rerunfailures==12.0; extra == "devel"
Dynamic: author
Dynamic: classifier
Dynamic: description
Dynamic: description-content-type
Dynamic: home-page
Dynamic: license-file
Dynamic: provides-extra
Dynamic: requires-dist
Dynamic: requires-python
Dynamic: summary

# Streamlit Selectable Grid

A Streamlit component that displays a selectable grid of cells with support for headers, row indices, and custom styling options.

![simple ss](docs/simple_example.png)

Requires Python 3.10 or newer and Streamlit 1.51 or newer.

## Installation

```bash
pip install st-selectable-grid
```

## Usage

```python
import streamlit as st
from st_selectable_grid import st_selectable_grid

# Create a grid with header and index
cells = [
    [
        {"label": "A1", "cell_color": "#f0f8ff", "tooltip": "Cell A1", "mark": True},
        {"label": "<b>A2</b>", "cell_color": "#e6e6fa", "html": True},
        {"label": "A3", "cell_color": "#f5f5dc"}
    ],
    [
        {"label": "B1", "cell_color": "#f0ffff"},
        {"label": "<span style='color:red'>B2</span>", "cell_color": "#f5f5f5", "html": True},
        {"label": "B3", "cell_color": "#fffaf0"}
    ],
    [
        {"label": "C1", "cell_color": "#fff0f5"},
        {"label": "C2", "cell_color": "#f0f0f0"},
        {"label": "<i>C3</i>", "cell_color": "#fffff0", "html": True}
    ]
]

header = [
    {"label": "Column 1", "cell_color": "#e0e0e0", "mark": True},
    {"label": "Column 2", "cell_color": "#e0e0e0"},
    {"label": "Column 3", "cell_color": "#e0e0e0"}
]

index = ["Row 1", "Row 2", "Row 3"]

selection = st_selectable_grid(
    cells=cells,
    header=header,
    index=index,
    aspect_ratio=1.0,
    allow_secondary_selection=True,
    allow_header_selection=True,
    height=300,
    grid_position="center",
    resize=True,
    mark_color="#2196F3",
    primary_selection_color="#2196F3",
    secondary_selection_color="#FF9800",
    key="grid1"
)

if selection:
    if "primary" in selection:
        st.write("Primary selection (left click):", selection["primary"])
    if "secondary" in selection:
        st.write("Secondary selection (right click):", selection["secondary"])
```

## Features

- Interactive grid with selectable cells
- Support for headers and row indices
- Customizable cell colors and aspect ratio
- Primary (left-click) and secondary (right-click) selections
- Tooltips on hover
- Cell marking with indicator dots
- Responsive design with positioning options
- Fixed or flexible sizing options
- HTML formatting support for cell content

## Parameters

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `cells` | List[List[dict or str]] | Required | 2D array of dictionaries or strings to be displayed in the grid. Dictionary keys: `label`, `cell_color`, `tooltip`, `mark`, `html`. |
| `header` | List[dict or str] or None | None | Optional 1D array for column headers. Same format as cells. |
| `index` | List[dict or str] or None | None | Optional 1D array for row indices. Same format as cells. |
| `aspect_ratio` | float | 1.0 | Controls the aspect ratio (height/width) of cells. |
| `allow_secondary_selection` | bool | False | If True, allows right-click to select a secondary cell. |
| `allow_secondary_selection_first` | bool | False | If True and `allow_secondary_selection` is True, allows right-clicking a secondary cell before selecting a primary cell. |
| `allow_header_selection` | bool | False | If True, allows header cells to be selected. |
| `height` | int or None | None | Optional height constraint in pixels. If None, grid sizes automatically based on width. |
| `resize` | bool | True | If True, grid resizes to fill available space. If False, maintains size based on content. |
| `grid_position` | str | 'center' | Horizontal alignment of the grid. Options: 'left', 'center', 'right'. Not applied if `resize = True`. |
| `mark_color` | str | '#2196F3' | Color for marker dots that appear on cells with mark=True. |
| `primary_selection_color` | str | '#2196F3' | Color for the primary (left-click) selection highlight. |
| `secondary_selection_color` | str | '#FF9800' | Color for the secondary (right-click) selection highlight. |
| `allow_copy_contents` | bool | False | If True, allows users to select and copy text within cells. If False, cells are clickable for selection but text cannot be highlighted. |
| `key` | str or None | None | Unique identifier for the component. |

## Cell Dictionary Format

Each cell can be either a string (which becomes the label) or a dictionary with these keys:

- `label` (str): The text to display in the cell
- `cell_color` (str): Background color in CSS format (e.g., "#f0f8ff" or "red")
- `tooltip` (str): Text to display when hovering over the cell
- `mark` (bool): If True, shows a marker dot in the top-right corner of the cell
- `html` (bool): If True, renders the label content as HTML, allowing formatting tags

## HTML Formatting Example

You can use HTML tags in cell labels when the `html` flag is set to `True`:

```python
cells = [
    [
        {"label": "Normal Text"},
        {"label": "<b>Bold Text</b>", "html": True},
        {"label": "<span style='color:red'>Red Text</span>", "html": True}
    ],
    [
        {"label": "<i>Italic</i>", "html": True},
        {"label": "<b>Bold</b> and <i>italic</i>", "html": True},
        {"label": "<u>Underlined</u>", "html": True}
    ]
]
```

**Security Note:** Use caution when setting `html=True` with untrusted content, as this could introduce security vulnerabilities.


## Return Value

```
{
    "primary": {"x": col_index, "y": row_index},  # For left-click selection
    "secondary": {"x": col_index, "y": row_index}  # For right-click selection (if enabled)
}
```

Secondary selection is only available after a primary selection has been made unless `allow_secondary_selection_first=True`.

## Local example testing

1. Clone and enter the repo:

   ```bash
   git clone https://github.com/hoggatt/st-selectable-grid.git
   cd st-selectable-grid
   ```

2. Create and activate a virtual environment (optional but recommended):

   ```bash
   python -m venv venv
   # On Windows
   venv\Scripts\activate
   # On macOS/Linux
   source venv/bin/activate
   ```

3. Install Python and frontend dependencies:

   ```bash
   pip install -e .
   npm --prefix st_selectable_grid/frontend install
   ```

4. Build the frontend assets:

   ```bash
   npm --prefix st_selectable_grid/frontend run build
   ```

5. From the repo root, run the example against this checkout:

   ```bash
   PYTHONPATH="$PWD" streamlit run st_selectable_grid/example.py
   ```

The `PYTHONPATH="$PWD"` prefix prevents Streamlit from importing an already-installed `st-selectable-grid` package instead of your local files.

While editing frontend files, run this in another terminal:

```bash
npm --prefix st_selectable_grid/frontend run dev
```

The v2 component loads from `st_selectable_grid/frontend/build`; `npm run dev` rebuilds that directory as files change.
