Metadata-Version: 2.4
Name: lhngrid
Version: 0.0.1
Summary: A custom grid to handle tabular data
Author-email: Anu <anu@abc.com>
License-Expression: MIT
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: streamlit>=1.51
Provides-Extra: snowpark
Requires-Dist: snowflake-snowpark-python>=1.5.0; extra == "snowpark"
Provides-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: license-file

# lhngrid

A custom grid to handle tabular data

## Installation instructions

```sh
uv pip install lhngrid
```

### Development install (editable)

When developing this component locally, install it in editable mode so Streamlit picks up code changes without rebuilding a wheel. Run this from the directory that contains `pyproject.toml`:

```sh
uv pip install -e . --force-reinstall
```

## Usage instructions

```python
import streamlit as st

from lhngrid import lhngrid

TABLE_KEY = "tasks"
PAGE_INDEX_KEY = f"{TABLE_KEY}_page_index"
PAGE_SIZE_KEY = f"{TABLE_KEY}_page_size"

st.session_state.setdefault(PAGE_INDEX_KEY, 0)
st.session_state.setdefault(PAGE_SIZE_KEY, 10)


def sync_grid_state(key: str) -> None:
    component = st.session_state.get(key)

    if component is None:
        return

    st.session_state[PAGE_INDEX_KEY] = component.pageIndex
    st.session_state[PAGE_SIZE_KEY] = component.pageSize


value = lhngrid(
    rows=rows,
    columns=columns,
    row_key="id",
    page_index=st.session_state[PAGE_INDEX_KEY],
    page_size=st.session_state[PAGE_SIZE_KEY],
    theme="streamlit-dataframe",
    show_row_selection=False,
    pagination_position="top-left",
    key=TABLE_KEY,
    on_pageIndex_change=sync_grid_state,
    on_pageSize_change=sync_grid_state,
)

st.write(value)
```

### Snowpark DataFrames

LHNGrid can also accept a Snowpark DataFrame through the same `rows`
parameter. Install the optional Snowpark extra when using this path:

```sh
uv pip install "lhngrid[snowpark]"
```

When `rows` is a Snowpark DataFrame, LHNGrid queries only the current page,
applies supported sorting/filtering in Snowpark, and sends page-sized JSON rows
to the frontend.

```python
value = lhngrid(
    rows=session.table("TASKS"),
    columns=None,  # infer columns from the Snowpark schema
    row_key="ID",
    page_index=st.session_state[PAGE_INDEX_KEY],
    page_size=st.session_state[PAGE_SIZE_KEY],
    sorting=st.session_state.get(SORTING_KEY, []),
    key=TABLE_KEY,
    on_pageIndex_change=sync_grid_state,
    on_pageSize_change=sync_grid_state,
    on_sorting_change=sync_grid_state,
)
```

Explicit columns remain the source of truth when provided. Use `sourceKey` when
the Snowpark column name differs from the frontend row key.

```python
columns = [
    {
        "id": "task",
        "header": "Task",
        "accessorKey": "task",
        "sourceKey": "TASK",
        "type": "text",
        "sortable": True,
    },
    {
        "id": "created_at",
        "header": "Created At",
        "accessorKey": "createdAt",
        "sourceKey": "CREATED_AT",
        "type": "date",
        "sortable": True,
    },
]

value = lhngrid(
    rows=session.table("TASKS"),
    columns=columns,
    row_key="ID",
    page_index=st.session_state[PAGE_INDEX_KEY],
    page_size=st.session_state[PAGE_SIZE_KEY],
    sorting=st.session_state.get(SORTING_KEY, []),
    key=TABLE_KEY,
)
```

Callbacks receive the component key so the handler can read the current
component value from `st.session_state[key]`. Exposed callbacks are
`on_pageIndex_change`, `on_pageSize_change`, `on_sorting_change`,
`on_columnFilters_change`, `on_selectedRowId_change`,
`on_selectedRowIds_change`, `on_rowOffset_change`, `on_rowLimit_change`, and
`on_rowAction_change`. The legacy `onIndexChange` parameter still aliases
`on_pageIndex_change`.

### Styling hooks

Available themes are `default` and `streamlit-dataframe`. The
`streamlit-dataframe` theme only changes styling so the grid visually matches
Streamlit's default DataFrame component; it does not add DataFrame features.
Set `show_row_selection=False` to hide the checkbox selection column.
Use `pagination_position` to place the pagination controls. Supported values are
`top-left`, `top-middle`, `top-right`, `bottom-left`, `bottom-middle`, and
`bottom-right`. The default is `bottom-right`.

The component uses readable, scoped class names so app-level CSS can target the
grid safely. Common hooks include `lhn-grid`, `lhn-grid-table-container`,
`lhn-grid-table`, `lhn-grid-header-cell`, `lhn-grid-cell`,
`lhn-grid-table-row`, `lhn-grid-table-row-selected`,
`lhn-grid-row-selection-checkbox`, `lhn-grid-badge`,
`lhn-grid-pagination`, `lhn-grid-page-size-select`, and
`lhn-grid-pagination-button`.

## Build a wheel

To package this component for distribution:

1. Build the frontend assets (from `lhngrid/frontend`):

   ```sh
   npm i
   npm run build
   ```

2. Build the Python wheel using UV (from the project root):
   ```sh
   uv build
   ```

This will create a `dist/` directory containing your wheel. The wheel includes the compiled frontend from `lhngrid/frontend/build`.

### Requirements

- Python >= 3.10
- Node.js >= 24 (LTS)

### Expected output

- `dist/lhngrid-0.0.1-py3-none-any.whl`
- If you run `uv run --with build python -m build` (without `--wheel`), you’ll also get an sdist: `dist/lhngrid-0.0.1.tar.gz`
