Metadata-Version: 2.4
Name: dash-fluida
Version: 0.2.3
Summary: A Dash custom component that measures its real container size in the browser and lays out its children using the same layout engine as @fluida/core.
Project-URL: Homepage, https://github.com/Jaderson1/Fluida
Project-URL: Repository, https://github.com/Jaderson1/Fluida
Project-URL: Issues, https://github.com/Jaderson1/Fluida/issues
Author: Jaderson Manoel Lichtnow Olson
License-Expression: MIT
License-File: LICENSE
Keywords: dash,dashboard,layout,plotly,responsive
Classifier: Development Status :: 3 - Alpha
Classifier: Framework :: Dash
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Requires-Python: >=3.9
Requires-Dist: dash>=2.4
Provides-Extra: dev
Requires-Dist: pytest>=8; extra == 'dev'
Provides-Extra: e2e
Requires-Dist: playwright>=1.56; extra == 'e2e'
Requires-Dist: pytest-playwright>=0.7; extra == 'e2e'
Requires-Dist: pytest>=8; extra == 'e2e'
Requires-Dist: requests>=2.32; extra == 'e2e'
Description-Content-Type: text/markdown

# dash-fluida

A Dash custom component (`FluidaGrid`) that measures its own real container size in the browser and lays out its children using the same layout engine as [`@fluida/core`](https://github.com/Jaderson1/Fluida/tree/main/packages/core).

**Status: pre-release, `0.2.0`.** Not published to PyPI yet.

## Architecture

```
Dash / Python declares FluidaGrid(...)
  → frontend JavaScript measures the container with ResizeObserver
  → requestAnimationFrame coalesces updates (at most one per frame)
  → @fluida/core computes the layout in the browser
  → CSS Grid receives the result
```

The Python side never computes a layout, and never sees a resize event unless you explicitly ask for one (see `notify_layout_changes` below). The computation always happens in the browser, using the real `@fluida/core` package — bundled directly into this component's frontend, not reimplemented in JavaScript or in Python.

`fluida-core` (the pure-Python port, in [`../fluida-core`](../fluida-core)) is a separate, independent thing from this package — useful for offline calculations, backend logic, or generating previews without a browser. This package does not use it and does not need to: the measurement itself only ever happens client-side.

## Installation

Not available on PyPI yet.

```bash
pip install -e path/to/dash-fluida
```

## Usage

```python
from dash import Dash, html
from dash_fluida import FluidaGrid

app = Dash(__name__)

app.layout = html.Div([
    FluidaGrid(
        item_count=6,
        gap=16,
        min_item_width=280,
        strategy="fill",
        children=[html.Div(f"Card {i}") for i in range(6)],
    ),
])

if __name__ == "__main__":
    app.run(debug=True)
```

## Props

| Prop                                         | Type                                                | Default | Notes                                                                                          |
| -------------------------------------------- | --------------------------------------------------- | ------- | ---------------------------------------------------------------------------------------------- |
| `item_count`                                 | `int`                                               | —       | Required. Positive integer only — `1.5`, `True`/`False`, `None` all raise `FluidaConfigError`. |
| `strategy`                                   | `"fit" \| "fill" \| "balanced" \| "preserve-ratio"` | `"fit"` | Anything else raises `FluidaConfigError`.                                                      |
| `gap`                                        | `float`                                             | `16`    |                                                                                                |
| `aspect_ratio`                               | `float`                                             | `1`     | Only used by `"preserve-ratio"`.                                                               |
| `min_item_width`                             | `float`                                             | `None`  | Omitted applies no constraint.                                                                 |
| `auto_height`                                | `bool`                                              | `False` | See below.                                                                                     |
| `style`                                      | `dict`                                              | `None`  | Merged with (and overriding) the layout-driven inline styles.                                  |
| `className`                                  | `str`                                               | `None`  |                                                                                                |
| `notify_layout_changes`                      | `bool`                                              | `False` | See below.                                                                                     |
| `columns`, `rows`, `cellWidth`, `cellHeight` | —                                                   | —       | Output-only; populated when `notify_layout_changes=True`.                                      |

## `auto_height`

By default, this component needs both a real measured width and height. Set `auto_height=True` to compute the layout from width alone — only with `strategy="fit"` or `strategy="preserve-ratio"`, and only with `min_item_width` also set; `"fill"` and `"balanced"` raise the same `FluidaConfigError` `@fluida/core` itself raises for that combination.

```python
FluidaGrid(
    item_count=4,
    strategy="preserve-ratio",
    aspect_ratio=4 / 3,
    min_item_width=300,
    auto_height=True,
    children=[chart_card_a, chart_card_b, chart_card_c, chart_card_d],
)
```

The element's height is then set explicitly — computed from the real result (`rows * cellHeight + (rows - 1) * gap`) — instead of left at a fixed minimum.

## `notify_layout_changes`

By default (`False`), the computed layout only drives this component's own rendering — nothing is ever sent to the Python side, and no round-trip happens on resize. Set it to `True` to also receive `columns`/`rows`/`cellWidth`/`cellHeight` as props, useful for a callback reacting to the computed layout:

```python
FluidaGrid(item_count=6, notify_layout_changes=True, id="grid")

@app.callback(Output("info", "children"), Input("grid", "columns"))
def show_columns(columns):
    return f"Currently showing {columns} columns"
```

Even with this enabled, updates are batched to at most one `setProps` call per animation frame — never one per raw resize event.

## Build tooling

No webpack, no `dash-component-boilerplate`. The frontend is built with [`tsup`](https://tsup.egoist.dev) (esbuild), producing a single IIFE bundle. React and `prop-types` are not bundled — they're provided by Dash's own renderer at runtime (`window.React` / `window.PropTypes`), the same convention Dash's own built-in components use — confirmed directly against `dash`'s own installed, shipped bundle, not assumed.

```bash
pnpm install
pnpm --filter dash-fluida-frontend test
pnpm --filter @fluida/core build
pnpm --filter dash-fluida-frontend build
```

This produces `src/dash_fluida/dash_fluida.min.js`, which `pyproject.toml` includes as a build artifact in the wheel.

## Development (Python side)

```bash
python -m venv .venv
.venv/bin/pip install -e ".[dev]"
.venv/bin/python -m pytest
```

## What is and isn't verified here

The frontend's resize handling — coalescing several `ResizeObserver` measurements into one `requestAnimationFrame` call, always applying the most recent one, and cleaning up on unmount — has its own real test suite (`src/frontend/FluidaGrid.test.tsx`, run with `pnpm --filter dash-fluida-frontend test`), not just an assumption that it matches `@fluida/react`'s equivalent pattern. The Python-side tests (props, validation, serialization, that the real bundle is present, contains the real `@fluida/core` algorithm, and its source map name matches the file actually shipped) also run and pass in this environment. What none of this verifies — because it requires an actual browser — is that `FluidaGrid` visually renders, resizes, and lays out children correctly inside a running Dash app.

## License

MIT.
