From bbe6261439cbb9ed0890c7cbdc86d5eab3950d36 Mon Sep 17 00:00:00 2001 From: Michael Chow Date: Thu, 25 Jul 2024 12:17:29 -0400 Subject: [PATCH 01/87] feat: start rough draft of narwhals support --- shiny/render/_data_frame_utils/_tbl_data.py | 38 +++++++++++++++++-- tests/pytest/test_render_data_frame.py | 1 + .../pytest/test_render_data_frame_tbl_data.py | 36 ++++++++++++++++-- 3 files changed, 68 insertions(+), 7 deletions(-) diff --git a/shiny/render/_data_frame_utils/_tbl_data.py b/shiny/render/_data_frame_utils/_tbl_data.py index 24bdc0501..c247ebd1f 100644 --- a/shiny/render/_data_frame_utils/_tbl_data.py +++ b/shiny/render/_data_frame_utils/_tbl_data.py @@ -5,6 +5,7 @@ from functools import singledispatch from typing import Any, List, Tuple, cast +import narwhals.stable.v1 as nw from htmltools import TagNode from ..._typing_extensions import TypeIs @@ -184,7 +185,7 @@ def _(col: PlSeries) -> FrameDtype: from ._html import col_contains_shiny_html - if col.dtype.is_(pl.String): + if col.dtype == pl.String(): if col_contains_shiny_html(col): type_ = "html" else: @@ -203,6 +204,30 @@ def _(col: PlSeries) -> FrameDtype: return {"type": type_} +@serialize_dtype.register +def _(col: nw.Series) -> FrameDtype: + + from ._html import col_contains_shiny_html + + if col.dtype == nw.String(): + if col_contains_shiny_html(col): + type_ = "html" + else: + type_ = "string" + elif col.dtype.is_numeric(): + type_ = "numeric" + + elif col.dtype == nw.Categorical(): + categories = col.cat.get_categories().to_list() + return {"type": "categorical", "categories": categories} + else: + type_ = "unknown" + if col_contains_shiny_html(col): + type_ = "html" + + return {"type": type_} + + # serialize_frame ---------------------------------------------------------------------- @@ -218,6 +243,8 @@ def _(data: PdDataFrame) -> FrameJson: return serialize_frame_pd(data) +# TODO: test this +@serialize_frame.register(nw.DataFrame) @serialize_frame.register def _(data: PlDataFrame) -> FrameJson: import json @@ -308,6 +335,7 @@ def _( return data.iloc[indx_rows, indx_cols] +@subset_frame.register(nw.DataFrame) @subset_frame.register def _( data: PlDataFrame, @@ -321,7 +349,7 @@ def _( else slice(None) ) indx_rows = rows if rows is not None else slice(None) - return data[indx_rows, indx_cols] + return data[indx_cols][indx_rows] # get_frame_cell ----------------------------------------------------------------------- @@ -341,9 +369,10 @@ def _(data: PdDataFrame, row: int, col: int) -> Any: ) +@get_frame_cell.register(nw.DataFrame) @get_frame_cell.register def _(data: PlDataFrame, row: int, col: int) -> Any: - return data[row, col] + return data.item(row, col) # shape -------------------------------------------------------------------------------- @@ -359,6 +388,7 @@ def _(data: PdDataFrame) -> Tuple[int, ...]: return data.shape +@frame_shape.register(nw.DataFrame) @frame_shape.register def _(data: PlDataFrame) -> Tuple[int, ...]: return data.shape @@ -377,6 +407,7 @@ def _(data: PdDataFrame) -> PdDataFrame: return data.copy() +@copy_frame.register(nw.DataFrame) @copy_frame.register def _(data: PlDataFrame) -> PlDataFrame: return data.clone() @@ -393,6 +424,7 @@ def _(data: PdDataFrame) -> List[str]: return data.columns.to_list() +@frame_column_names.register(nw.DataFrame) @frame_column_names.register def _(data: PlDataFrame) -> List[str]: return data.columns diff --git a/tests/pytest/test_render_data_frame.py b/tests/pytest/test_render_data_frame.py index 8c17fda13..c5757d110 100644 --- a/tests/pytest/test_render_data_frame.py +++ b/tests/pytest/test_render_data_frame.py @@ -1,3 +1,4 @@ +import narwhals as nw import pandas as pd import pytest diff --git a/tests/pytest/test_render_data_frame_tbl_data.py b/tests/pytest/test_render_data_frame_tbl_data.py index 62df978ce..52ee0c7f8 100644 --- a/tests/pytest/test_render_data_frame_tbl_data.py +++ b/tests/pytest/test_render_data_frame_tbl_data.py @@ -4,6 +4,7 @@ from datetime import datetime from typing import Any, Union +import narwhals.stable.v1 as nw import pandas as pd import polars as pl import polars.testing as pl_testing @@ -53,6 +54,9 @@ class D: params_frames = [ pytest.param(pd.DataFrame, id="pandas"), pytest.param(pl.DataFrame, id="polars"), + pytest.param( + lambda d: nw.from_native(pl.DataFrame(d), eager_only=True), id="narwhals" + ), ] DataFrameLike: TypeAlias = Union[pd.DataFrame, pl.DataFrame] @@ -93,6 +97,17 @@ def assert_frame_equal( raise NotImplementedError(f"Unsupported data type: {type(src)}") +def assert_frame_equal2( + src: pd.DataFrame | pl.DataFrame, + target_dict: dict, + use_index: bool = False, +): + src = nw.to_native(src, strict=False) + target = nw.to_native(src, strict=False).__class__(target_dict) + + assert_frame_equal(src, target, use_index) + + # TODO: explicitly pass dtype= when doing Series construction @pytest.mark.parametrize( "ser, res_type", @@ -126,6 +141,13 @@ def test_serialize_dtype( ], res_type: str, ): + if isinstance(ser, pl.Series): + assert ( + serialize_dtype(nw.from_native(ser, eager_only=True, allow_series=True))[ + "type" + ] + == res_type + ) assert serialize_dtype(ser)["type"] == res_type @@ -158,9 +180,9 @@ def test_serialize_frame(df: DataFrameLike): def test_subset_frame(df: DataFrameLike): # TODO: this assumes subset_frame doesn't reset index res = subset_frame(df, rows=[1], cols=["chr", "num"]) - dst = df.__class__({"chr": ["b"], "num": [2]}) + dst = {"chr": ["b"], "num": [2]} - assert_frame_equal(res, dst) + assert_frame_equal2(res, dst) def test_get_frame_cell(df: DataFrameLike): @@ -176,14 +198,20 @@ def test_copy_frame(df: DataFrameLike): def test_subset_frame_rows_single(small_df: DataFrameLike): res = subset_frame(small_df, rows=[1]) - assert_frame_equal(res, small_df.__class__({"x": [2], "y": [4]})) + assert_frame_equal2( + res, + {"x": [2], "y": [4]}, + ) def test_subset_frame_cols_single(small_df: DataFrameLike): # TODO: include test of polars res = subset_frame(small_df, cols=["y"]) - assert_frame_equal(res, small_df.__class__({"y": [3, 4]})) + assert_frame_equal2( + res, + {"y": [3, 4]}, + ) def test_shape(small_df: DataFrameLike): From 57fe20f097ac448773a37c33cc2fadc63bedbf18 Mon Sep 17 00:00:00 2001 From: Barret Schloerke Date: Fri, 26 Jul 2024 11:52:54 -0400 Subject: [PATCH 02/87] add narwhals to deps --- setup.cfg | 1 + 1 file changed, 1 insertion(+) diff --git a/setup.cfg b/setup.cfg index e06db054a..c0200cf55 100644 --- a/setup.cfg +++ b/setup.cfg @@ -58,6 +58,7 @@ install_requires = # https://github.com/posit-dev/py-shiny/issues/1114#issuecomment-1942757757 python-multipart>=0.0.7;platform_system!="Emscripten" setuptools;python_version>="3.12" + narwhals>=1.1.7 tests_require = pytest>=3 zip_safe = False From 81058ea3dd0d74f6b92a237d069f134e741d58a8 Mon Sep 17 00:00:00 2001 From: Barret Schloerke Date: Fri, 26 Jul 2024 11:53:12 -0400 Subject: [PATCH 03/87] lint --- tests/pytest/test_render_data_frame.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/pytest/test_render_data_frame.py b/tests/pytest/test_render_data_frame.py index c5757d110..8c17fda13 100644 --- a/tests/pytest/test_render_data_frame.py +++ b/tests/pytest/test_render_data_frame.py @@ -1,4 +1,3 @@ -import narwhals as nw import pandas as pd import pytest From 869aa7ada347adfe0cad959fc3f80ce93ef25f7a Mon Sep 17 00:00:00 2001 From: Barret Schloerke Date: Fri, 26 Jul 2024 15:12:05 -0400 Subject: [PATCH 04/87] Fix typing issues --- shiny/render/_data_frame_utils/_html.py | 9 ++++++-- .../pytest/test_render_data_frame_tbl_data.py | 23 +++++++++++-------- 2 files changed, 20 insertions(+), 12 deletions(-) diff --git a/shiny/render/_data_frame_utils/_html.py b/shiny/render/_data_frame_utils/_html.py index 196b2069e..ab6626356 100644 --- a/shiny/render/_data_frame_utils/_html.py +++ b/shiny/render/_data_frame_utils/_html.py @@ -9,6 +9,8 @@ from ._types import CellHtml, ReprHtml, SeriesLike if TYPE_CHECKING: + import narwhals.stable.v1 as nw + from ...session import Session @@ -41,8 +43,11 @@ def maybe_as_cell_html( return cast(Jsonifiable, x) -def col_contains_shiny_html(col: SeriesLike) -> bool: - return any(is_shiny_html(val) for _, val in enumerate(col)) +def col_contains_shiny_html(col: SeriesLike | nw.Series) -> bool: + for val in col: + if is_shiny_html(val): + return True + return False # TODO-barret-test; Add test to assert the union type of `TagNode` contains `str` and (HTML | Tagifiable | MetadataNode | ReprHtml). Until a `is tag renderable` method is available in htmltools, we need to check for these types manually and must stay in sync with the `TagNode` union type. diff --git a/tests/pytest/test_render_data_frame_tbl_data.py b/tests/pytest/test_render_data_frame_tbl_data.py index 52ee0c7f8..d4f8c7d13 100644 --- a/tests/pytest/test_render_data_frame_tbl_data.py +++ b/tests/pytest/test_render_data_frame_tbl_data.py @@ -51,12 +51,19 @@ class D: "object": [C(1), D(2)], } + +def polars_df_to_narwhals(df: dict[str, Any]) -> nw.DataFrame[pl.DataFrame]: + return nw.from_native(pl.DataFrame(df), eager_only=True) + + +def polars_series_to_narwhals(ser: pl.Series) -> nw.Series: + return nw.from_native(ser, series_only=True, strict=True) + + params_frames = [ pytest.param(pd.DataFrame, id="pandas"), pytest.param(pl.DataFrame, id="polars"), - pytest.param( - lambda d: nw.from_native(pl.DataFrame(d), eager_only=True), id="narwhals" - ), + pytest.param(polars_df_to_narwhals, id="narwhals"), ] DataFrameLike: TypeAlias = Union[pd.DataFrame, pl.DataFrame] @@ -99,7 +106,7 @@ def assert_frame_equal( def assert_frame_equal2( src: pd.DataFrame | pl.DataFrame, - target_dict: dict, + target_dict: dict[str, Any], use_index: bool = False, ): src = nw.to_native(src, strict=False) @@ -142,12 +149,8 @@ def test_serialize_dtype( res_type: str, ): if isinstance(ser, pl.Series): - assert ( - serialize_dtype(nw.from_native(ser, eager_only=True, allow_series=True))[ - "type" - ] - == res_type - ) + nw_ser = polars_series_to_narwhals(ser) + assert serialize_dtype(nw_ser)["type"] == res_type assert serialize_dtype(ser)["type"] == res_type From 271ec5f52e9c97f1b71b8fb54cfe08c2156fed17 Mon Sep 17 00:00:00 2001 From: Barret Schloerke Date: Fri, 26 Jul 2024 15:16:13 -0400 Subject: [PATCH 05/87] Rename fixtures --- .../pytest/test_render_data_frame_tbl_data.py | 36 +++++++++---------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/tests/pytest/test_render_data_frame_tbl_data.py b/tests/pytest/test_render_data_frame_tbl_data.py index d4f8c7d13..a6d97bad6 100644 --- a/tests/pytest/test_render_data_frame_tbl_data.py +++ b/tests/pytest/test_render_data_frame_tbl_data.py @@ -74,12 +74,12 @@ def polars_series_to_narwhals(ser: pl.Series) -> nw.Series: @pytest.fixture(params=params_frames, scope="function") -def df(request: pytest.FixtureRequest) -> DataFrameLike: +def df_f(request: pytest.FixtureRequest) -> DataFrameLike: return request.param(DATA) @pytest.fixture(params=params_frames, scope="function") -def small_df(request: pytest.FixtureRequest) -> DataFrameLike: +def small_df_f(request: pytest.FixtureRequest) -> DataFrameLike: return request.param({"x": [1, 2], "y": [3, 4]}) @@ -154,13 +154,13 @@ def test_serialize_dtype( assert serialize_dtype(ser)["type"] == res_type -def test_serialize_frame(df: DataFrameLike): +def test_serialize_frame(df_f: DataFrameLike): # TODO: pandas converts datetime entries to int, but Polars # preserves the datetime object. - if isinstance(df, pl.DataFrame): + if isinstance(df_f, pl.DataFrame): pytest.xfail() - res = serialize_frame(df) + res = serialize_frame(df_f) assert res == { "columns": ["num", "chr", "cat", "dt", "struct", "arr", "object"], "index": [0, 1], @@ -180,26 +180,26 @@ def test_serialize_frame(df: DataFrameLike): } -def test_subset_frame(df: DataFrameLike): +def test_subset_frame(df_f: DataFrameLike): # TODO: this assumes subset_frame doesn't reset index - res = subset_frame(df, rows=[1], cols=["chr", "num"]) + res = subset_frame(df_f, rows=[1], cols=["chr", "num"]) dst = {"chr": ["b"], "num": [2]} assert_frame_equal2(res, dst) -def test_get_frame_cell(df: DataFrameLike): - assert get_frame_cell(df, 1, 1) == "b" +def test_get_frame_cell(df_f: DataFrameLike): + assert get_frame_cell(df_f, 1, 1) == "b" -def test_copy_frame(df: DataFrameLike): - new_df = copy_frame(df) +def test_copy_frame(df_f: DataFrameLike): + new_df = copy_frame(df_f) - assert new_df is not df + assert new_df is not df_f -def test_subset_frame_rows_single(small_df: DataFrameLike): - res = subset_frame(small_df, rows=[1]) +def test_subset_frame_rows_single(small_df_f: DataFrameLike): + res = subset_frame(small_df_f, rows=[1]) assert_frame_equal2( res, @@ -207,9 +207,9 @@ def test_subset_frame_rows_single(small_df: DataFrameLike): ) -def test_subset_frame_cols_single(small_df: DataFrameLike): +def test_subset_frame_cols_single(small_df_f: DataFrameLike): # TODO: include test of polars - res = subset_frame(small_df, cols=["y"]) + res = subset_frame(small_df_f, cols=["y"]) assert_frame_equal2( res, @@ -217,5 +217,5 @@ def test_subset_frame_cols_single(small_df: DataFrameLike): ) -def test_shape(small_df: DataFrameLike): - assert frame_shape(small_df) == (2, 2) +def test_shape(small_df_f: DataFrameLike): + assert frame_shape(small_df_f) == (2, 2) From a5714e40e747b1c269dc9a4c65f64ea9c8d0206a Mon Sep 17 00:00:00 2001 From: Barret Schloerke Date: Fri, 26 Jul 2024 17:25:25 -0400 Subject: [PATCH 06/87] Partial for narwhals serialize frame. Still needs work. Need datetime type --- shiny/render/_data_frame_utils/_pandas.py | 3 ++ shiny/render/_data_frame_utils/_tbl_data.py | 46 ++++++++++++++++++- .../pytest/test_render_data_frame_tbl_data.py | 4 +- 3 files changed, 50 insertions(+), 3 deletions(-) diff --git a/shiny/render/_data_frame_utils/_pandas.py b/shiny/render/_data_frame_utils/_pandas.py index a2a3bae26..23df0a9c0 100644 --- a/shiny/render/_data_frame_utils/_pandas.py +++ b/shiny/render/_data_frame_utils/_pandas.py @@ -80,6 +80,9 @@ def wrap_shiny_html_with_session(x: TagNode): res["typeHints"] = type_hints + if "index" in res: + del res["index"] + # print(json.dumps(res, indent=4)) return res diff --git a/shiny/render/_data_frame_utils/_tbl_data.py b/shiny/render/_data_frame_utils/_tbl_data.py index c247ebd1f..2a1426efd 100644 --- a/shiny/render/_data_frame_utils/_tbl_data.py +++ b/shiny/render/_data_frame_utils/_tbl_data.py @@ -244,7 +244,6 @@ def _(data: PdDataFrame) -> FrameJson: # TODO: test this -@serialize_frame.register(nw.DataFrame) @serialize_frame.register def _(data: PlDataFrame) -> FrameJson: import json @@ -276,6 +275,51 @@ def wrap_shiny_html_with_session(x: TagNode): } +@serialize_frame.register(nw.DataFrame) +def _(data: nw.DataFrame[Any]) -> FrameJson: + import json + + type_hints = [serialize_dtype(data[col_name]) for col_name in data.columns] + type_hints_type = {type_hint["type"] for type_hint in type_hints} + + data_rows = data.rows(named=False) + + print(data_rows) + print(data.rows(named=False)) + + # Shiny tag support + if "html" in type_hints_type: + session = require_active_session(None) + + def wrap_shiny_html_with_session(x: TagNode): + return maybe_as_cell_html(x, session=session) + + html_column_positions = [ + i for i, x in enumerate(type_hints_type) if x == "html" + ] + + new_rows: list[tuple[Any, ...]] = [] + + # Wrap the corresponding columns with the cell html object + for row in data_rows: + new_row = list(row) + for html_column_position in html_column_positions: + new_row[html_column_position] = wrap_shiny_html_with_session( + new_row[html_column_position] + ) + new_rows.append(tuple(new_row)) + + data_rows = new_rows + + data_val = json.loads(json.dumps(data_rows, default=str)) + + return { + "columns": data.columns, + "data": data_val, + "typeHints": type_hints, + } + + # subset_frame ------------------------------------------------------------------------- def subset_frame__typed( data: DataFrameLikeT, *, rows: RowsList = None, cols: ColsList = None diff --git a/tests/pytest/test_render_data_frame_tbl_data.py b/tests/pytest/test_render_data_frame_tbl_data.py index a6d97bad6..2504aba20 100644 --- a/tests/pytest/test_render_data_frame_tbl_data.py +++ b/tests/pytest/test_render_data_frame_tbl_data.py @@ -123,7 +123,7 @@ def assert_frame_equal2( (pl.Series([1]), "numeric"), (pl.Series([1.1]), "numeric"), (pl.Series(["a"]), "string"), - (pl.Series([datetime.now()]), "unknown"), + (pl.Series([datetime.now()]), "datetime"), (pl.Series(["a"], dtype=pl.Categorical), "categorical"), (pl.Series([{"x": 1}]), "unknown"), (pl.Series([h1("yo")]), "html"), @@ -163,7 +163,7 @@ def test_serialize_frame(df_f: DataFrameLike): res = serialize_frame(df_f) assert res == { "columns": ["num", "chr", "cat", "dt", "struct", "arr", "object"], - "index": [0, 1], + # "index": [0, 1], "data": [ [1, "a", "a", "2000-01-02T00:00:00.000", {"x": 1}, [1, 2], ""], [2, "b", "a", "2000-01-02T00:00:00.000", {"x": 2}, [3, 4], "D(y=2)"], From db83bc7bb4dc9cab8746bdeeb0a3153da04688c9 Mon Sep 17 00:00:00 2001 From: Barret Schloerke Date: Mon, 26 Aug 2024 15:17:28 -0400 Subject: [PATCH 07/87] add missing narwhals dep in config --- pyproject.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/pyproject.toml b/pyproject.toml index 4643bdaea..fe2a39655 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -49,6 +49,7 @@ dependencies = [ "prompt-toolkit;platform_system!='Emscripten'", "python-multipart>=0.0.7;platform_system!='Emscripten'", "setuptools;python_version>='3.12'", + "narwhals>=1.1.7", ] [project.optional-dependencies] From 9318a5b02608292829d20e8d92564a15fc90c2df Mon Sep 17 00:00:00 2001 From: Barret Schloerke Date: Thu, 5 Sep 2024 13:23:27 -0400 Subject: [PATCH 08/87] Disable timedelta dtype within pandas (as moving towards all narwhals operations) --- shiny/render/_data_frame_utils/_pandas.py | 6 ++++-- shiny/render/_data_frame_utils/_types.py | 9 ++++++++- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/shiny/render/_data_frame_utils/_pandas.py b/shiny/render/_data_frame_utils/_pandas.py index 23df0a9c0..fa8bc3286 100644 --- a/shiny/render/_data_frame_utils/_pandas.py +++ b/shiny/render/_data_frame_utils/_pandas.py @@ -122,8 +122,10 @@ def serialize_pd_dtype( } elif t in {"datetime64", "datetime"}: t = "datetime" - elif t in {"timedelta", "timedelta64"}: - t = "timedelta" + + # # Disable timedelta as narwhals does not support it + # elif t in {"timedelta", "timedelta64"}: + # t = "timedelta" else: if col_contains_shiny_html(col): t = "html" diff --git a/shiny/render/_data_frame_utils/_types.py b/shiny/render/_data_frame_utils/_types.py index 9bef6c76d..6250f0c3d 100644 --- a/shiny/render/_data_frame_utils/_types.py +++ b/shiny/render/_data_frame_utils/_types.py @@ -175,7 +175,14 @@ class FrameJson(TypedDict): class FrameDtypeSubset(TypedDict): - type: Literal["numeric", "string", "html", "datetime", "timedelta", "unknown"] + type: Literal[ + "numeric", + "string", + "html", + "datetime", + # "timedelta", + "unknown", + ] class FrameDtypeCategories(TypedDict): From 42d035380b25468c8f8f5810086dffd4cef86686 Mon Sep 17 00:00:00 2001 From: Barret Schloerke Date: Thu, 5 Sep 2024 13:24:24 -0400 Subject: [PATCH 09/87] Scaffold out more dtypes --- shiny/render/_data_frame_utils/_tbl_data.py | 38 +++++++++++++++++---- shiny/render/_data_frame_utils/_types.py | 3 ++ 2 files changed, 35 insertions(+), 6 deletions(-) diff --git a/shiny/render/_data_frame_utils/_tbl_data.py b/shiny/render/_data_frame_utils/_tbl_data.py index 2a1426efd..c030e706e 100644 --- a/shiny/render/_data_frame_utils/_tbl_data.py +++ b/shiny/render/_data_frame_utils/_tbl_data.py @@ -11,8 +11,6 @@ from ..._typing_extensions import TypeIs from ...session import require_active_session from ._html import maybe_as_cell_html - -# from ...types import Jsonifiable from ._types import ( CellPatch, ColsList, @@ -204,12 +202,21 @@ def _(col: PlSeries) -> FrameDtype: return {"type": type_} +nw_boolean = nw.Boolean() +nw_categorical = nw.Categorical() +nw_enum = nw.Enum() +nw_string = nw.String() +nw_datetime = nw.Datetime() +nw_duration = nw.Duration() +nw_object = nw.Object() + + @serialize_dtype.register def _(col: nw.Series) -> FrameDtype: from ._html import col_contains_shiny_html - if col.dtype == nw.String(): + if col.dtype == nw_string: if col_contains_shiny_html(col): type_ = "html" else: @@ -217,9 +224,28 @@ def _(col: nw.Series) -> FrameDtype: elif col.dtype.is_numeric(): type_ = "numeric" - elif col.dtype == nw.Categorical(): + elif col.dtype == nw_categorical: categories = col.cat.get_categories().to_list() return {"type": "categorical", "categories": categories} + elif col.dtype == nw_enum: + raise NotImplementedError("boolean type not tested") + cat_col = col.cast(nw.Categorical) + categories = cat_col.cat.get_categories().to_list() + return {"type": "categorical", "categories": categories} + + elif col.dtype == nw_boolean: + raise NotImplementedError("boolean type not tested") + type_ = "boolean" + elif col.dtype == nw_duration: + raise NotImplementedError("duration type not tested") + type_ = "duration" + elif col.dtype == nw_datetime: + type_ = "datetime" + elif col.dtype == nw_object: + type_ = "object" + if col_contains_shiny_html(col): + type_ = "html" + else: type_ = "unknown" if col_contains_shiny_html(col): @@ -284,8 +310,8 @@ def _(data: nw.DataFrame[Any]) -> FrameJson: data_rows = data.rows(named=False) - print(data_rows) - print(data.rows(named=False)) + # print(data_rows) + # print(data.rows(named=False)) # Shiny tag support if "html" in type_hints_type: diff --git a/shiny/render/_data_frame_utils/_types.py b/shiny/render/_data_frame_utils/_types.py index 6250f0c3d..a8f6cf49f 100644 --- a/shiny/render/_data_frame_utils/_types.py +++ b/shiny/render/_data_frame_utils/_types.py @@ -176,11 +176,14 @@ class FrameJson(TypedDict): class FrameDtypeSubset(TypedDict): type: Literal[ + "boolean", "numeric", "string", "html", "datetime", # "timedelta", + "duration", + "object", "unknown", ] From 3e3c8c07c4920c5f37dbf0130d795c889210545a Mon Sep 17 00:00:00 2001 From: Barret Schloerke Date: Thu, 5 Sep 2024 13:25:02 -0400 Subject: [PATCH 10/87] Use `orjson` instead of `json` package to serialize json. (Native date iso support) --- pyproject.toml | 1 + shiny/render/_data_frame_utils/_tbl_data.py | 14 ++++++++++++-- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index d53bad810..261f9dfc4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -48,6 +48,7 @@ dependencies = [ "python-multipart>=0.0.7;platform_system!='Emscripten'", "setuptools;python_version>='3.12'", "narwhals>=1.1.7", + "orjson>=3.10.7", ] [project.optional-dependencies] diff --git a/shiny/render/_data_frame_utils/_tbl_data.py b/shiny/render/_data_frame_utils/_tbl_data.py index c030e706e..fc767f0f0 100644 --- a/shiny/render/_data_frame_utils/_tbl_data.py +++ b/shiny/render/_data_frame_utils/_tbl_data.py @@ -303,7 +303,6 @@ def wrap_shiny_html_with_session(x: TagNode): @serialize_frame.register(nw.DataFrame) def _(data: nw.DataFrame[Any]) -> FrameJson: - import json type_hints = [serialize_dtype(data[col_name]) for col_name in data.columns] type_hints_type = {type_hint["type"] for type_hint in type_hints} @@ -337,7 +336,18 @@ def wrap_shiny_html_with_session(x: TagNode): data_rows = new_rows - data_val = json.loads(json.dumps(data_rows, default=str)) + import orjson + + data_val = orjson.loads( + orjson.dumps( + data_rows, + default=str, + option=orjson.OPT_UTC_Z, + ) + ) + + # import json + # data_val = json.loads(json.dumps(data_rows, default=str)) return { "columns": data.columns, From ef2ee1c9a309906a4e5864158460086c25483e97 Mon Sep 17 00:00:00 2001 From: Barret Schloerke Date: Thu, 5 Sep 2024 13:25:37 -0400 Subject: [PATCH 11/87] Update tests, trying to support more dtypes (more to go). Disable non-narwhals tests --- shiny/render/_data_frame_utils/_types.py | 1 + .../pytest/test_render_data_frame_tbl_data.py | 51 +++++++++++-------- 2 files changed, 30 insertions(+), 22 deletions(-) diff --git a/shiny/render/_data_frame_utils/_types.py b/shiny/render/_data_frame_utils/_types.py index a8f6cf49f..43fb8b85f 100644 --- a/shiny/render/_data_frame_utils/_types.py +++ b/shiny/render/_data_frame_utils/_types.py @@ -70,6 +70,7 @@ class DataFrameLike(ABC): ... DataFrameLike.register(PlDataFrame) DataFrameLikeT = TypeVar("DataFrameLikeT", PdDataFrame, PlDataFrame) +SeriesLikeT = TypeVar("SeriesLikeT", PdSeries, PlSeries) # --------------------------------------------------------------------- diff --git a/tests/pytest/test_render_data_frame_tbl_data.py b/tests/pytest/test_render_data_frame_tbl_data.py index 2504aba20..64d1787f6 100644 --- a/tests/pytest/test_render_data_frame_tbl_data.py +++ b/tests/pytest/test_render_data_frame_tbl_data.py @@ -9,7 +9,6 @@ import polars as pl import polars.testing as pl_testing import pytest -from typing_extensions import TypeAlias from shiny.render._data_frame_utils._tbl_data import ( copy_frame, @@ -19,6 +18,11 @@ serialize_frame, subset_frame, ) +from shiny.render._data_frame_utils._types import ( + DataFrameLike, + DataFrameLikeT, + SeriesLike, +) from shiny.ui import HTML, h1 @@ -52,26 +56,24 @@ class D: } -def polars_df_to_narwhals(df: dict[str, Any]) -> nw.DataFrame[pl.DataFrame]: - return nw.from_native(pl.DataFrame(df), eager_only=True) +def polars_dict_to_narwhals(d: dict[str, Any]) -> nw.DataFrame[pl.DataFrame]: + return nw.from_native(pl.DataFrame(d), eager_only=True) + +def df_to_narwhals(df: DataFrameLikeT) -> nw.DataFrame[DataFrameLikeT]: + return nw.from_native(df, eager_only=True) -def polars_series_to_narwhals(ser: pl.Series) -> nw.Series: + +def series_to_narwhals(ser: SeriesLike) -> nw.Series: return nw.from_native(ser, series_only=True, strict=True) params_frames = [ pytest.param(pd.DataFrame, id="pandas"), pytest.param(pl.DataFrame, id="polars"), - pytest.param(polars_df_to_narwhals, id="narwhals"), + pytest.param(polars_dict_to_narwhals, id="narwhals"), ] -DataFrameLike: TypeAlias = Union[pd.DataFrame, pl.DataFrame] -# SeriesLike: TypeAlias = Union[ -# pd.Series[Any], -# pl.Series, -# ] - @pytest.fixture(params=params_frames, scope="function") def df_f(request: pytest.FixtureRequest) -> DataFrameLike: @@ -134,7 +136,7 @@ def assert_frame_equal2( (pd.Series(["a"], dtype="object"), "string"), (pd.Series(["a"], dtype="string"), "string"), (pd.Series([datetime.now()], dtype="datetime64[ns]"), "datetime"), - (pd.Series([pd.Timedelta(days=1)]), "timedelta"), + # (pd.Series([pd.Timedelta(days=1)]), "timedelta"), (pd.Series(["a"], dtype="category"), "categorical"), (pd.Series([{"x": 1}]), "unknown"), (pd.Series([h1("yo")]), "html"), @@ -149,24 +151,29 @@ def test_serialize_dtype( res_type: str, ): if isinstance(ser, pl.Series): - nw_ser = polars_series_to_narwhals(ser) + nw_ser = series_to_narwhals(ser) assert serialize_dtype(nw_ser)["type"] == res_type - assert serialize_dtype(ser)["type"] == res_type + # assert serialize_dtype(ser)["type"] == res_type def test_serialize_frame(df_f: DataFrameLike): - # TODO: pandas converts datetime entries to int, but Polars - # preserves the datetime object. - if isinstance(df_f, pl.DataFrame): - pytest.xfail() + if not isinstance(df_f, pl.DataFrame): + pytest.skip() - res = serialize_frame(df_f) + df_nw = df_to_narwhals(df_f) + + # # TODO: pandas converts datetime entries to int, but Polars + # # preserves the datetime object. + # if isinstance(df_f, pl.DataFrame): + # pytest.xfail() + + res = serialize_frame(df_nw) assert res == { "columns": ["num", "chr", "cat", "dt", "struct", "arr", "object"], # "index": [0, 1], "data": [ - [1, "a", "a", "2000-01-02T00:00:00.000", {"x": 1}, [1, 2], ""], - [2, "b", "a", "2000-01-02T00:00:00.000", {"x": 2}, [3, 4], "D(y=2)"], + [1, "a", "a", "2000-01-02T00:00:00", {"x": 1}, [1, 2], ""], + [2, "b", "a", "2000-01-02T00:00:00", {"x": 2}, [3, 4], {"y": 2}], ], "typeHints": [ {"type": "numeric"}, @@ -175,7 +182,7 @@ def test_serialize_frame(df_f: DataFrameLike): {"type": "datetime"}, {"type": "unknown"}, {"type": "unknown"}, - {"type": "unknown"}, + {"type": "object"}, ], } From 563bc520dfcda0d2067100e5fbc181b52574b5fc Mon Sep 17 00:00:00 2001 From: Barret Schloerke Date: Mon, 16 Sep 2024 16:37:52 -0400 Subject: [PATCH 12/87] Bump min version of narwhals to v1.8.0 for `nw.Series.scatter(rows, vals)` support` --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 261f9dfc4..8b07a9a19 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -47,7 +47,7 @@ dependencies = [ "prompt-toolkit;platform_system!='Emscripten'", "python-multipart>=0.0.7;platform_system!='Emscripten'", "setuptools;python_version>='3.12'", - "narwhals>=1.1.7", + "narwhals>=1.8.0", "orjson>=3.10.7", ] From 861329a0f00c850546fce403c9f2801a1ec62b8f Mon Sep 17 00:00:00 2001 From: Barret Schloerke Date: Mon, 16 Sep 2024 16:39:43 -0400 Subject: [PATCH 13/87] Expose narwhals types of `DataFrame`, `DataFrameT`, `IntoDataFrame`, and `IntoDataFrameT` --- shiny/render/__init__.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/shiny/render/__init__.py b/shiny/render/__init__.py index cba8c5df0..1144ac56d 100644 --- a/shiny/render/__init__.py +++ b/shiny/render/__init__.py @@ -15,7 +15,10 @@ from ._data_frame_utils._selection import CellSelection from ._data_frame_utils._types import ( # noqa: F401 StyleInfo, - DataFrameLikeT as _DataFrameLikeT, # pyright: ignore[reportUnusedImport] + DataFrame, # pyright: ignore[reportUnusedImport] + DataFrameT, # pyright: ignore[reportUnusedImport] + IntoDataFrame, # pyright: ignore[reportUnusedImport] + IntoDataFrameT, # pyright: ignore[reportUnusedImport] ) from ._deprecated import ( # noqa: F401 RenderFunction, # pyright: ignore[reportUnusedImport] From 517273439971d8d489b4eba4e99c272beba47f0a Mon Sep 17 00:00:00 2001 From: Barret Schloerke Date: Mon, 16 Sep 2024 16:45:55 -0400 Subject: [PATCH 14/87] Add narwhals for types and integrate into _tbl_data.py --- shiny/render/_data_frame_utils/_tbl_data.py | 631 +++++++++++++------- shiny/render/_data_frame_utils/_types.py | 70 ++- shiny/render/_render.py | 1 + 3 files changed, 459 insertions(+), 243 deletions(-) diff --git a/shiny/render/_data_frame_utils/_tbl_data.py b/shiny/render/_data_frame_utils/_tbl_data.py index fc767f0f0..c3b46d4bf 100644 --- a/shiny/render/_data_frame_utils/_tbl_data.py +++ b/shiny/render/_data_frame_utils/_tbl_data.py @@ -3,7 +3,7 @@ from __future__ import annotations from functools import singledispatch -from typing import Any, List, Tuple, cast +from typing import Any, List, Tuple, TypedDict import narwhals.stable.v1 as nw from htmltools import TagNode @@ -13,42 +13,58 @@ from ._html import maybe_as_cell_html from ._types import ( CellPatch, + CellValue, ColsList, - DataFrameLike, - DataFrameLikeT, + DataFrame, + DataFrameT, + DType, FrameDtype, FrameJson, - ListSeriesLike, + IntoDataFrame, + IntoDataFrameT, PandasCompatible, PdDataFrame, - PdSeries, - PlDataFrame, - PlSeries, RowsList, SeriesLike, ) __all__ = ( - "is_data_frame_like", + "is_into_data_frame", # "as_data_frame_like", - "frame_columns", + "as_data_frame", + "data_frame_to_native", + # "frame_columns", "apply_frame_patches", "serialize_dtype", "serialize_frame", "subset_frame", - "get_frame_cell", + # "get_frame_cell", "frame_shape", "copy_frame", "frame_column_names", ) + # as_frame ----------------------------------------------------------------------------- -def as_data_frame_like( - data: DataFrameLikeT, -) -> DataFrameLikeT: - if is_data_frame_like(data): +def data_frame_to_native(data: DataFrame[IntoDataFrameT]) -> IntoDataFrameT: + return nw.to_native(data) + + +def as_data_frame( + data: IntoDataFrameT | DataFrame[IntoDataFrameT], +) -> DataFrame[IntoDataFrameT]: + if isinstance(data, DataFrame): + return data # pyright: ignore[reportUnknownVariableType] + + return nw.from_native(as_native_data_frame(data), eager_only=True) + + +def as_native_data_frame( + data: IntoDataFrameT, +) -> IntoDataFrameT: + if is_into_data_frame(data): return data # Legacy support for non-Pandas/Polars data frames that were previously supported @@ -85,76 +101,161 @@ def as_data_frame_like( # return True -def is_data_frame_like( - data: DataFrameLikeT | object, -) -> TypeIs[DataFrameLikeT]: - if isinstance(data, (PdDataFrame, PlDataFrame)): +# TODO-barret; Replace with `nw.is_into_data_frame(x)` +def is_into_data_frame( + data: IntoDataFrameT | object, +) -> TypeIs[IntoDataFrameT]: + nw_df = nw.from_native(data, strict=False, eager_only=True) + if isinstance(nw_df, nw.DataFrame): return True - return False -# frame_columns ------------------------------------------------------------------------ +# # frame_columns ------------------------------------------------------------------------ -@singledispatch -def frame_columns(data: DataFrameLike) -> ListSeriesLike: - raise TypeError(f"Unsupported type: {type(data)}") +# @singledispatch +# def frame_columns(data: IntoDataFrame) -> ListSeriesLike: +# raise TypeError(f"Unsupported type: {type(data)}") -@frame_columns.register -def _(data: PdDataFrame) -> ListSeriesLike: - ret = [cast(PlSeries, data[col]) for col in data.columns] - return ret +# @frame_columns.register +# def _(data: PdDataFrame) -> ListSeriesLike: +# ret = [cast(PlSeries, data[col]) for col in data.columns] +# return ret -@frame_columns.register -def _(data: PlDataFrame) -> ListSeriesLike: - return data.get_columns() +# @frame_columns.register +# def _(data: PlDataFrame) -> ListSeriesLike: +# return data.get_columns() # apply_frame_patches -------------------------------------------------------------------- -def apply_frame_patches__typed( - data: DataFrameLikeT, patches: List[CellPatch] -) -> DataFrameLikeT: - return cast(DataFrameLikeT, apply_frame_patches(data, patches)) +# def apply_frame_patches__typed( +# data: IntoDataFrameT, patches: List[CellPatch] +# ) -> IntoDataFrameT: +# return cast(IntoDataFrameT, apply_frame_patches(data, patches)) -@singledispatch +# @singledispatch +# def apply_frame_patches( +# data: IntoDataFrame, +# patches: List[CellPatch], +# ) -> IntoDataFrame: +# raise TypeError(f"Unsupported type: {type(data)}") + + +# @apply_frame_patches.register +# def _(data: PdDataFrame, patches: List[CellPatch]) -> PdDataFrame: +# import pandas as pd + +# # Enable copy-on-write mode for the data; +# # Use `deep=False` to avoid copying the full data; CoW will copy the necessary data when modified +# with pd.option_context("mode.copy_on_write", True): +# # Apply patches! +# data = data.copy(deep=False) +# for cell_patch in patches: +# data.iat[ # pyright: ignore[reportUnknownMemberType] +# cell_patch["row_index"], +# cell_patch["column_index"], +# ] = cell_patch["value"] + +# return data + + +# @apply_frame_patches.register +# def _(data: PlDataFrame, patches: List[CellPatch]) -> PlDataFrame: +# data = data.clone() +# for cell_patch in patches: +# data[cell_patch["row_index"], cell_patch["column_index"]] = cell_patch["value"] + +# return data + + +# @apply_frame_patches.register(DataFrame) def apply_frame_patches( - data: DataFrameLike, + nw_data: DataFrame[IntoDataFrameT], patches: List[CellPatch], -) -> DataFrameLike: - raise TypeError(f"Unsupported type: {type(data)}") +) -> DataFrame[IntoDataFrameT]: + # data = data.clone() + # Us an index to know which row we are updating + data_with_index = nw_data.with_row_index() -@apply_frame_patches.register -def _(data: PdDataFrame, patches: List[CellPatch]) -> PdDataFrame: - import pandas as pd + # Apply the patches - # Enable copy-on-write mode for the data; - # Use `deep=False` to avoid copying the full data; CoW will copy the necessary data when modified - with pd.option_context("mode.copy_on_write", True): - # Apply patches! - data = data.copy(deep=False) - for cell_patch in patches: - data.iat[ # pyright: ignore[reportUnknownMemberType] - cell_patch["row_index"], - cell_patch["column_index"], - ] = cell_patch["value"] + # If multiple `when` statements are possible, then use this code + if True: + # # https://discord.com/channels/1235257048170762310/1235257049626181656/1283415086722977895 + # # Using narwhals >= v1.7.0 + # @nw.narwhalify + # def func(df): + # return df.with_columns( + # df['a'].scatter([0, 1], [999, 888]), + # df['b'].scatter([0, 1], [777, 555]), + # ) - return data + # Group patches by column + # This allows for a single column to be updated in a single operation (rather than multiple updates to the same column) + cell_patches_by_column: dict[str, ScatterValues] = {} + for cell_patch in patches: + column_name = nw_data.columns[cell_patch["column_index"]] + if column_name not in cell_patches_by_column: + cell_patches_by_column[column_name] = { + "row_indexes": [], + "values": [], + } + + # Append the row index and value to the column information + cell_patches_by_column[column_name]["row_indexes"].append( + cell_patch["row_index"] + ) + cell_patches_by_column[column_name]["values"].append(cell_patch["value"]) + + # Upgrade the Scatter info to new column Series objects + scatter_columns = [ + nw_data[column_name].scatter( + scatter_values["row_indexes"], scatter_values["values"] + ) + for column_name, scatter_values in cell_patches_by_column.items() + ] + # Apply patches to the nw data + return nw_data.with_columns(*scatter_columns) + + # Documentation for nw.when: https://narwhals-dev.github.io/narwhals/api-reference/narwhals/#narwhals.when + # when_then_otherwise_arr: List[IntoExpr] = [] + + for column_name, cell_patches in cell_patches_by_column.items(): + col_expr = nw.when( + nw.col("index") == cell_patches[0]["row_index"], + ).then(cell_patches[0]["value"]) + + for i, cell_patch in enumerate(cell_patches): + if i == 0: + # Performed above to get typing value + continue + col_expr = col_expr.when( + nw.col("index") == cell_patch["row_index"], + ).then(cell_patch["value"]) + + col_expr = col_expr.alias(column_name) + # when_then_otherwise_arr.append(col_expr) + else: + # https://discord.com/channels/1235257048170762310/1235257049626181656/1283078606775517184 + # Very inefficient code that works to update a cell by making a new column for every patch value + for cell_patch in patches: + data_with_index = data_with_index.with_columns( + nw.when(nw.col("index") == cell_patch["row_index"]) + .then(cell_patch["value"]) + .otherwise(nw.col(nw_data.columns[cell_patch["column_index"]])) + ) -@apply_frame_patches.register -def _(data: PlDataFrame, patches: List[CellPatch]) -> PlDataFrame: - data = data.clone() - for cell_patch in patches: - data[cell_patch["row_index"], cell_patch["column_index"]] = cell_patch["value"] + patched_data = data_with_index.drop("index") - return data + return patched_data # serialize_dtype ---------------------------------------------------------------------- @@ -170,36 +271,36 @@ def serialize_dtype(col: SeriesLike) -> FrameDtype: # the dispatch type below. -@serialize_dtype.register -def _(col: PdSeries) -> FrameDtype: - from ._pandas import serialize_pd_dtype +# @serialize_dtype.register +# def _(col: PdSeries) -> FrameDtype: +# from ._pandas import serialize_pd_dtype - return serialize_pd_dtype(col) +# return serialize_pd_dtype(col) -@serialize_dtype.register -def _(col: PlSeries) -> FrameDtype: - import polars as pl +# @serialize_dtype.register +# def _(col: PlSeries) -> FrameDtype: +# import polars as pl - from ._html import col_contains_shiny_html +# from ._html import col_contains_shiny_html - if col.dtype == pl.String(): - if col_contains_shiny_html(col): - type_ = "html" - else: - type_ = "string" - elif col.dtype.is_numeric(): - type_ = "numeric" +# if col.dtype == pl.String(): +# if col_contains_shiny_html(col): +# type_ = "html" +# else: +# type_ = "string" +# elif col.dtype.is_numeric(): +# type_ = "numeric" - elif col.dtype.is_(pl.Categorical()): - categories = col.cat.get_categories().to_list() - return {"type": "categorical", "categories": categories} - else: - type_ = "unknown" - if col_contains_shiny_html(col): - type_ = "html" +# elif col.dtype.is_(pl.Categorical()): +# categories = col.cat.get_categories().to_list() +# return {"type": "categorical", "categories": categories} +# else: +# type_ = "unknown" +# if col_contains_shiny_html(col): +# type_ = "html" - return {"type": type_} +# return {"type": type_} nw_boolean = nw.Boolean() @@ -216,32 +317,34 @@ def _(col: nw.Series) -> FrameDtype: from ._html import col_contains_shiny_html - if col.dtype == nw_string: + dtype: DType = col.dtype + + if dtype == nw_string: if col_contains_shiny_html(col): type_ = "html" else: type_ = "string" - elif col.dtype.is_numeric(): + elif dtype.is_numeric(): type_ = "numeric" - elif col.dtype == nw_categorical: + elif dtype == nw_categorical: categories = col.cat.get_categories().to_list() return {"type": "categorical", "categories": categories} - elif col.dtype == nw_enum: - raise NotImplementedError("boolean type not tested") + elif dtype == nw_enum: + raise NotImplementedError("enum type not tested") cat_col = col.cast(nw.Categorical) categories = cat_col.cat.get_categories().to_list() return {"type": "categorical", "categories": categories} - elif col.dtype == nw_boolean: + elif dtype == nw_boolean: raise NotImplementedError("boolean type not tested") type_ = "boolean" - elif col.dtype == nw_duration: + elif dtype == nw_duration: raise NotImplementedError("duration type not tested") type_ = "duration" - elif col.dtype == nw_datetime: + elif dtype == nw_datetime: type_ = "datetime" - elif col.dtype == nw_object: + elif dtype == nw_object: type_ = "object" if col_contains_shiny_html(col): type_ = "html" @@ -257,52 +360,62 @@ def _(col: nw.Series) -> FrameDtype: # serialize_frame ---------------------------------------------------------------------- -@singledispatch -def serialize_frame(data: DataFrameLike) -> FrameJson: - raise TypeError(f"Unsupported type: {type(data)}") +# @singledispatch +# def serialize_frame(data: IntoDataFrame) -> FrameJson: +# raise TypeError(f"Unsupported type: {type(data)}") -@serialize_frame.register -def _(data: PdDataFrame) -> FrameJson: - from ._pandas import serialize_frame_pd +# @serialize_frame.register +# def _(data: PdDataFrame) -> FrameJson: +# from ._pandas import serialize_frame_pd - return serialize_frame_pd(data) +# return serialize_frame_pd(data) -# TODO: test this -@serialize_frame.register -def _(data: PlDataFrame) -> FrameJson: - import json +# # TODO: test this +# @serialize_frame.register +# def _(data: PlDataFrame) -> FrameJson: +# import json - type_hints = list(map(serialize_dtype, data)) - data_by_row = list(map(list, data.rows())) +# type_hints = list(map(serialize_dtype, data)) +# data_by_row = list(map(list, data.rows())) - # Shiny tag support - type_hints_type = [type_hint["type"] for type_hint in type_hints] - if "html" in type_hints_type: - session = require_active_session(None) +# # Shiny tag support +# type_hints_type = [type_hint["type"] for type_hint in type_hints] +# if "html" in type_hints_type: +# session = require_active_session(None) - def wrap_shiny_html_with_session(x: TagNode): - return maybe_as_cell_html(x, session=session) +# def wrap_shiny_html_with_session(x: TagNode): +# return maybe_as_cell_html(x, session=session) - html_columns = [i for i, x in enumerate(type_hints_type) if x == "html"] +# html_columns = [i for i, x in enumerate(type_hints_type) if x == "html"] - for html_column in html_columns: - for row in data_by_row: - row[html_column] = wrap_shiny_html_with_session(row[html_column]) +# for html_column in html_columns: +# for row in data_by_row: +# row[html_column] = wrap_shiny_html_with_session(row[html_column]) - data_val = json.loads(json.dumps(data_by_row, default=str)) +# data_val = json.loads(json.dumps(data_by_row, default=str)) - return { - # "index": list(range(len(data))), - "columns": data.columns, - "data": data_val, - "typeHints": type_hints, - } +# return { +# # "index": list(range(len(data))), +# "columns": data.columns, +# "data": data_val, +# "typeHints": type_hints, +# } + +# try: +# import pandas as pd # type: ignore # noqa: F401 + +# has_pandas = True +# except ImportError: +# has_pandas = False -@serialize_frame.register(nw.DataFrame) -def _(data: nw.DataFrame[Any]) -> FrameJson: +# @serialize_frame.register(DataFrame) +def serialize_frame(into_data: IntoDataFrame) -> FrameJson: + # def _(data: DataFrame[Any]) -> FrameJson: + + data = as_data_frame(into_data) type_hints = [serialize_dtype(data[col_name]) for col_name in data.columns] type_hints_type = {type_hint["type"] for type_hint in type_hints} @@ -338,11 +451,28 @@ def wrap_shiny_html_with_session(x: TagNode): import orjson + # TODO-barret; Remove debug! Maybe? + native_data = nw.to_native(data) + if isinstance(native_data, PdDataFrame): + from pandas import Timestamp + + def my_str(x: Any) -> str: + print("x", x) + if isinstance(x, Timestamp): + return x.isoformat() + + return str(x) + + else: + + def my_str(x: Any) -> str: + return str(x) + data_val = orjson.loads( orjson.dumps( data_rows, - default=str, - option=orjson.OPT_UTC_Z, + default=my_str, + # option=(orjson.OPT_NAIVE_UTC), ) ) @@ -357,16 +487,13 @@ def wrap_shiny_html_with_session(x: TagNode): # subset_frame ------------------------------------------------------------------------- -def subset_frame__typed( - data: DataFrameLikeT, *, rows: RowsList = None, cols: ColsList = None -) -> DataFrameLikeT: - return cast(DataFrameLikeT, subset_frame(data, rows=rows, cols=cols)) - - -@singledispatch +# @singledispatch def subset_frame( - data: DataFrameLike, *, rows: RowsList = None, cols: ColsList = None -) -> DataFrameLike: + data: DataFrameT, + *, + rows: RowsList = None, + cols: ColsList = None, +) -> DataFrameT: """Return a subsetted DataFrame, based on row positions and column names. Note that when None is passed, all rows or columns get included. @@ -374,137 +501,181 @@ def subset_frame( # Note that this type signature assumes column names are strings things. # This is always true in Polars, but not in Pandas (e.g. a column name could be an # int, or even a tuple of ints) - raise TypeError(f"Unsupported type: {type(data)}") + if cols is None: + if rows is None: + return data + else: + # This feels like it should be `data[rows, :]` but that doesn't work for polars + return data[rows] + else: + # `cols` is not None + col_names = [data.columns[col] if isinstance(col, int) else col for col in cols] + if rows is None: + return data[:, col_names] + else: + return data[rows, col_names] + + +# @subset_frame.register +# def _( +# data: PdDataFrame, +# *, +# rows: RowsList = None, +# cols: ColsList = None, +# ) -> PdDataFrame: +# # Enable copy-on-write mode for the data; +# # Use `deep=False` to avoid copying the full data; CoW will copy the necessary data when modified +# import pandas as pd + +# with pd.option_context("mode.copy_on_write", True): +# # iloc requires integer positions, so we convert column name strings to ints, or +# # the slice default. +# indx_cols = ( # pyright: ignore[reportUnknownVariableType] +# slice(None) +# if cols is None +# else [ +# ( +# # Send in an array of size 1 and retrieve the first element +# data.columns.get_indexer_for( # pyright: ignore[reportUnknownMemberType] +# [col] +# )[ +# 0 +# ] +# if isinstance(col, str) +# else col +# ) +# for col in cols +# ] +# ) + +# # Force list when using a non-None value for pandas compatibility +# indx_rows = list(rows) if rows is not None else slice(None) + +# return data.iloc[indx_rows, indx_cols] + + +# @subset_frame.register +# def _( +# data: PlDataFrame, +# *, +# rows: RowsList = None, +# cols: ColsList = None, +# ) -> PlDataFrame: +# indx_cols = ( +# [col if isinstance(col, str) else data.columns[col] for col in cols] +# if cols is not None +# else slice(None) +# ) +# indx_rows = rows if rows is not None else slice(None) +# return data[indx_cols][indx_rows] + + +# # get_frame_cell ----------------------------------------------------------------------- -@subset_frame.register -def _( - data: PdDataFrame, - *, - rows: RowsList = None, - cols: ColsList = None, -) -> PdDataFrame: - # Enable copy-on-write mode for the data; - # Use `deep=False` to avoid copying the full data; CoW will copy the necessary data when modified - import pandas as pd - - with pd.option_context("mode.copy_on_write", True): - # iloc requires integer positions, so we convert column name strings to ints, or - # the slice default. - indx_cols = ( # pyright: ignore[reportUnknownVariableType] - slice(None) - if cols is None - else [ - ( - # Send in an array of size 1 and retrieve the first element - data.columns.get_indexer_for( # pyright: ignore[reportUnknownMemberType] - [col] - )[ - 0 - ] - if isinstance(col, str) - else col - ) - for col in cols - ] - ) +# @singledispatch +# def get_frame_cell(data: IntoDataFrame, row: int, col: int) -> Any: +# raise TypeError(f"Unsupported type: {type(data)}") - # Force list when using a non-None value for pandas compatibility - indx_rows = list(rows) if rows is not None else slice(None) - return data.iloc[indx_rows, indx_cols] +# @get_frame_cell.register +# def _(data: PdDataFrame, row: int, col: int) -> Any: +# return ( +# data.iat[ # pyright: ignore[reportUnknownMemberType, reportUnknownVariableType] +# row, col +# ] +# ) -@subset_frame.register(nw.DataFrame) -@subset_frame.register -def _( - data: PlDataFrame, - *, - rows: RowsList = None, - cols: ColsList = None, -) -> PlDataFrame: - indx_cols = ( - [col if isinstance(col, str) else data.columns[col] for col in cols] - if cols is not None - else slice(None) - ) - indx_rows = rows if rows is not None else slice(None) - return data[indx_cols][indx_rows] +# @get_frame_cell.register(DataFrame) +# @get_frame_cell.register +# def _(data: PlDataFrame, row: int, col: int) -> Any: +# return data.item(row, col) -# get_frame_cell ----------------------------------------------------------------------- +# shape -------------------------------------------------------------------------------- -@singledispatch -def get_frame_cell(data: DataFrameLike, row: int, col: int) -> Any: - raise TypeError(f"Unsupported type: {type(data)}") +# @singledispatch +# def frame_shape(data: IntoDataFrame) -> Tuple[int, int]: +# raise TypeError(f"Unsupported type: {type(data)}") -@get_frame_cell.register -def _(data: PdDataFrame, row: int, col: int) -> Any: - return ( - data.iat[ # pyright: ignore[reportUnknownMemberType, reportUnknownVariableType] - row, col - ] - ) +# # @frame_shape.register +# # def _(data: PdDataFrame) -> Tuple[int, int]: +# # return data.shape -@get_frame_cell.register(nw.DataFrame) -@get_frame_cell.register -def _(data: PlDataFrame, row: int, col: int) -> Any: - return data.item(row, col) +# # @frame_shape.register +# # def _(data: PlDataFrame) -> Tuple[int, int]: +# # return data.shape -# shape -------------------------------------------------------------------------------- +# @frame_shape.register(DataFrame) +# def _(data: DataFrame[Any]) -> Tuple[int, int]: +# return data.shape -@singledispatch -def frame_shape(data: DataFrameLike) -> Tuple[int, ...]: - raise TypeError(f"Unsupported type: {type(data)}") +def frame_shape(data: IntoDataFrame) -> Tuple[int, int]: + nw_data = as_data_frame(data) + return nw_data.shape -@frame_shape.register -def _(data: PdDataFrame) -> Tuple[int, ...]: - return data.shape +def column_is_numeric(nw_data: DataFrame[Any], column_index: int) -> bool: + series_dtype: DType = nw_data[:, column_index].dtype + return series_dtype.is_numeric() -@frame_shape.register(nw.DataFrame) -@frame_shape.register -def _(data: PlDataFrame) -> Tuple[int, ...]: - return data.shape +# copy_frame --------------------------------------------------------------------------- -# copy_frame --------------------------------------------------------------------------- +def copy_frame(nw_data: DataFrameT) -> DataFrameT: + return nw_data.clone() -@singledispatch -def copy_frame(data: DataFrameLike) -> DataFrameLike: - raise TypeError(f"Unsupported type: {type(data)}") +# @singledispatch +# def copy_frame(data: IntoDataFrame) -> IntoDataFrame: +# raise TypeError(f"Unsupported type: {type(data)}") -@copy_frame.register -def _(data: PdDataFrame) -> PdDataFrame: - return data.copy() +# @copy_frame.register +# def _(data: PdDataFrame) -> PdDataFrame: +# return data.copy() -@copy_frame.register(nw.DataFrame) -@copy_frame.register -def _(data: PlDataFrame) -> PlDataFrame: - return data.clone() +# @copy_frame.register(DataFrame) +# @copy_frame.register +# def _(data: PlDataFrame) -> PlDataFrame: +# return data.clone() # column_names ------------------------------------------------------------------------- -@singledispatch -def frame_column_names(data: DataFrameLike) -> List[str]: - raise TypeError(f"Unsupported type: {type(data)}") +# @singledispatch +# def frame_column_names(data: IntoDataFrame) -> List[str]: +# raise TypeError(f"Unsupported type: {type(data)}") + + +# # @frame_column_names.register +# # def _(data: PdDataFrame) -> List[str]: +# # return data.columns.to_list() + +# # @frame_column_names.register +# # def _(data: PlDataFrame) -> List[str]: +# # return data.columns + + +# @frame_column_names.register(DataFrame) +# def _(data: DataFrame[Any]) -> List[str]: +# return data.columns + + +def frame_column_names(into_data: IntoDataFrame) -> List[str]: + return as_data_frame(into_data).columns -@frame_column_names.register -def _(data: PdDataFrame) -> List[str]: - return data.columns.to_list() +nw.narwhalify -@frame_column_names.register(nw.DataFrame) -@frame_column_names.register -def _(data: PlDataFrame) -> List[str]: - return data.columns +class ScatterValues(TypedDict): + row_indexes: list[int] + values: list[CellValue] diff --git a/shiny/render/_data_frame_utils/_types.py b/shiny/render/_data_frame_utils/_types.py index 43fb8b85f..b3d3d8506 100644 --- a/shiny/render/_data_frame_utils/_types.py +++ b/shiny/render/_data_frame_utils/_types.py @@ -1,3 +1,5 @@ +# TODO-barret; Replace all usage of (PdDataFrame, PlDataFrame, etc) with narwhals + from __future__ import annotations from abc import ABC @@ -10,18 +12,67 @@ Optional, Protocol, Tuple, - TypeVar, Union, cast, runtime_checkable, ) +import narwhals.stable.v1 as nw from htmltools import TagNode +from narwhals.dtypes import DType as DType +from narwhals.typing import DataFrameT as DataFrameT +from narwhals.typing import IntoDataFrame as IntoDataFrame +from narwhals.typing import IntoDataFrameT as IntoDataFrameT +from narwhals.typing import IntoExpr as IntoExpr from ..._typing_extensions import Annotated, NotRequired, Required, TypedDict from ...types import Jsonifiable, JsonifiableDict, ListOrTuple from ._databackend import AbstractBackend +# from narwhals.typing import FrameT as NwFrameT + +__all__ = ( + "PdDataFrame", + "PlDataFrame", + "PdSeries", + "PlSeries", + # "ListSeriesLike", + "SeriesLike", + "IntoExpr", + "DataFrame", + "DataFrameT", + "DType", + "IntoDataFrame", + "IntoDataFrameT", + "PandasCompatible", + "CellHtml", + "ColumnSort", + "ColumnFilterStr", + "ColumnFilterNumber", + "ColumnFilter", + "DataViewInfo", + "FrameRenderPatchInfo", + "FrameRenderSelectionModes", + "FrameRender", + "frame_render_to_jsonifiable", + "FrameJsonOptions", + "FrameJson", + "RowsList", + "ColsList", + "FrameDtypeSubset", + "FrameDtypeCategories", + "FrameDtype", + "StyleInfoBody", + "StyleInfo", + "BrowserStyleInfoBody", + "BrowserStyleInfo", + "ReprHtml", + "CellValue", + "CellPatch", + "CellPatchProcessed", +) + + # --------------------------------------------------------------------- if TYPE_CHECKING: @@ -35,9 +86,8 @@ PdSeries = pd.Series[Any] PlSeries = pl.Series - ListSeriesLike = Union[List[PdSeries], List[PlSeries]] + # ListSeriesLike = Union[List[PdSeries], List[PlSeries]] SeriesLike = Union[PdSeries, PlSeries] - DataFrameLike = Union[PdDataFrame, PlDataFrame] else: @@ -54,23 +104,17 @@ class PdSeries(AbstractBackend): class PlSeries(AbstractBackend): _backends = [("polars", "Series")] - class ListSeriesLike(ABC): ... + # class ListSeriesLike(ABC): ... class SeriesLike(ABC): ... - class DataFrameLike(ABC): ... - - ListSeriesLike.register(PdSeries) - ListSeriesLike.register(PlSeries) + # ListSeriesLike.register(PdSeries) + # ListSeriesLike.register(PlSeries) SeriesLike.register(PdSeries) SeriesLike.register(PlSeries) - DataFrameLike.register(PdDataFrame) - DataFrameLike.register(PlDataFrame) - -DataFrameLikeT = TypeVar("DataFrameLikeT", PdDataFrame, PlDataFrame) -SeriesLikeT = TypeVar("SeriesLikeT", PdSeries, PlSeries) +DataFrame = nw.DataFrame # --------------------------------------------------------------------- diff --git a/shiny/render/_render.py b/shiny/render/_render.py index fd00d4af9..8fa4d0f24 100644 --- a/shiny/render/_render.py +++ b/shiny/render/_render.py @@ -11,6 +11,7 @@ from htmltools import Tag, TagAttrValue, TagChild +# TODO-barret; Replace usage of (PdDataFrame, PandasCompatible, etc) with narwhals from ._data_frame_utils._types import PandasCompatible, PdDataFrame if TYPE_CHECKING: From ce6cd351b0903d7bfd9cb21f493ed95d66368fda Mon Sep 17 00:00:00 2001 From: Barret Schloerke Date: Mon, 16 Sep 2024 16:46:39 -0400 Subject: [PATCH 15/87] Styles function will accept `IntoDataFrameT` type --- shiny/render/_data_frame_utils/_styles.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/shiny/render/_data_frame_utils/_styles.py b/shiny/render/_data_frame_utils/_styles.py index 0653924fa..b5119de28 100644 --- a/shiny/render/_data_frame_utils/_styles.py +++ b/shiny/render/_data_frame_utils/_styles.py @@ -3,10 +3,10 @@ from typing import Callable, List from ...types import ListOrTuple -from ._tbl_data import frame_column_names -from ._types import BrowserStyleInfo, DataFrameLikeT, StyleInfo +from ._tbl_data import frame_column_names, frame_shape +from ._types import BrowserStyleInfo, IntoDataFrameT, StyleInfo -StyleFn = Callable[[DataFrameLikeT], List["StyleInfo"]] +StyleFn = Callable[[IntoDataFrameT], List["StyleInfo"]] def style_info_to_browser_style_info( @@ -163,8 +163,8 @@ def style_info_rows( def as_style_infos( - infos: StyleInfo | list[StyleInfo] | StyleFn[DataFrameLikeT] | None, -) -> list[StyleInfo] | StyleFn[DataFrameLikeT]: + infos: StyleInfo | list[StyleInfo] | StyleFn[IntoDataFrameT] | None, +) -> list[StyleInfo] | StyleFn[IntoDataFrameT]: if callable(infos): return infos @@ -179,14 +179,14 @@ def as_style_infos( def as_browser_style_infos( - infos: list[StyleInfo] | StyleFn[DataFrameLikeT], + infos: list[StyleInfo] | StyleFn[IntoDataFrameT], *, - data: DataFrameLikeT, + into_data: IntoDataFrameT, ) -> list[BrowserStyleInfo]: - browser_column_names = frame_column_names(data) + browser_column_names = frame_column_names(into_data) if callable(infos): - style_infos = infos(data) + style_infos = infos(into_data) else: style_infos = infos @@ -195,7 +195,7 @@ def as_browser_style_infos( if not isinstance(style_infos, list): style_infos = [style_infos] - nrow = data.shape[0] + nrow = frame_shape(into_data)[0] browser_infos = [ style_info_to_browser_style_info( From 3fea35ceec0eb5b1eb1252bc98a68dd2b69d1af3 Mon Sep 17 00:00:00 2001 From: Barret Schloerke Date: Mon, 16 Sep 2024 16:47:04 -0400 Subject: [PATCH 16/87] Be explicit on type of object being inspected --- shiny/render/_data_frame_utils/_selection.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/shiny/render/_data_frame_utils/_selection.py b/shiny/render/_data_frame_utils/_selection.py index 52125f5b6..ac51127ae 100644 --- a/shiny/render/_data_frame_utils/_selection.py +++ b/shiny/render/_data_frame_utils/_selection.py @@ -3,13 +3,13 @@ # TODO-barret-render.data_frame; Docs # TODO-barret-render.data_frame; Add examples of selection! import warnings -from typing import Literal, Set, Union, cast +from typing import Any, Literal, Set, Union, cast from ..._deprecated import warn_deprecated from ..._typing_extensions import TypedDict from ...types import ListOrTuple from ._tbl_data import frame_shape -from ._types import DataFrameLike, FrameRenderSelectionModes +from ._types import DataFrame, FrameRenderSelectionModes NoneSelectionMode = Literal["none"] RowSelectionMode = Literal["row", "rows"] @@ -233,14 +233,14 @@ def as_browser_cell_selection( x: BrowserCellSelection | CellSelection | Literal["all"] | None, *, selection_modes: SelectionModes, - data: DataFrameLike, + nw_data: DataFrame[Any], ) -> BrowserCellSelection: if x is None or selection_modes._is_none(): return {"type": "none"} if x == "all": - row_len, col_len = frame_shape(data) + row_len, col_len = frame_shape(nw_data) # Look at the selection modes to determine what to do if selection_modes._has_rect(): if selection_modes.rect == "cell": @@ -334,7 +334,7 @@ def as_cell_selection( x: CellSelection | Literal["all"] | None | BrowserCellSelection, *, selection_modes: SelectionModes, - data: DataFrameLike, + nw_data: DataFrame[Any], data_view_rows: ListOrTuple[int], data_view_cols: ListOrTuple[int], ) -> CellSelection: @@ -345,7 +345,7 @@ def as_cell_selection( browser_cell_selection = as_browser_cell_selection( x, selection_modes=selection_modes, - data=data, + nw_data=nw_data, ) ret: CellSelection | None = None if browser_cell_selection["type"] == "none": @@ -379,7 +379,7 @@ def as_cell_selection( ) # Make sure the rows are within the data - nrow, ncol = frame_shape(data) + nrow, ncol = frame_shape(nw_data) ret["rows"] = tuple(row for row in ret["rows"] if row < nrow) ret["cols"] = tuple(col for col in ret["cols"] if col < ncol) From dc8179f2b8a9b97291016bef28c29c1d5703b302 Mon Sep 17 00:00:00 2001 From: Barret Schloerke Date: Mon, 16 Sep 2024 16:47:19 -0400 Subject: [PATCH 17/87] Disable all pandas specific functions for data frame --- shiny/render/_data_frame_utils/_pandas.py | 266 +++++++++++----------- 1 file changed, 133 insertions(+), 133 deletions(-) diff --git a/shiny/render/_data_frame_utils/_pandas.py b/shiny/render/_data_frame_utils/_pandas.py index fa8bc3286..0eedbbb82 100644 --- a/shiny/render/_data_frame_utils/_pandas.py +++ b/shiny/render/_data_frame_utils/_pandas.py @@ -1,135 +1,135 @@ from __future__ import annotations -import json -from typing import TYPE_CHECKING, Any - -from htmltools import TagNode - -from ...session._utils import require_active_session -from ._html import col_contains_shiny_html, maybe_as_cell_html -from ._tbl_data import PdDataFrame, frame_column_names -from ._types import FrameDtype, FrameJson - -if TYPE_CHECKING: - import pandas as pd - - -def serialize_frame_pd(df: "pd.DataFrame") -> FrameJson: - import pandas as pd - - columns = frame_column_names(df) - columns_set = set(columns) - if len(columns_set) != len(columns): - raise ValueError( - "The column names of the pandas DataFrame are not unique." - " This is not supported by the data_frame renderer." - ) - - # Currently, we don't make use of the index; drop it so we don't error trying to - # serialize it or something - df = df.reset_index(drop=True) - - # # Can we keep the original column information? - # # Maybe we need to inspect the original columns for any "unknown" column type. See if it contains any HTML or Tag objects - # for col in columns: - # if df[col].dtype.name == "unknown": - # print(df[col].to_list()) - # raise ValueError( - # "The pandas DataFrame contains columns of type 'object'." - # " This is not supported by the data_frame renderer." - # ) - - type_hints = serialize_numpy_dtypes(df) - - # Auto opt-in for html columns - html_columns = [ - i for i, type_hint in enumerate(type_hints) if type_hint["type"] == "html" - ] - - if len(html_columns) > 0: - # Enable copy-on-write mode for the data; - # Use `deep=False` to avoid copying the full data; CoW will copy the necessary data when modified - - with pd.option_context("mode.copy_on_write", True): - df = df.copy(deep=False) - session = require_active_session(None) - - def wrap_shiny_html_with_session(x: TagNode): - return maybe_as_cell_html(x, session=session) - - for html_column in html_columns: - # _upgrade_ all the HTML columns to `CellHtml` json objects - df[df.columns[html_column]] = df[ - df.columns[html_column] - ].apply( # pyright: ignore[reportUnknownMemberType] - wrap_shiny_html_with_session - ) - - res = json.loads( - # {index: [index], columns: [columns], data: [values]} - df.to_json( # pyright: ignore[reportUnknownMemberType] - None, - orient="split", - # note that date_format iso converts durations to ISO8601 Durations. - # e.g. 1 Day -> P1DT0H0M0S - # see https://en.wikipedia.org/wiki/ISO_8601#Durations - date_format="iso", - default_handler=str, - ) - ) - - res["typeHints"] = type_hints - - if "index" in res: - del res["index"] - - # print(json.dumps(res, indent=4)) - return res - - -def serialize_numpy_dtypes(df: PdDataFrame) -> list[FrameDtype]: - return [ - serialize_pd_dtype(df[col]) # pyright: ignore[reportUnknownArgumentType] - for col in df.columns - ] - - -def serialize_pd_dtype( - col: "pd.Series[Any]", -) -> FrameDtype: - import pandas as pd - - t = pd.api.types.infer_dtype(col) - # t can be any of: string, bytes, floating, integer, mixed-integer, - # mixed-integer-float, decimal, complex, categorical, boolean, datetime64, - # datetime, date, timedelta64, timedelta, time, period, mixed, unknown-array - - if t == "string": - if col_contains_shiny_html(col): - t = "html" - else: - pass - # If no HTML (which is a str) is found, then it is a string! (Keep t as `"string"`) - elif t in ["bytes", "floating", "integer", "decimal", "mixed-integer-float"]: - t = "numeric" - elif t == "categorical": - return { - "type": "categorical", - "categories": [ - str(x) # pyright: ignore[reportUnknownArgumentType] - for x in col.cat.categories.to_list() # pyright: ignore[reportUnknownVariableType, reportUnknownMemberType] - ], - } - elif t in {"datetime64", "datetime"}: - t = "datetime" - - # # Disable timedelta as narwhals does not support it - # elif t in {"timedelta", "timedelta64"}: - # t = "timedelta" - else: - if col_contains_shiny_html(col): - t = "html" - else: - t = "unknown" - - return {"type": t} +# import json +# from typing import TYPE_CHECKING, Any + +# from htmltools import TagNode + +# from ...session._utils import require_active_session +# from ._html import col_contains_shiny_html, maybe_as_cell_html +# from ._tbl_data import PdDataFrame, frame_column_names +# from ._types import FrameDtype, FrameJson + +# if TYPE_CHECKING: +# import pandas as pd + + +# def serialize_frame_pd(df: "pd.DataFrame") -> FrameJson: +# import pandas as pd + +# columns = frame_column_names(df) +# columns_set = set(columns) +# if len(columns_set) != len(columns): +# raise ValueError( +# "The column names of the pandas DataFrame are not unique." +# " This is not supported by the data_frame renderer." +# ) + +# # Currently, we don't make use of the index; drop it so we don't error trying to +# # serialize it or something +# df = df.reset_index(drop=True) + +# # # Can we keep the original column information? +# # # Maybe we need to inspect the original columns for any "unknown" column type. See if it contains any HTML or Tag objects +# # for col in columns: +# # if df[col].dtype.name == "unknown": +# # print(df[col].to_list()) +# # raise ValueError( +# # "The pandas DataFrame contains columns of type 'object'." +# # " This is not supported by the data_frame renderer." +# # ) + +# type_hints = serialize_numpy_dtypes(df) + +# # Auto opt-in for html columns +# html_columns = [ +# i for i, type_hint in enumerate(type_hints) if type_hint["type"] == "html" +# ] + +# if len(html_columns) > 0: +# # Enable copy-on-write mode for the data; +# # Use `deep=False` to avoid copying the full data; CoW will copy the necessary data when modified + +# with pd.option_context("mode.copy_on_write", True): +# df = df.copy(deep=False) +# session = require_active_session(None) + +# def wrap_shiny_html_with_session(x: TagNode): +# return maybe_as_cell_html(x, session=session) + +# for html_column in html_columns: +# # _upgrade_ all the HTML columns to `CellHtml` json objects +# df[df.columns[html_column]] = df[ +# df.columns[html_column] +# ].apply( # pyright: ignore[reportUnknownMemberType] +# wrap_shiny_html_with_session +# ) + +# res = json.loads( +# # {index: [index], columns: [columns], data: [values]} +# df.to_json( # pyright: ignore[reportUnknownMemberType] +# None, +# orient="split", +# # note that date_format iso converts durations to ISO8601 Durations. +# # e.g. 1 Day -> P1DT0H0M0S +# # see https://en.wikipedia.org/wiki/ISO_8601#Durations +# date_format="iso", +# default_handler=str, +# ) +# ) + +# res["typeHints"] = type_hints + +# if "index" in res: +# del res["index"] + +# # print(json.dumps(res, indent=4)) +# return res + + +# def serialize_numpy_dtypes(df: PdDataFrame) -> list[FrameDtype]: +# return [ +# serialize_pd_dtype(df[col]) # pyright: ignore[reportUnknownArgumentType] +# for col in df.columns +# ] + + +# def serialize_pd_dtype( +# col: "pd.Series[Any]", +# ) -> FrameDtype: +# import pandas as pd + +# t = pd.api.types.infer_dtype(col) +# # t can be any of: string, bytes, floating, integer, mixed-integer, +# # mixed-integer-float, decimal, complex, categorical, boolean, datetime64, +# # datetime, date, timedelta64, timedelta, time, period, mixed, unknown-array + +# if t == "string": +# if col_contains_shiny_html(col): +# t = "html" +# else: +# pass +# # If no HTML (which is a str) is found, then it is a string! (Keep t as `"string"`) +# elif t in ["bytes", "floating", "integer", "decimal", "mixed-integer-float"]: +# t = "numeric" +# elif t == "categorical": +# return { +# "type": "categorical", +# "categories": [ +# str(x) # pyright: ignore[reportUnknownArgumentType] +# for x in col.cat.categories.to_list() # pyright: ignore[reportUnknownVariableType, reportUnknownMemberType] +# ], +# } +# elif t in {"datetime64", "datetime"}: +# t = "datetime" + +# # # Disable timedelta as narwhals does not support it +# # elif t in {"timedelta", "timedelta64"}: +# # t = "timedelta" +# else: +# if col_contains_shiny_html(col): +# t = "html" +# else: +# t = "unknown" + +# return {"type": t} From 002ba7e4533d8034aac8c0aaa45a349fcaaaaf25 Mon Sep 17 00:00:00 2001 From: Barret Schloerke Date: Mon, 16 Sep 2024 17:00:05 -0400 Subject: [PATCH 18/87] DataGrid and DataTable can now accept `IntroDataFrameT` --- .../_data_frame_utils/_datagridtable.py | 35 ++++++++++--------- shiny/render/_data_frame_utils/_tbl_data.py | 20 +++++++---- 2 files changed, 33 insertions(+), 22 deletions(-) diff --git a/shiny/render/_data_frame_utils/_datagridtable.py b/shiny/render/_data_frame_utils/_datagridtable.py index 93cfd57a8..86c652f79 100644 --- a/shiny/render/_data_frame_utils/_datagridtable.py +++ b/shiny/render/_data_frame_utils/_datagridtable.py @@ -11,8 +11,8 @@ as_selection_modes, ) from ._styles import StyleFn, StyleInfo, as_browser_style_infos, as_style_infos -from ._tbl_data import as_data_frame_like, serialize_frame -from ._types import DataFrameLikeT, FrameJson +from ._tbl_data import compatible_to_pandas, serialize_frame +from ._types import FrameJson, IntoDataFrameT class AbstractTabularData(abc.ABC): @@ -22,7 +22,7 @@ def to_payload(self) -> FrameJson: ... @add_example(ex_dir="../../api-examples/data_frame_grid_table") @add_example(ex_dir="../../api-examples/data_frame_styles") -class DataGrid(AbstractTabularData, Generic[DataFrameLikeT]): +class DataGrid(AbstractTabularData, Generic[IntoDataFrameT]): """ Holds the data and options for a :class:`~shiny.render.data_frame` output, for a spreadsheet-like view. @@ -114,18 +114,18 @@ class DataGrid(AbstractTabularData, Generic[DataFrameLikeT]): * :class:`~shiny.render.DataTable` - A more _tabular_ view of the data. """ - data: DataFrameLikeT + data: IntoDataFrameT width: str | float | None height: str | float | None summary: bool | str filters: bool editable: bool selection_modes: SelectionModes - styles: list[StyleInfo] | StyleFn[DataFrameLikeT] + styles: list[StyleInfo] | StyleFn[IntoDataFrameT] def __init__( self, - data: DataFrameLikeT, + data: IntoDataFrameT, *, width: str | float | None = "fit-content", height: str | float | None = None, @@ -133,11 +133,14 @@ def __init__( filters: bool = False, editable: bool = False, selection_mode: SelectionModeInput = "none", - styles: StyleInfo | list[StyleInfo] | StyleFn[DataFrameLikeT] | None = None, + styles: StyleInfo | list[StyleInfo] | StyleFn[IntoDataFrameT] | None = None, row_selection_mode: RowSelectionModeDeprecated = "deprecated", ): - self.data = as_data_frame_like(data) + # self._data_is_nw = isinstance(data, NwDataFrameRaw) + # self.data = as_narwhals(data) + # self.data = as_nw_friendly_data_frame(data) + self.data = data self.width = width self.height = height @@ -172,7 +175,7 @@ def to_payload(self) -> FrameJson: "fill": self.height is None, "styles": as_browser_style_infos( self.styles, - data=self.data, + into_data=self.data, ), }, } @@ -181,7 +184,7 @@ def to_payload(self) -> FrameJson: @add_example(ex_dir="../../api-examples/data_frame_grid_table") @add_example(ex_dir="../../api-examples/data_frame_styles") -class DataTable(AbstractTabularData, Generic[DataFrameLikeT]): +class DataTable(AbstractTabularData, Generic[IntoDataFrameT]): """ Holds the data and options for a :class:`~shiny.render.data_frame` output, for a spreadsheet-like view. @@ -273,18 +276,18 @@ class DataTable(AbstractTabularData, Generic[DataFrameLikeT]): * :class:`~shiny.render.DataTable` - A more _grid_ view of the data. """ - data: DataFrameLikeT + data: IntoDataFrameT width: str | float | None height: str | float | None summary: bool | str filters: bool editable: bool selection_modes: SelectionModes - styles: list[StyleInfo] | StyleFn[DataFrameLikeT] + styles: list[StyleInfo] | StyleFn[IntoDataFrameT] def __init__( self, - data: DataFrameLikeT, + data: IntoDataFrameT, *, width: str | float | None = "fit-content", height: str | float | None = "500px", @@ -292,10 +295,10 @@ def __init__( filters: bool = False, editable: bool = False, selection_mode: SelectionModeInput = "none", - styles: StyleInfo | list[StyleInfo] | StyleFn[DataFrameLikeT] | None = None, + styles: StyleInfo | list[StyleInfo] | StyleFn[IntoDataFrameT] | None = None, row_selection_mode: Literal["deprecated"] = "deprecated", ): - self.data = as_data_frame_like(data) + self.data = compatible_to_pandas(data) self.width = width self.height = height @@ -329,7 +332,7 @@ def to_payload(self) -> FrameJson: "style": "table", "styles": as_browser_style_infos( self.styles, - data=self.data, + into_data=self.data, ), }, } diff --git a/shiny/render/_data_frame_utils/_tbl_data.py b/shiny/render/_data_frame_utils/_tbl_data.py index c3b46d4bf..9c058eab8 100644 --- a/shiny/render/_data_frame_utils/_tbl_data.py +++ b/shiny/render/_data_frame_utils/_tbl_data.py @@ -57,16 +57,24 @@ def as_data_frame( ) -> DataFrame[IntoDataFrameT]: if isinstance(data, DataFrame): return data # pyright: ignore[reportUnknownVariableType] + try: + return nw.from_native(data, eager_only=True) + except TypeError as e: + try: + return nw.from_native(compatible_to_pandas(data), eager_only=True) + except BaseException: + # Couldn't convert to pandas, so raise the original error + raise e - return nw.from_native(as_native_data_frame(data), eager_only=True) - -def as_native_data_frame( +def compatible_to_pandas( data: IntoDataFrameT, ) -> IntoDataFrameT: - if is_into_data_frame(data): - return data + """ + Convert data to pandas, if possible. + Should only call this method if Narwhals can not handle the data directly. + """ # Legacy support for non-Pandas/Polars data frames that were previously supported # and converted to pandas if isinstance(data, PandasCompatible): @@ -101,7 +109,7 @@ def as_native_data_frame( # return True -# TODO-barret; Replace with `nw.is_into_data_frame(x)` +# TODO-barret; Replace with `nw.is_into_data_frame(x)`? def is_into_data_frame( data: IntoDataFrameT | object, ) -> TypeIs[IntoDataFrameT]: From 2eacaa502b11b990bc815a3d00e217692fa95fd4 Mon Sep 17 00:00:00 2001 From: Barret Schloerke Date: Mon, 16 Sep 2024 17:12:23 -0400 Subject: [PATCH 19/87] Upgrade `render.data_frame` to handle `IntoDataFrameT`. Add `._nw_data()`, `._value_data()`, `._data_is_nw()`, and convert to original type helper method --- shiny/render/_data_frame.py | 150 +++++++++++++------- shiny/render/_data_frame_utils/_tbl_data.py | 2 +- shiny/render/_data_frame_utils/_types.py | 1 - 3 files changed, 101 insertions(+), 52 deletions(-) diff --git a/shiny/render/_data_frame.py b/shiny/render/_data_frame.py index ede2d8e1f..a37a20e72 100644 --- a/shiny/render/_data_frame.py +++ b/shiny/render/_data_frame.py @@ -4,7 +4,7 @@ # TODO-barret-render.data_frame; Docs # TODO-barret-render.data_frame; Add examples! -from typing import TYPE_CHECKING, Any, Awaitable, Callable, Literal, Union, cast +from typing import TYPE_CHECKING, Any, Awaitable, Callable, Literal, cast from htmltools import Tag @@ -32,19 +32,20 @@ ) from ._data_frame_utils._styles import as_browser_style_infos from ._data_frame_utils._tbl_data import ( - apply_frame_patches__typed, - frame_columns, + apply_frame_patches, + as_data_frame, + data_frame_to_native, frame_shape, - serialize_dtype, - subset_frame__typed, + subset_frame, ) from ._data_frame_utils._types import ( CellPatchProcessed, ColumnFilter, ColumnSort, - DataFrameLikeT, + DataFrame, FrameDtype, FrameRender, + IntoDataFrameT, cell_patch_processed_to_jsonifiable, frame_render_to_jsonifiable, ) @@ -55,17 +56,13 @@ if TYPE_CHECKING: from ..session import Session -DataFrameResult = Union[ - None, - DataFrameLikeT, - "DataGrid[DataFrameLikeT]", - "DataTable[DataFrameLikeT]", -] -DataFrameValue = Union[None, DataGrid[DataFrameLikeT], DataTable[DataFrameLikeT]] - @add_example() -class data_frame(Renderer[DataFrameResult[DataFrameLikeT]]): +class data_frame( + Renderer[ + None | IntoDataFrameT | DataGrid[IntoDataFrameT] | DataTable[IntoDataFrameT] + ] +): """ Decorator for a function that returns a [pandas](https://pandas.pydata.org/) or [polars](https://pola.rs/) `DataFrame` object to render as an interactive table or @@ -138,7 +135,11 @@ class data_frame(Renderer[DataFrameResult[DataFrameLikeT]]): objects you can return from the rendering function to specify options. """ - _value: reactive.Value[DataFrameValue[DataFrameLikeT] | None] + _value: reactive.Value[None | DataGrid[IntoDataFrameT] | DataTable[IntoDataFrameT]] + """ + Reactive value of the data frame's rendered object. + """ + _value_data: reactive.Calc_[IntoDataFrameT] """ Reactive value of the data frame's rendered object. """ @@ -181,7 +182,7 @@ class data_frame(Renderer[DataFrameResult[DataFrameLikeT]]): Reactive value of the data frame's edits provided by the user. """ - data: reactive.Calc_[DataFrameLikeT] + data: reactive.Calc_[IntoDataFrameT] """ Reactive value of the data frame's output data. @@ -192,17 +193,17 @@ class data_frame(Renderer[DataFrameResult[DataFrameLikeT]]): Even if the rendered data value was not of type `pd.DataFrame` or `pl.DataFrame`, this method currently converts it to a `pd.DataFrame`. """ - _data_view_all: reactive.Calc_[DataFrameLikeT] + _data_view_all: reactive.Calc_[IntoDataFrameT] """ Reactive value of the full (sorted and filtered) data. """ - _data_view_selected: reactive.Calc_[DataFrameLikeT] + _data_view_selected: reactive.Calc_[IntoDataFrameT] """ Reactive value of the selected rows of the (sorted and filtered) data. """ @add_example(ex_dir="../api-examples/data_frame_data_view") - def data_view(self, *, selected: bool = False) -> DataFrameLikeT: + def data_view(self, *, selected: bool = False) -> IntoDataFrameT: """ Reactive function that retrieves the data how it is viewed within the browser. @@ -274,7 +275,7 @@ def data_view(self, *, selected: bool = False) -> DataFrameLikeT: after sorting and filtering has been applied. """ - _data_patched: reactive.Calc_[DataFrameLikeT] + _data_patched: reactive.Calc_[DataFrame[IntoDataFrameT]] """ Reactive value of the data frame's patched data. @@ -314,9 +315,9 @@ def _init_reactives(self) -> None: from .. import req # Init - self._value: reactive.Value[DataFrameValue[DataFrameLikeT] | None] = ( - reactive.Value(None) - ) + self._value: reactive.Value[ + None | DataGrid[IntoDataFrameT] | DataTable[IntoDataFrameT] + ] = reactive.Value(None) self._type_hints: reactive.Value[list[FrameDtype] | None] = reactive.Value(None) self._cell_patch_map = reactive.Value({}) @@ -327,17 +328,47 @@ def self_cell_patches() -> list[CellPatch]: self.cell_patches = self_cell_patches @reactive.calc - def self_data() -> DataFrameLikeT: + def self__value_data() -> IntoDataFrameT: value = self._value() - req(value) - - if not isinstance(value, (DataGrid, DataTable)): - raise TypeError( - f"Unsupported type returned from render function: {type(value)}. Expected `DataGrid` or `DataTable`" - ) + if not value: + req(False) + raise RuntimeError("req() failed to raise a silent error.") return value.data + self._value_data = self__value_data + + @reactive.calc + def self__nw_data() -> DataFrame[IntoDataFrameT]: + return as_data_frame(self._value_data()) + + self._nw_data = self__nw_data + + @reactive.calc + def self__data_is_nw() -> bool: + return isinstance(self._value_data(), DataFrame) + + self._data_is_nw = self__data_is_nw + + # @overload + # def + @reactive.calc + def self__nw_data_to_original_type_fn(): + + def _(nw_data: DataFrame[IntoDataFrameT]) -> IntoDataFrameT: + if self._data_is_nw(): + # At this point, `IntoDataFrameT` represents `DataFrame[IntoDataFrameT]` + return cast(IntoDataFrameT, nw_data) + return data_frame_to_native(nw_data) + + return _ + + self._nw_data_to_original_type_fn = self__nw_data_to_original_type_fn + + @reactive.calc + def self_data() -> IntoDataFrameT: + return data_frame_to_native(self._nw_data()) + self.data = self_data @reactive.calc @@ -363,11 +394,11 @@ def self_cell_selection() -> CellSelection: cell_selection = as_cell_selection( browser_cell_selection, selection_modes=self.selection_modes(), - data=self.data(), + nw_data=self._nw_data(), data_view_rows=self.data_view_rows(), # TODO-barret: replace methods like .shape, .loc. .iat with those from # _tbl_data.py, test in the playright app. - data_view_cols=tuple(range(frame_shape(self.data())[1])), + data_view_cols=tuple(range(frame_shape(self._nw_data())[1])), ) return cell_selection @@ -400,14 +431,14 @@ def self_data_view_rows() -> tuple[int, ...]: self.data_view_rows = self_data_view_rows @reactive.calc - def self__data_patched() -> DataFrameLikeT: - return apply_frame_patches__typed(self.data(), self.cell_patches()) + def self__data_patched() -> DataFrame[IntoDataFrameT]: + return apply_frame_patches(self._nw_data(), self.cell_patches()) self._data_patched = self__data_patched # Apply filtering and sorting # https://github.com/posit-dev/py-shiny/issues/1240 - def _subset_data_view(selected: bool) -> DataFrameLikeT: + def _subset_data_view(selected: bool) -> IntoDataFrameT: """ Helper method to subset data according to what is viewed in the browser; @@ -431,15 +462,20 @@ def _subset_data_view(selected: bool) -> DataFrameLikeT: else: rows = self.data_view_rows() - return subset_frame__typed(self._data_patched(), rows=rows) + nw_data = subset_frame(self._data_patched(), rows=rows) + + to_original_type = self._nw_data_to_original_type_fn() + patched_subsetted_into_data = to_original_type(nw_data) + + return patched_subsetted_into_data # Helper reactives so that internal calculations can be cached for use in other calculations @reactive.calc - def self__data_view() -> DataFrameLikeT: + def self__data_view() -> IntoDataFrameT: return _subset_data_view(selected=False) @reactive.calc - def self__data_view_selected() -> DataFrameLikeT: + def self__data_view_selected() -> IntoDataFrameT: return _subset_data_view(selected=True) self._data_view_all = self__data_view @@ -677,7 +713,10 @@ async def _attempt_update_cell_style(self) -> None: if not callable(styles_fn): return - new_styles = as_browser_style_infos(styles_fn, data=self._data_patched()) + # TODO-barret; Use the returned data type from the rener function! + to_original_type = self._nw_data_to_original_type_fn() + patched_into_data = to_original_type(self._data_patched()) + new_styles = as_browser_style_infos(styles_fn, into_data=patched_into_data) await self._send_message_to_browser( "updateStyles", @@ -709,7 +748,12 @@ async def _attempt_update_cell_style(self) -> None: def auto_output_ui(self) -> Tag: return ui.output_data_frame(id=self.output_id) - def __init__(self, fn: ValueFn[DataFrameResult[DataFrameLikeT]]): + def __init__( + self, + fn: ValueFn[ + None | IntoDataFrameT | DataGrid[IntoDataFrameT] | DataTable[IntoDataFrameT] + ], + ): super().__init__(fn) # Set reactives from calculated properties @@ -756,6 +800,11 @@ async def render(self) -> JsonifiableDict | None: # Set patches url handler for client patch_key = self._set_patches_handler() + + if not isinstance(value, (DataGrid, DataTable)): + raise TypeError( + f"Unsupported type returned from render function: {type(value)}. Expected `DataGrid` or `DataTable`" + ) self._value.set(value) # pyright: ignore[reportArgumentType] # Use session context so `to_payload()` gets the correct session @@ -810,9 +859,9 @@ async def update_cell_selection( """ with reactive.isolate(): selection_modes = self.selection_modes() - data = self.data() + nw_data = self._nw_data() data_view_rows = self.data_view_rows() - data_view_cols = tuple(range(data.shape[1])) + data_view_cols = tuple(range(nw_data.shape[1])) if selection_modes._is_none(): warnings.warn( @@ -828,7 +877,7 @@ async def update_cell_selection( cell_selection = as_cell_selection( selection, selection_modes=selection_modes, - data=data, + nw_data=nw_data, data_view_rows=data_view_rows, data_view_cols=data_view_cols, ) @@ -886,14 +935,15 @@ async def update_sort( vals: list[ColumnSort] = [] if len(sort) > 0: with reactive.isolate(): - data = self.data() - ncol = frame_shape(data)[1] + nw_data = self._nw_data() + ncol = frame_shape(nw_data)[1] for val in sort: val_dict: ColumnSort if isinstance(val, int): - col = frame_columns(data)[val] - desc = serialize_dtype(col)["type"] == "numeric" + # col = frame_columns(data)[val] + # desc = serialize_dtype(col)["type"] == "numeric" + desc = nw_data[:, val].dtype.is_numeric() val_dict = {"col": val, "desc": desc} val_dict: ColumnSort = ( val if isinstance(val, dict) else {"col": val, "desc": True} @@ -929,8 +979,8 @@ async def update_filter( filter = [] else: with reactive.isolate(): - data = self.data() - ncol = len(data.columns) + shape = frame_shape(self._nw_data()) + ncol = shape[1] for column_filter, i in zip(filter, range(len(filter))): assert isinstance(column_filter, dict) diff --git a/shiny/render/_data_frame_utils/_tbl_data.py b/shiny/render/_data_frame_utils/_tbl_data.py index 9c058eab8..da0223603 100644 --- a/shiny/render/_data_frame_utils/_tbl_data.py +++ b/shiny/render/_data_frame_utils/_tbl_data.py @@ -62,7 +62,7 @@ def as_data_frame( except TypeError as e: try: return nw.from_native(compatible_to_pandas(data), eager_only=True) - except BaseException: + except TypeError: # Couldn't convert to pandas, so raise the original error raise e diff --git a/shiny/render/_data_frame_utils/_types.py b/shiny/render/_data_frame_utils/_types.py index b3d3d8506..d2273ee31 100644 --- a/shiny/render/_data_frame_utils/_types.py +++ b/shiny/render/_data_frame_utils/_types.py @@ -7,7 +7,6 @@ TYPE_CHECKING, Any, Dict, - List, Literal, Optional, Protocol, From 32fe46646cf620037d24fc0fd3dfe520b2c39877 Mon Sep 17 00:00:00 2001 From: Barret Schloerke Date: Mon, 16 Sep 2024 17:12:52 -0400 Subject: [PATCH 20/87] Update typing --- .../shiny/components/data_frame/data_view_info/app.py | 5 ++++- .../shiny/components/data_frame/df_methods/app.py | 2 +- .../shiny/components/data_frame/row_selection/app.py | 7 +++++-- tests/playwright/shiny/components/data_frame/styles/app.py | 4 ++-- .../components/data_frame/validate_column_labels/app.py | 2 +- 5 files changed, 13 insertions(+), 7 deletions(-) diff --git a/tests/playwright/shiny/components/data_frame/data_view_info/app.py b/tests/playwright/shiny/components/data_frame/data_view_info/app.py index 88790e591..624d85278 100644 --- a/tests/playwright/shiny/components/data_frame/data_view_info/app.py +++ b/tests/playwright/shiny/components/data_frame/data_view_info/app.py @@ -52,7 +52,10 @@ def mod_ui(): @module.server def mod_server( - input: Inputs, output: Outputs, session: Session, dt: render._DataFrameLikeT + input: Inputs, + output: Outputs, + session: Session, + dt: render.IntoDataFrame, ): @render.data_frame def penguins_df(): diff --git a/tests/playwright/shiny/components/data_frame/df_methods/app.py b/tests/playwright/shiny/components/data_frame/df_methods/app.py index 4cf702031..665d3f51b 100644 --- a/tests/playwright/shiny/components/data_frame/df_methods/app.py +++ b/tests/playwright/shiny/components/data_frame/df_methods/app.py @@ -45,7 +45,7 @@ def mod_server( input: Inputs, output: Outputs, session: Session, - data: render._DataFrameLikeT, + data: render.IntoDataFrame, ): @render.text def df_type(): diff --git a/tests/playwright/shiny/components/data_frame/row_selection/app.py b/tests/playwright/shiny/components/data_frame/row_selection/app.py index 01307468c..dccc6396f 100644 --- a/tests/playwright/shiny/components/data_frame/row_selection/app.py +++ b/tests/playwright/shiny/components/data_frame/row_selection/app.py @@ -41,7 +41,7 @@ def make_ui(title: str): ) -def make_server(input: Inputs, data: render._DataFrameLikeT): +def make_server(input: Inputs, data: render.IntoDataFrame): @render.data_frame def grid(): return render.DataGrid( @@ -100,7 +100,10 @@ def mod_ui(title: str = "Module"): @module.server def mod_server( - input: Inputs, output: Outputs, session: Session, data: render._DataFrameLikeT + input: Inputs, + output: Outputs, + session: Session, + data: render.IntoDataFrame, ): make_server(input, data) diff --git a/tests/playwright/shiny/components/data_frame/styles/app.py b/tests/playwright/shiny/components/data_frame/styles/app.py index cf242c981..361690b3d 100644 --- a/tests/playwright/shiny/components/data_frame/styles/app.py +++ b/tests/playwright/shiny/components/data_frame/styles/app.py @@ -110,7 +110,7 @@ def mod_server( input: Inputs, output: Outputs, session: Session, - data: render._DataFrameLikeT, + data: render.IntoDataFrame, ): @render.data_frame def fn_styles(): @@ -118,7 +118,7 @@ def fn_styles(): counter = 0 def df_styles_fn( - data: render._DataFrameLikeT, + data: render.IntoDataFrame, ) -> list[render.StyleInfo]: nonlocal counter diff --git a/tests/playwright/shiny/components/data_frame/validate_column_labels/app.py b/tests/playwright/shiny/components/data_frame/validate_column_labels/app.py index f49ecb618..50753200b 100644 --- a/tests/playwright/shiny/components/data_frame/validate_column_labels/app.py +++ b/tests/playwright/shiny/components/data_frame/validate_column_labels/app.py @@ -22,7 +22,7 @@ def df_mod( output: Outputs, session: Session, name: str, - data: render._DataFrameLikeT, + data: render.IntoDataFrame, ): ui.hr() From 00088beac24f9015c384f271b675ae03ed23d8dc Mon Sep 17 00:00:00 2001 From: Barret Schloerke Date: Mon, 16 Sep 2024 17:13:14 -0400 Subject: [PATCH 21/87] Update tests to handle the new types --- tests/pytest/test_render_data_frame.py | 18 ++--- .../pytest/test_render_data_frame_tbl_data.py | 66 ++++++++----------- 2 files changed, 32 insertions(+), 52 deletions(-) diff --git a/tests/pytest/test_render_data_frame.py b/tests/pytest/test_render_data_frame.py index 8c17fda13..1e3557ff4 100644 --- a/tests/pytest/test_render_data_frame.py +++ b/tests/pytest/test_render_data_frame.py @@ -4,6 +4,7 @@ from shiny import render from shiny._deprecated import ShinyDeprecationWarning from shiny.render._data_frame_utils._selection import SelectionModes +from shiny.render._data_frame_utils._tbl_data import as_data_frame def test_data_frame_needs_unique_col_names(): @@ -11,20 +12,9 @@ def test_data_frame_needs_unique_col_names(): df = pd.DataFrame(data={"a": [1, 2]}) df.insert(1, "a", [3, 4], True) # pyright: ignore - data_grid = render.DataGrid(df) - data_table = render.DataTable(df) - - with pytest.raises( - ValueError, - match="column names of the pandas DataFrame are not unique", - ): - data_grid.to_payload() - - with pytest.raises( - ValueError, - match="column names of the pandas DataFrame are not unique", - ): - data_table.to_payload() + with pytest.raises(ValueError) as e: + as_data_frame(df) + assert "Expected unique column names" in str(e.value) def test_as_selection_modes_legacy(): diff --git a/tests/pytest/test_render_data_frame_tbl_data.py b/tests/pytest/test_render_data_frame_tbl_data.py index 64d1787f6..6aacd21b9 100644 --- a/tests/pytest/test_render_data_frame_tbl_data.py +++ b/tests/pytest/test_render_data_frame_tbl_data.py @@ -11,18 +11,14 @@ import pytest from shiny.render._data_frame_utils._tbl_data import ( + as_data_frame, copy_frame, frame_shape, - get_frame_cell, serialize_dtype, serialize_frame, subset_frame, ) -from shiny.render._data_frame_utils._types import ( - DataFrameLike, - DataFrameLikeT, - SeriesLike, -) +from shiny.render._data_frame_utils._types import IntoDataFrame, SeriesLike from shiny.ui import HTML, h1 @@ -60,10 +56,6 @@ def polars_dict_to_narwhals(d: dict[str, Any]) -> nw.DataFrame[pl.DataFrame]: return nw.from_native(pl.DataFrame(d), eager_only=True) -def df_to_narwhals(df: DataFrameLikeT) -> nw.DataFrame[DataFrameLikeT]: - return nw.from_native(df, eager_only=True) - - def series_to_narwhals(ser: SeriesLike) -> nw.Series: return nw.from_native(ser, series_only=True, strict=True) @@ -76,12 +68,12 @@ def series_to_narwhals(ser: SeriesLike) -> nw.Series: @pytest.fixture(params=params_frames, scope="function") -def df_f(request: pytest.FixtureRequest) -> DataFrameLike: +def df_f(request: pytest.FixtureRequest) -> IntoDataFrame: return request.param(DATA) @pytest.fixture(params=params_frames, scope="function") -def small_df_f(request: pytest.FixtureRequest) -> DataFrameLike: +def small_df_f(request: pytest.FixtureRequest) -> IntoDataFrame: return request.param({"x": [1, 2], "y": [3, 4]}) @@ -107,14 +99,14 @@ def assert_frame_equal( def assert_frame_equal2( - src: pd.DataFrame | pl.DataFrame, + src: IntoDataFrame, target_dict: dict[str, Any], use_index: bool = False, ): - src = nw.to_native(src, strict=False) - target = nw.to_native(src, strict=False).__class__(target_dict) + src_native = nw.to_native(src, strict=False) + target_native = nw.to_native(src, strict=False).__class__(target_dict) - assert_frame_equal(src, target, use_index) + assert_frame_equal(src_native, target_native, use_index) # TODO: explicitly pass dtype= when doing Series construction @@ -138,7 +130,7 @@ def assert_frame_equal2( (pd.Series([datetime.now()], dtype="datetime64[ns]"), "datetime"), # (pd.Series([pd.Timedelta(days=1)]), "timedelta"), (pd.Series(["a"], dtype="category"), "categorical"), - (pd.Series([{"x": 1}]), "unknown"), + (pd.Series([{"x": 1}]), "object"), (pd.Series([h1("yo")]), "html"), (pd.Series([HTML("yo")]), "html"), ], @@ -150,17 +142,15 @@ def test_serialize_dtype( ], res_type: str, ): - if isinstance(ser, pl.Series): - nw_ser = series_to_narwhals(ser) - assert serialize_dtype(nw_ser)["type"] == res_type - # assert serialize_dtype(ser)["type"] == res_type + nw_ser = series_to_narwhals(ser) + assert serialize_dtype(nw_ser)["type"] == res_type -def test_serialize_frame(df_f: DataFrameLike): - if not isinstance(df_f, pl.DataFrame): - pytest.skip() +def test_serialize_frame(df_f: IntoDataFrame): + # if not isinstance(df_f, pl.DataFrame): + # pytest.skip() - df_nw = df_to_narwhals(df_f) + df_nw = as_data_frame(df_f) # # TODO: pandas converts datetime entries to int, but Polars # # preserves the datetime object. @@ -180,33 +170,33 @@ def test_serialize_frame(df_f: DataFrameLike): {"type": "string"}, {"type": "string"}, {"type": "datetime"}, - {"type": "unknown"}, - {"type": "unknown"}, + {"type": "object" if (isinstance(df_f, pd.DataFrame)) else "unknown"}, + {"type": "object" if (isinstance(df_f, pd.DataFrame)) else "unknown"}, {"type": "object"}, ], } -def test_subset_frame(df_f: DataFrameLike): +def test_subset_frame(df_f: IntoDataFrame): # TODO: this assumes subset_frame doesn't reset index - res = subset_frame(df_f, rows=[1], cols=["chr", "num"]) + res = subset_frame(as_data_frame(df_f), rows=[1], cols=["chr", "num"]) dst = {"chr": ["b"], "num": [2]} assert_frame_equal2(res, dst) -def test_get_frame_cell(df_f: DataFrameLike): - assert get_frame_cell(df_f, 1, 1) == "b" +# def test_get_frame_cell(df_f: IntoDataFrameT): +# assert get_frame_cell(df_f, 1, 1) == "b" -def test_copy_frame(df_f: DataFrameLike): - new_df = copy_frame(df_f) +def test_copy_frame(df_f: IntoDataFrame): + new_df = copy_frame(as_data_frame(df_f)) assert new_df is not df_f -def test_subset_frame_rows_single(small_df_f: DataFrameLike): - res = subset_frame(small_df_f, rows=[1]) +def test_subset_frame_rows_single(small_df_f: IntoDataFrame): + res = subset_frame(as_data_frame(small_df_f), rows=[1]) assert_frame_equal2( res, @@ -214,9 +204,9 @@ def test_subset_frame_rows_single(small_df_f: DataFrameLike): ) -def test_subset_frame_cols_single(small_df_f: DataFrameLike): +def test_subset_frame_cols_single(small_df_f: IntoDataFrame): # TODO: include test of polars - res = subset_frame(small_df_f, cols=["y"]) + res = subset_frame(as_data_frame(small_df_f), cols=["y"]) assert_frame_equal2( res, @@ -224,5 +214,5 @@ def test_subset_frame_cols_single(small_df_f: DataFrameLike): ) -def test_shape(small_df_f: DataFrameLike): +def test_shape(small_df_f: IntoDataFrame): assert frame_shape(small_df_f) == (2, 2) From cf6b283c056db701c4c6da5c889c1b2379b99d22 Mon Sep 17 00:00:00 2001 From: Barret Schloerke Date: Mon, 16 Sep 2024 17:13:31 -0400 Subject: [PATCH 22/87] Fix port test to be more robust --- tests/pytest/test_utils.py | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/tests/pytest/test_utils.py b/tests/pytest/test_utils.py index ac99d4ab6..c6fd8d9ce 100644 --- a/tests/pytest/test_utils.py +++ b/tests/pytest/test_utils.py @@ -141,7 +141,6 @@ async def mutate_registrations(): @pytest.mark.timeout(2) @pytest.mark.flaky(reruns=3) def test_random_port(): - assert random_port(9000, 9000) == 9000 # Starting port port = 9001 @@ -150,6 +149,19 @@ def test_random_port(): # Number of times to try to find a port range n = 100 + # Make sure a single port can be found + attempts = 0 + for _ in range(n): + port_i = port - 1000 + attempts + attempts += 1 + try: + assert random_port(port_i, port_i) == port_i + break + except RuntimeError as e: + print(e) + if attempts == n: + raise RuntimeError(f"Could not find a usable port in {n} tries") + # Find a range of `num_ports` ports that are all available attempts = 0 for _ in range(n): From 9cf92d3ba39c78bd0a735ab78493999239ac8dfb Mon Sep 17 00:00:00 2001 From: Barret Schloerke Date: Tue, 17 Sep 2024 13:48:10 -0400 Subject: [PATCH 23/87] Add quick short circuit --- shiny/render/_data_frame_utils/_tbl_data.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/shiny/render/_data_frame_utils/_tbl_data.py b/shiny/render/_data_frame_utils/_tbl_data.py index da0223603..b214134af 100644 --- a/shiny/render/_data_frame_utils/_tbl_data.py +++ b/shiny/render/_data_frame_utils/_tbl_data.py @@ -189,6 +189,9 @@ def apply_frame_patches( ) -> DataFrame[IntoDataFrameT]: # data = data.clone() + if len(patches) == 0: + return nw_data + # Us an index to know which row we are updating data_with_index = nw_data.with_row_index() From cfb5ac7695dcb17cc0b4f9aa9bc7f1b5d451ca73 Mon Sep 17 00:00:00 2001 From: Barret Schloerke Date: Tue, 17 Sep 2024 13:48:32 -0400 Subject: [PATCH 24/87] Add TODO with hint from Marco --- shiny/render/_data_frame_utils/_tbl_data.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/shiny/render/_data_frame_utils/_tbl_data.py b/shiny/render/_data_frame_utils/_tbl_data.py index b214134af..a7cd0aa46 100644 --- a/shiny/render/_data_frame_utils/_tbl_data.py +++ b/shiny/render/_data_frame_utils/_tbl_data.py @@ -342,16 +342,18 @@ def _(col: nw.Series) -> FrameDtype: categories = col.cat.get_categories().to_list() return {"type": "categorical", "categories": categories} elif dtype == nw_enum: - raise NotImplementedError("enum type not tested") + raise NotImplementedError("TODO-barret; enum type not tested") cat_col = col.cast(nw.Categorical) categories = cat_col.cat.get_categories().to_list() return {"type": "categorical", "categories": categories} elif dtype == nw_boolean: - raise NotImplementedError("boolean type not tested") + raise NotImplementedError("TODO-barret; boolean type not tested") type_ = "boolean" elif dtype == nw_duration: - raise NotImplementedError("duration type not tested") + raise NotImplementedError( + "TODO-barret; duration type not tested. Look at pandas timedelta" + ) type_ = "duration" elif dtype == nw_datetime: type_ = "datetime" From aa0d8dd43948121e36c0a93ebfd5cda8a096e468 Mon Sep 17 00:00:00 2001 From: Barret Schloerke Date: Tue, 17 Sep 2024 13:48:47 -0400 Subject: [PATCH 25/87] Fix html column bug --- shiny/render/_data_frame_utils/_tbl_data.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shiny/render/_data_frame_utils/_tbl_data.py b/shiny/render/_data_frame_utils/_tbl_data.py index a7cd0aa46..e23641929 100644 --- a/shiny/render/_data_frame_utils/_tbl_data.py +++ b/shiny/render/_data_frame_utils/_tbl_data.py @@ -431,7 +431,7 @@ def serialize_frame(into_data: IntoDataFrame) -> FrameJson: data = as_data_frame(into_data) type_hints = [serialize_dtype(data[col_name]) for col_name in data.columns] - type_hints_type = {type_hint["type"] for type_hint in type_hints} + type_hints_type = (type_hint["type"] for type_hint in type_hints) data_rows = data.rows(named=False) From 8b88353d4f2ceec7947edbabc1e1fd5026af0042 Mon Sep 17 00:00:00 2001 From: Barret Schloerke Date: Tue, 17 Sep 2024 16:57:14 -0400 Subject: [PATCH 26/87] Fix narwhals subset bugs --- shiny/render/_data_frame_utils/_tbl_data.py | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/shiny/render/_data_frame_utils/_tbl_data.py b/shiny/render/_data_frame_utils/_tbl_data.py index e23641929..812dfb683 100644 --- a/shiny/render/_data_frame_utils/_tbl_data.py +++ b/shiny/render/_data_frame_utils/_tbl_data.py @@ -519,14 +519,26 @@ def subset_frame( return data else: # This feels like it should be `data[rows, :]` but that doesn't work for polars - return data[rows] + # https://github.com/narwhals-dev/narwhals/issues/989 + # Must use `list(rows)` as tuples are not supported + # https://github.com/narwhals-dev/narwhals/issues/990 + return data[list(rows), data.columns] else: # `cols` is not None col_names = [data.columns[col] if isinstance(col, int) else col for col in cols] + # If len(cols) == 0, then we should return an empty DataFrame + # Currently this is broken when backed by pandas. + # https://github.com/narwhals-dev/narwhals/issues/989 + if len(col_names) == 0: + # Return a DataFrame with no rows or columns + # If there are no columns, there are no Series objects to support any rows + return data[[], []] + if rows is None: return data[:, col_names] else: - return data[rows, col_names] + # Be sure rows is a list, not a tuple. Tuple + return data[list(rows), col_names] # @subset_frame.register @@ -686,9 +698,6 @@ def frame_column_names(into_data: IntoDataFrame) -> List[str]: return as_data_frame(into_data).columns -nw.narwhalify - - class ScatterValues(TypedDict): row_indexes: list[int] values: list[CellValue] From cf5a8453890df781f67c8635bea27102724148a6 Mon Sep 17 00:00:00 2001 From: Barret Schloerke Date: Tue, 17 Sep 2024 16:58:19 -0400 Subject: [PATCH 27/87] Do not convert data early --- shiny/render/_data_frame_utils/_datagridtable.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/shiny/render/_data_frame_utils/_datagridtable.py b/shiny/render/_data_frame_utils/_datagridtable.py index 86c652f79..42812d6f7 100644 --- a/shiny/render/_data_frame_utils/_datagridtable.py +++ b/shiny/render/_data_frame_utils/_datagridtable.py @@ -11,7 +11,7 @@ as_selection_modes, ) from ._styles import StyleFn, StyleInfo, as_browser_style_infos, as_style_infos -from ._tbl_data import compatible_to_pandas, serialize_frame +from ._tbl_data import serialize_frame from ._types import FrameJson, IntoDataFrameT @@ -298,7 +298,7 @@ def __init__( styles: StyleInfo | list[StyleInfo] | StyleFn[IntoDataFrameT] | None = None, row_selection_mode: Literal["deprecated"] = "deprecated", ): - self.data = compatible_to_pandas(data) + self.data = data self.width = width self.height = height From 08e70ad66c50a02996430fb6f016d1cee080addf Mon Sep 17 00:00:00 2001 From: Barret Schloerke Date: Tue, 17 Sep 2024 16:58:56 -0400 Subject: [PATCH 28/87] Update _data_frame.py --- shiny/render/_data_frame.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/shiny/render/_data_frame.py b/shiny/render/_data_frame.py index a37a20e72..a85fb385a 100644 --- a/shiny/render/_data_frame.py +++ b/shiny/render/_data_frame.py @@ -464,8 +464,8 @@ def _subset_data_view(selected: bool) -> IntoDataFrameT: nw_data = subset_frame(self._data_patched(), rows=rows) - to_original_type = self._nw_data_to_original_type_fn() - patched_subsetted_into_data = to_original_type(nw_data) + to_original_type_fn = self._nw_data_to_original_type_fn() + patched_subsetted_into_data = to_original_type_fn(nw_data) return patched_subsetted_into_data @@ -714,8 +714,8 @@ async def _attempt_update_cell_style(self) -> None: return # TODO-barret; Use the returned data type from the rener function! - to_original_type = self._nw_data_to_original_type_fn() - patched_into_data = to_original_type(self._data_patched()) + to_original_type_fn = self._nw_data_to_original_type_fn() + patched_into_data = to_original_type_fn(self._data_patched()) new_styles = as_browser_style_infos(styles_fn, into_data=patched_into_data) await self._send_message_to_browser( From 3b4be829215d10a3e5f223a6cdbd867ca68ae5ff Mon Sep 17 00:00:00 2001 From: Barret Schloerke Date: Tue, 17 Sep 2024 17:17:23 -0400 Subject: [PATCH 29/87] Fix another html column issue --- shiny/render/_data_frame_utils/_tbl_data.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/shiny/render/_data_frame_utils/_tbl_data.py b/shiny/render/_data_frame_utils/_tbl_data.py index 812dfb683..7abf6265f 100644 --- a/shiny/render/_data_frame_utils/_tbl_data.py +++ b/shiny/render/_data_frame_utils/_tbl_data.py @@ -431,7 +431,7 @@ def serialize_frame(into_data: IntoDataFrame) -> FrameJson: data = as_data_frame(into_data) type_hints = [serialize_dtype(data[col_name]) for col_name in data.columns] - type_hints_type = (type_hint["type"] for type_hint in type_hints) + type_hints_type = [type_hint["type"] for type_hint in type_hints] data_rows = data.rows(named=False) @@ -511,6 +511,7 @@ def subset_frame( Note that when None is passed, all rows or columns get included. """ + # Note that this type signature assumes column names are strings things. # This is always true in Polars, but not in Pandas (e.g. a column name could be an # int, or even a tuple of ints) From 1f8c9c66cc0a1f5bae444504f68e89706239cbb5 Mon Sep 17 00:00:00 2001 From: Barret Schloerke Date: Wed, 18 Sep 2024 09:39:56 -0400 Subject: [PATCH 30/87] lint --- shiny/render/_data_frame.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/shiny/render/_data_frame.py b/shiny/render/_data_frame.py index a85fb385a..be66d4f7a 100644 --- a/shiny/render/_data_frame.py +++ b/shiny/render/_data_frame.py @@ -4,7 +4,7 @@ # TODO-barret-render.data_frame; Docs # TODO-barret-render.data_frame; Add examples! -from typing import TYPE_CHECKING, Any, Awaitable, Callable, Literal, cast +from typing import TYPE_CHECKING, Any, Awaitable, Callable, Literal, Union, cast from htmltools import Tag @@ -60,7 +60,7 @@ @add_example() class data_frame( Renderer[ - None | IntoDataFrameT | DataGrid[IntoDataFrameT] | DataTable[IntoDataFrameT] + Union[None, IntoDataFrameT, DataGrid[IntoDataFrameT], DataTable[IntoDataFrameT]] ] ): """ From 627388551832a5b3985eea2899bc00cfe2b15bc7 Mon Sep 17 00:00:00 2001 From: Barret Schloerke Date: Wed, 18 Sep 2024 11:38:41 -0400 Subject: [PATCH 31/87] Update tests for narwhals. Note: py-htmltools is holding up PR's tests as HTML type needs to inherit from UserString --- shiny/render/_data_frame_utils/_tbl_data.py | 17 ++- .../pytest/test_render_data_frame_tbl_data.py | 110 +++++++++++++++--- 2 files changed, 101 insertions(+), 26 deletions(-) diff --git a/shiny/render/_data_frame_utils/_tbl_data.py b/shiny/render/_data_frame_utils/_tbl_data.py index 7abf6265f..7aa712e75 100644 --- a/shiny/render/_data_frame_utils/_tbl_data.py +++ b/shiny/render/_data_frame_utils/_tbl_data.py @@ -272,9 +272,9 @@ def apply_frame_patches( # serialize_dtype ---------------------------------------------------------------------- -@singledispatch -def serialize_dtype(col: SeriesLike) -> FrameDtype: - raise TypeError(f"Unsupported type: {type(col)}") +# @singledispatch +# def serialize_dtype(col: SeriesLike) -> FrameDtype: +# raise TypeError(f"Unsupported type: {type(col)}") # TODO: we can't import DataFrameDtype at runtime, due to circular dependency. So @@ -323,8 +323,9 @@ def serialize_dtype(col: SeriesLike) -> FrameDtype: nw_object = nw.Object() -@serialize_dtype.register -def _(col: nw.Series) -> FrameDtype: +# @serialize_dtype.register +# def _(col: nw.Series) -> FrameDtype: +def serialize_dtype(col: nw.Series) -> FrameDtype: from ._html import col_contains_shiny_html @@ -435,9 +436,6 @@ def serialize_frame(into_data: IntoDataFrame) -> FrameJson: data_rows = data.rows(named=False) - # print(data_rows) - # print(data.rows(named=False)) - # Shiny tag support if "html" in type_hints_type: session = require_active_session(None) @@ -467,10 +465,11 @@ def wrap_shiny_html_with_session(x: TagNode): # TODO-barret; Remove debug! Maybe? native_data = nw.to_native(data) if isinstance(native_data, PdDataFrame): + # print("types:", type_hints_type, type_hints) from pandas import Timestamp def my_str(x: Any) -> str: - print("x", x) + # print("barret-pandas value!", x) if isinstance(x, Timestamp): return x.isoformat() diff --git a/tests/pytest/test_render_data_frame_tbl_data.py b/tests/pytest/test_render_data_frame_tbl_data.py index 6aacd21b9..d03ab31c3 100644 --- a/tests/pytest/test_render_data_frame_tbl_data.py +++ b/tests/pytest/test_render_data_frame_tbl_data.py @@ -2,7 +2,7 @@ from dataclasses import dataclass from datetime import datetime -from typing import Any, Union +from typing import Any, Union, cast import narwhals.stable.v1 as nw import pandas as pd @@ -19,7 +19,27 @@ subset_frame, ) from shiny.render._data_frame_utils._types import IntoDataFrame, SeriesLike -from shiny.ui import HTML, h1 +from shiny.session import Session, session_context +from shiny.session._session import RenderedDeps, ResolvedId, Root +from shiny.ui import HTML, TagChild, TagList, h1, span + + +class _MockSession: + ns: ResolvedId = Root + + # Simplified version of `AppSession._process_ui()` + def _process_ui(self, ui: TagChild) -> RenderedDeps: + res = TagList(ui).render() + deps: list[dict[str, Any]] = [] + # for dep in res["dependencies"]: + # self.app._register_web_dependency(dep) + # dep_dict = dep.as_dict(lib_prefix=self.app.lib_prefix) + # deps.append(dep_dict) + + return {"deps": deps, "html": res["html"]} + + +test_session = cast(Session, _MockSession()) class C: @@ -42,16 +62,19 @@ class D: "chr": ["a", "b"], "cat": ["a", "a"], "dt": [datetime(2000, 1, 2)] * 2, - # TODO: mock session in tests (needed for registering dependencies) - # "html": [htmltools.span("span content")] * 2, - # "html_str": [htmltools.HTML("bolded")] * 2, - # TODO: ts code to stringify objects + "html": [span("span content")] * 2, + "html_str": [HTML("bolded")] * 2, + # TODO-barret: ts code to stringify objects? "struct": [{"x": 1}, {"x": 2}], "arr": [[1, 2], [3, 4]], "object": [C(1), D(2)], } +def pandas_dict_to_narwhals(d: dict[str, Any]) -> nw.DataFrame[pd.DataFrame]: + return nw.from_native(pd.DataFrame(d), eager_only=True) + + def polars_dict_to_narwhals(d: dict[str, Any]) -> nw.DataFrame[pl.DataFrame]: return nw.from_native(pl.DataFrame(d), eager_only=True) @@ -63,7 +86,8 @@ def series_to_narwhals(ser: SeriesLike) -> nw.Series: params_frames = [ pytest.param(pd.DataFrame, id="pandas"), pytest.param(pl.DataFrame, id="polars"), - pytest.param(polars_dict_to_narwhals, id="narwhals"), + pytest.param(pandas_dict_to_narwhals, id="narwhals-pandas"), + pytest.param(polars_dict_to_narwhals, id="narwhals-polars"), ] @@ -121,7 +145,8 @@ def assert_frame_equal2( (pl.Series(["a"], dtype=pl.Categorical), "categorical"), (pl.Series([{"x": 1}]), "unknown"), (pl.Series([h1("yo")]), "html"), - pytest.param(pl.Series([HTML("yo")]), "html", marks=pytest.mark.xfail), + # TODO-barret; Need https://github.com/posit-dev/py-htmltools/pull/86 to be merged to remove custom dtype + (pl.Series([HTML("yo")], dtype=pl.Object), "html"), # pandas ---- (pd.Series([1]), "numeric"), (pd.Series([1.1]), "numeric"), @@ -147,6 +172,7 @@ def test_serialize_dtype( def test_serialize_frame(df_f: IntoDataFrame): + # if not isinstance(df_f, pl.DataFrame): # pytest.skip() @@ -157,21 +183,71 @@ def test_serialize_frame(df_f: IntoDataFrame): # if isinstance(df_f, pl.DataFrame): # pytest.xfail() - res = serialize_frame(df_nw) + is_polars_backed = isinstance( + nw.to_native(nw.from_native(df_f, eager_only=True)), pl.DataFrame + ) + + with session_context(test_session): + res = serialize_frame(df_nw) assert res == { - "columns": ["num", "chr", "cat", "dt", "struct", "arr", "object"], - # "index": [0, 1], + "columns": [ + "num", + "chr", + "cat", + "dt", + "html", + "html_str", + "struct", + "arr", + "object", + ], "data": [ - [1, "a", "a", "2000-01-02T00:00:00", {"x": 1}, [1, 2], ""], - [2, "b", "a", "2000-01-02T00:00:00", {"x": 2}, [3, 4], {"y": 2}], + [ + 1, + "a", + "a", + "2000-01-02T00:00:00", + { + "isShinyHtml": True, + "obj": {"deps": [], "html": "span content"}, + }, + { + "isShinyHtml": True, + "obj": {"deps": [], "html": "bolded"}, + }, + {"x": 1}, + [1, 2], + "", + ], + [ + 2, + "b", + "a", + "2000-01-02T00:00:00", + { + "isShinyHtml": True, + "obj": {"deps": [], "html": "span content"}, + }, + { + "isShinyHtml": True, + "obj": {"deps": [], "html": "bolded"}, + }, + {"x": 2}, + [3, 4], + {"y": 2}, + ], ], "typeHints": [ {"type": "numeric"}, {"type": "string"}, {"type": "string"}, {"type": "datetime"}, - {"type": "object" if (isinstance(df_f, pd.DataFrame)) else "unknown"}, - {"type": "object" if (isinstance(df_f, pd.DataFrame)) else "unknown"}, + {"type": "html"}, + {"type": "html"}, + # Polars doesn't have a way to represent a struct, + # so Narwhals marks it as unknown + {"type": "unknown" if is_polars_backed else "object"}, + {"type": "unknown" if is_polars_backed else "object"}, {"type": "object"}, ], } @@ -185,8 +261,8 @@ def test_subset_frame(df_f: IntoDataFrame): assert_frame_equal2(res, dst) -# def test_get_frame_cell(df_f: IntoDataFrameT): -# assert get_frame_cell(df_f, 1, 1) == "b" +def test_get_frame_cell(df_f: IntoDataFrame): + assert as_data_frame(df_f).item(1, 1) == "b" def test_copy_frame(df_f: IntoDataFrame): From d0282aa19348e89cd91d74877d5d723b5fcf0bdb Mon Sep 17 00:00:00 2001 From: Barret Schloerke Date: Mon, 23 Sep 2024 08:40:10 -0400 Subject: [PATCH 32/87] Remove `SeriesLike` type --- shiny/render/_data_frame_utils/_html.py | 4 ++-- shiny/render/_data_frame_utils/_tbl_data.py | 2 -- shiny/render/_data_frame_utils/_types.py | 9 ++++----- tests/pytest/test_render_data_frame_tbl_data.py | 4 ++-- 4 files changed, 8 insertions(+), 11 deletions(-) diff --git a/shiny/render/_data_frame_utils/_html.py b/shiny/render/_data_frame_utils/_html.py index ab6626356..e5f0f7f3f 100644 --- a/shiny/render/_data_frame_utils/_html.py +++ b/shiny/render/_data_frame_utils/_html.py @@ -6,7 +6,7 @@ from ..._typing_extensions import TypeGuard from ...types import Jsonifiable -from ._types import CellHtml, ReprHtml, SeriesLike +from ._types import CellHtml, ReprHtml if TYPE_CHECKING: import narwhals.stable.v1 as nw @@ -43,7 +43,7 @@ def maybe_as_cell_html( return cast(Jsonifiable, x) -def col_contains_shiny_html(col: SeriesLike | nw.Series) -> bool: +def col_contains_shiny_html(col: nw.Series) -> bool: for val in col: if is_shiny_html(val): return True diff --git a/shiny/render/_data_frame_utils/_tbl_data.py b/shiny/render/_data_frame_utils/_tbl_data.py index 7aa712e75..1bdce6750 100644 --- a/shiny/render/_data_frame_utils/_tbl_data.py +++ b/shiny/render/_data_frame_utils/_tbl_data.py @@ -2,7 +2,6 @@ from __future__ import annotations -from functools import singledispatch from typing import Any, List, Tuple, TypedDict import narwhals.stable.v1 as nw @@ -25,7 +24,6 @@ PandasCompatible, PdDataFrame, RowsList, - SeriesLike, ) __all__ = ( diff --git a/shiny/render/_data_frame_utils/_types.py b/shiny/render/_data_frame_utils/_types.py index d2273ee31..cbcdb26c0 100644 --- a/shiny/render/_data_frame_utils/_types.py +++ b/shiny/render/_data_frame_utils/_types.py @@ -36,7 +36,6 @@ "PdSeries", "PlSeries", # "ListSeriesLike", - "SeriesLike", "IntoExpr", "DataFrame", "DataFrameT", @@ -86,7 +85,7 @@ PlSeries = pl.Series # ListSeriesLike = Union[List[PdSeries], List[PlSeries]] - SeriesLike = Union[PdSeries, PlSeries] + # SeriesLike = Union[PdSeries, PlSeries] else: @@ -105,13 +104,13 @@ class PlSeries(AbstractBackend): # class ListSeriesLike(ABC): ... - class SeriesLike(ABC): ... + # class SeriesLike(ABC): ... # ListSeriesLike.register(PdSeries) # ListSeriesLike.register(PlSeries) - SeriesLike.register(PdSeries) - SeriesLike.register(PlSeries) + # SeriesLike.register(PdSeries) + # SeriesLike.register(PlSeries) DataFrame = nw.DataFrame diff --git a/tests/pytest/test_render_data_frame_tbl_data.py b/tests/pytest/test_render_data_frame_tbl_data.py index d03ab31c3..6160031b5 100644 --- a/tests/pytest/test_render_data_frame_tbl_data.py +++ b/tests/pytest/test_render_data_frame_tbl_data.py @@ -18,7 +18,7 @@ serialize_frame, subset_frame, ) -from shiny.render._data_frame_utils._types import IntoDataFrame, SeriesLike +from shiny.render._data_frame_utils._types import IntoDataFrame from shiny.session import Session, session_context from shiny.session._session import RenderedDeps, ResolvedId, Root from shiny.ui import HTML, TagChild, TagList, h1, span @@ -79,7 +79,7 @@ def polars_dict_to_narwhals(d: dict[str, Any]) -> nw.DataFrame[pl.DataFrame]: return nw.from_native(pl.DataFrame(d), eager_only=True) -def series_to_narwhals(ser: SeriesLike) -> nw.Series: +def series_to_narwhals(ser: pd.Series[Any] | pl.Series) -> nw.Series: return nw.from_native(ser, series_only=True, strict=True) From c9009e805a403c5d4cdc9a9ef070e78fc26253d8 Mon Sep 17 00:00:00 2001 From: Barret Schloerke Date: Mon, 23 Sep 2024 13:17:04 -0400 Subject: [PATCH 33/87] Tighten up code. Remove mention of singledispatch --- shiny/render/_data_frame_utils/_html.py | 6 +- shiny/render/_data_frame_utils/_pandas.py | 135 -------- shiny/render/_data_frame_utils/_tbl_data.py | 325 +------------------- shiny/render/_data_frame_utils/_types.py | 17 +- 4 files changed, 7 insertions(+), 476 deletions(-) delete mode 100644 shiny/render/_data_frame_utils/_pandas.py diff --git a/shiny/render/_data_frame_utils/_html.py b/shiny/render/_data_frame_utils/_html.py index e5f0f7f3f..9461a2112 100644 --- a/shiny/render/_data_frame_utils/_html.py +++ b/shiny/render/_data_frame_utils/_html.py @@ -6,11 +6,9 @@ from ..._typing_extensions import TypeGuard from ...types import Jsonifiable -from ._types import CellHtml, ReprHtml +from ._types import CellHtml, ReprHtml, Series if TYPE_CHECKING: - import narwhals.stable.v1 as nw - from ...session import Session @@ -43,7 +41,7 @@ def maybe_as_cell_html( return cast(Jsonifiable, x) -def col_contains_shiny_html(col: nw.Series) -> bool: +def col_contains_shiny_html(col: Series) -> bool: for val in col: if is_shiny_html(val): return True diff --git a/shiny/render/_data_frame_utils/_pandas.py b/shiny/render/_data_frame_utils/_pandas.py deleted file mode 100644 index 0eedbbb82..000000000 --- a/shiny/render/_data_frame_utils/_pandas.py +++ /dev/null @@ -1,135 +0,0 @@ -from __future__ import annotations - -# import json -# from typing import TYPE_CHECKING, Any - -# from htmltools import TagNode - -# from ...session._utils import require_active_session -# from ._html import col_contains_shiny_html, maybe_as_cell_html -# from ._tbl_data import PdDataFrame, frame_column_names -# from ._types import FrameDtype, FrameJson - -# if TYPE_CHECKING: -# import pandas as pd - - -# def serialize_frame_pd(df: "pd.DataFrame") -> FrameJson: -# import pandas as pd - -# columns = frame_column_names(df) -# columns_set = set(columns) -# if len(columns_set) != len(columns): -# raise ValueError( -# "The column names of the pandas DataFrame are not unique." -# " This is not supported by the data_frame renderer." -# ) - -# # Currently, we don't make use of the index; drop it so we don't error trying to -# # serialize it or something -# df = df.reset_index(drop=True) - -# # # Can we keep the original column information? -# # # Maybe we need to inspect the original columns for any "unknown" column type. See if it contains any HTML or Tag objects -# # for col in columns: -# # if df[col].dtype.name == "unknown": -# # print(df[col].to_list()) -# # raise ValueError( -# # "The pandas DataFrame contains columns of type 'object'." -# # " This is not supported by the data_frame renderer." -# # ) - -# type_hints = serialize_numpy_dtypes(df) - -# # Auto opt-in for html columns -# html_columns = [ -# i for i, type_hint in enumerate(type_hints) if type_hint["type"] == "html" -# ] - -# if len(html_columns) > 0: -# # Enable copy-on-write mode for the data; -# # Use `deep=False` to avoid copying the full data; CoW will copy the necessary data when modified - -# with pd.option_context("mode.copy_on_write", True): -# df = df.copy(deep=False) -# session = require_active_session(None) - -# def wrap_shiny_html_with_session(x: TagNode): -# return maybe_as_cell_html(x, session=session) - -# for html_column in html_columns: -# # _upgrade_ all the HTML columns to `CellHtml` json objects -# df[df.columns[html_column]] = df[ -# df.columns[html_column] -# ].apply( # pyright: ignore[reportUnknownMemberType] -# wrap_shiny_html_with_session -# ) - -# res = json.loads( -# # {index: [index], columns: [columns], data: [values]} -# df.to_json( # pyright: ignore[reportUnknownMemberType] -# None, -# orient="split", -# # note that date_format iso converts durations to ISO8601 Durations. -# # e.g. 1 Day -> P1DT0H0M0S -# # see https://en.wikipedia.org/wiki/ISO_8601#Durations -# date_format="iso", -# default_handler=str, -# ) -# ) - -# res["typeHints"] = type_hints - -# if "index" in res: -# del res["index"] - -# # print(json.dumps(res, indent=4)) -# return res - - -# def serialize_numpy_dtypes(df: PdDataFrame) -> list[FrameDtype]: -# return [ -# serialize_pd_dtype(df[col]) # pyright: ignore[reportUnknownArgumentType] -# for col in df.columns -# ] - - -# def serialize_pd_dtype( -# col: "pd.Series[Any]", -# ) -> FrameDtype: -# import pandas as pd - -# t = pd.api.types.infer_dtype(col) -# # t can be any of: string, bytes, floating, integer, mixed-integer, -# # mixed-integer-float, decimal, complex, categorical, boolean, datetime64, -# # datetime, date, timedelta64, timedelta, time, period, mixed, unknown-array - -# if t == "string": -# if col_contains_shiny_html(col): -# t = "html" -# else: -# pass -# # If no HTML (which is a str) is found, then it is a string! (Keep t as `"string"`) -# elif t in ["bytes", "floating", "integer", "decimal", "mixed-integer-float"]: -# t = "numeric" -# elif t == "categorical": -# return { -# "type": "categorical", -# "categories": [ -# str(x) # pyright: ignore[reportUnknownArgumentType] -# for x in col.cat.categories.to_list() # pyright: ignore[reportUnknownVariableType, reportUnknownMemberType] -# ], -# } -# elif t in {"datetime64", "datetime"}: -# t = "datetime" - -# # # Disable timedelta as narwhals does not support it -# # elif t in {"timedelta", "timedelta64"}: -# # t = "timedelta" -# else: -# if col_contains_shiny_html(col): -# t = "html" -# else: -# t = "unknown" - -# return {"type": t} diff --git a/shiny/render/_data_frame_utils/_tbl_data.py b/shiny/render/_data_frame_utils/_tbl_data.py index 1bdce6750..874fe1a80 100644 --- a/shiny/render/_data_frame_utils/_tbl_data.py +++ b/shiny/render/_data_frame_utils/_tbl_data.py @@ -1,5 +1,3 @@ -# Note - barret 2024-07-08; When we adopt `narwhals` support, we should remove the singledispatch and instead always use `narwhals`. In addition, we should return the native type of a native type was originally provided. (Or maintain the narwhals object, if a narwhals object was provided.) - from __future__ import annotations from typing import Any, List, Tuple, TypedDict @@ -28,15 +26,13 @@ __all__ = ( "is_into_data_frame", - # "as_data_frame_like", "as_data_frame", "data_frame_to_native", - # "frame_columns", "apply_frame_patches", "serialize_dtype", "serialize_frame", "subset_frame", - # "get_frame_cell", + "get_frame_cell", "frame_shape", "copy_frame", "frame_column_names", @@ -90,24 +86,7 @@ def compatible_to_pandas( raise TypeError(f"Unsupported type: {type(data)}") -# @singledispatch -# def is_data_frame_like( -# data: object, -# ) -> bool: -# return False - - -# @is_data_frame_like.register -# def _(data: PdDataFrame) -> bool: -# return True - - -# @is_data_frame_like.register -# def _(data: PlDataFrame) -> bool: -# return True - - -# TODO-barret; Replace with `nw.is_into_data_frame(x)`? +# TODO-future; Replace with `nw.is_into_data_frame(x)`? def is_into_data_frame( data: IntoDataFrameT | object, ) -> TypeIs[IntoDataFrameT]: @@ -117,70 +96,7 @@ def is_into_data_frame( return False -# # frame_columns ------------------------------------------------------------------------ - - -# @singledispatch -# def frame_columns(data: IntoDataFrame) -> ListSeriesLike: -# raise TypeError(f"Unsupported type: {type(data)}") - - -# @frame_columns.register -# def _(data: PdDataFrame) -> ListSeriesLike: -# ret = [cast(PlSeries, data[col]) for col in data.columns] -# return ret - - -# @frame_columns.register -# def _(data: PlDataFrame) -> ListSeriesLike: -# return data.get_columns() - - # apply_frame_patches -------------------------------------------------------------------- - - -# def apply_frame_patches__typed( -# data: IntoDataFrameT, patches: List[CellPatch] -# ) -> IntoDataFrameT: -# return cast(IntoDataFrameT, apply_frame_patches(data, patches)) - - -# @singledispatch -# def apply_frame_patches( -# data: IntoDataFrame, -# patches: List[CellPatch], -# ) -> IntoDataFrame: -# raise TypeError(f"Unsupported type: {type(data)}") - - -# @apply_frame_patches.register -# def _(data: PdDataFrame, patches: List[CellPatch]) -> PdDataFrame: -# import pandas as pd - -# # Enable copy-on-write mode for the data; -# # Use `deep=False` to avoid copying the full data; CoW will copy the necessary data when modified -# with pd.option_context("mode.copy_on_write", True): -# # Apply patches! -# data = data.copy(deep=False) -# for cell_patch in patches: -# data.iat[ # pyright: ignore[reportUnknownMemberType] -# cell_patch["row_index"], -# cell_patch["column_index"], -# ] = cell_patch["value"] - -# return data - - -# @apply_frame_patches.register -# def _(data: PlDataFrame, patches: List[CellPatch]) -> PlDataFrame: -# data = data.clone() -# for cell_patch in patches: -# data[cell_patch["row_index"], cell_patch["column_index"]] = cell_patch["value"] - -# return data - - -# @apply_frame_patches.register(DataFrame) def apply_frame_patches( nw_data: DataFrame[IntoDataFrameT], patches: List[CellPatch], @@ -268,50 +184,6 @@ def apply_frame_patches( # serialize_dtype ---------------------------------------------------------------------- - - -# @singledispatch -# def serialize_dtype(col: SeriesLike) -> FrameDtype: -# raise TypeError(f"Unsupported type: {type(col)}") - - -# TODO: we can't import DataFrameDtype at runtime, due to circular dependency. So -# we import it during type checking. But this means we have to explicitly register -# the dispatch type below. - - -# @serialize_dtype.register -# def _(col: PdSeries) -> FrameDtype: -# from ._pandas import serialize_pd_dtype - -# return serialize_pd_dtype(col) - - -# @serialize_dtype.register -# def _(col: PlSeries) -> FrameDtype: -# import polars as pl - -# from ._html import col_contains_shiny_html - -# if col.dtype == pl.String(): -# if col_contains_shiny_html(col): -# type_ = "html" -# else: -# type_ = "string" -# elif col.dtype.is_numeric(): -# type_ = "numeric" - -# elif col.dtype.is_(pl.Categorical()): -# categories = col.cat.get_categories().to_list() -# return {"type": "categorical", "categories": categories} -# else: -# type_ = "unknown" -# if col_contains_shiny_html(col): -# type_ = "html" - -# return {"type": type_} - - nw_boolean = nw.Boolean() nw_categorical = nw.Categorical() nw_enum = nw.Enum() @@ -321,8 +193,6 @@ def apply_frame_patches( nw_object = nw.Object() -# @serialize_dtype.register -# def _(col: nw.Series) -> FrameDtype: def serialize_dtype(col: nw.Series) -> FrameDtype: from ._html import col_contains_shiny_html @@ -370,62 +240,7 @@ def serialize_dtype(col: nw.Series) -> FrameDtype: # serialize_frame ---------------------------------------------------------------------- - - -# @singledispatch -# def serialize_frame(data: IntoDataFrame) -> FrameJson: -# raise TypeError(f"Unsupported type: {type(data)}") - - -# @serialize_frame.register -# def _(data: PdDataFrame) -> FrameJson: -# from ._pandas import serialize_frame_pd - -# return serialize_frame_pd(data) - - -# # TODO: test this -# @serialize_frame.register -# def _(data: PlDataFrame) -> FrameJson: -# import json - -# type_hints = list(map(serialize_dtype, data)) -# data_by_row = list(map(list, data.rows())) - -# # Shiny tag support -# type_hints_type = [type_hint["type"] for type_hint in type_hints] -# if "html" in type_hints_type: -# session = require_active_session(None) - -# def wrap_shiny_html_with_session(x: TagNode): -# return maybe_as_cell_html(x, session=session) - -# html_columns = [i for i, x in enumerate(type_hints_type) if x == "html"] - -# for html_column in html_columns: -# for row in data_by_row: -# row[html_column] = wrap_shiny_html_with_session(row[html_column]) - -# data_val = json.loads(json.dumps(data_by_row, default=str)) - -# return { -# # "index": list(range(len(data))), -# "columns": data.columns, -# "data": data_val, -# "typeHints": type_hints, -# } - -# try: -# import pandas as pd # type: ignore # noqa: F401 - -# has_pandas = True -# except ImportError: -# has_pandas = False - - -# @serialize_frame.register(DataFrame) def serialize_frame(into_data: IntoDataFrame) -> FrameJson: - # def _(data: DataFrame[Any]) -> FrameJson: data = as_data_frame(into_data) @@ -497,7 +312,6 @@ def my_str(x: Any) -> str: # subset_frame ------------------------------------------------------------------------- -# @singledispatch def subset_frame( data: DataFrameT, *, @@ -539,106 +353,12 @@ def subset_frame( return data[list(rows), col_names] -# @subset_frame.register -# def _( -# data: PdDataFrame, -# *, -# rows: RowsList = None, -# cols: ColsList = None, -# ) -> PdDataFrame: -# # Enable copy-on-write mode for the data; -# # Use `deep=False` to avoid copying the full data; CoW will copy the necessary data when modified -# import pandas as pd - -# with pd.option_context("mode.copy_on_write", True): -# # iloc requires integer positions, so we convert column name strings to ints, or -# # the slice default. -# indx_cols = ( # pyright: ignore[reportUnknownVariableType] -# slice(None) -# if cols is None -# else [ -# ( -# # Send in an array of size 1 and retrieve the first element -# data.columns.get_indexer_for( # pyright: ignore[reportUnknownMemberType] -# [col] -# )[ -# 0 -# ] -# if isinstance(col, str) -# else col -# ) -# for col in cols -# ] -# ) - -# # Force list when using a non-None value for pandas compatibility -# indx_rows = list(rows) if rows is not None else slice(None) - -# return data.iloc[indx_rows, indx_cols] - - -# @subset_frame.register -# def _( -# data: PlDataFrame, -# *, -# rows: RowsList = None, -# cols: ColsList = None, -# ) -> PlDataFrame: -# indx_cols = ( -# [col if isinstance(col, str) else data.columns[col] for col in cols] -# if cols is not None -# else slice(None) -# ) -# indx_rows = rows if rows is not None else slice(None) -# return data[indx_cols][indx_rows] - - # # get_frame_cell ----------------------------------------------------------------------- - - -# @singledispatch -# def get_frame_cell(data: IntoDataFrame, row: int, col: int) -> Any: -# raise TypeError(f"Unsupported type: {type(data)}") - - -# @get_frame_cell.register -# def _(data: PdDataFrame, row: int, col: int) -> Any: -# return ( -# data.iat[ # pyright: ignore[reportUnknownMemberType, reportUnknownVariableType] -# row, col -# ] -# ) - - -# @get_frame_cell.register(DataFrame) -# @get_frame_cell.register -# def _(data: PlDataFrame, row: int, col: int) -> Any: -# return data.item(row, col) +def get_frame_cell(data: DataFrame[Any], row: int, col: int) -> Any: + return data.item(row, col) # shape -------------------------------------------------------------------------------- - - -# @singledispatch -# def frame_shape(data: IntoDataFrame) -> Tuple[int, int]: -# raise TypeError(f"Unsupported type: {type(data)}") - - -# # @frame_shape.register -# # def _(data: PdDataFrame) -> Tuple[int, int]: -# # return data.shape - - -# # @frame_shape.register -# # def _(data: PlDataFrame) -> Tuple[int, int]: -# # return data.shape - - -# @frame_shape.register(DataFrame) -# def _(data: DataFrame[Any]) -> Tuple[int, int]: -# return data.shape - - def frame_shape(data: IntoDataFrame) -> Tuple[int, int]: nw_data = as_data_frame(data) return nw_data.shape @@ -650,48 +370,11 @@ def column_is_numeric(nw_data: DataFrame[Any], column_index: int) -> bool: # copy_frame --------------------------------------------------------------------------- - - def copy_frame(nw_data: DataFrameT) -> DataFrameT: return nw_data.clone() -# @singledispatch -# def copy_frame(data: IntoDataFrame) -> IntoDataFrame: -# raise TypeError(f"Unsupported type: {type(data)}") - - -# @copy_frame.register -# def _(data: PdDataFrame) -> PdDataFrame: -# return data.copy() - - -# @copy_frame.register(DataFrame) -# @copy_frame.register -# def _(data: PlDataFrame) -> PlDataFrame: -# return data.clone() - - # column_names ------------------------------------------------------------------------- -# @singledispatch -# def frame_column_names(data: IntoDataFrame) -> List[str]: -# raise TypeError(f"Unsupported type: {type(data)}") - - -# # @frame_column_names.register -# # def _(data: PdDataFrame) -> List[str]: -# # return data.columns.to_list() - -# # @frame_column_names.register -# # def _(data: PlDataFrame) -> List[str]: -# # return data.columns - - -# @frame_column_names.register(DataFrame) -# def _(data: DataFrame[Any]) -> List[str]: -# return data.columns - - def frame_column_names(into_data: IntoDataFrame) -> List[str]: return as_data_frame(into_data).columns diff --git a/shiny/render/_data_frame_utils/_types.py b/shiny/render/_data_frame_utils/_types.py index cbcdb26c0..7f3bf9826 100644 --- a/shiny/render/_data_frame_utils/_types.py +++ b/shiny/render/_data_frame_utils/_types.py @@ -2,7 +2,6 @@ from __future__ import annotations -from abc import ABC from typing import ( TYPE_CHECKING, Any, @@ -28,14 +27,11 @@ from ...types import Jsonifiable, JsonifiableDict, ListOrTuple from ._databackend import AbstractBackend -# from narwhals.typing import FrameT as NwFrameT - __all__ = ( "PdDataFrame", "PlDataFrame", "PdSeries", "PlSeries", - # "ListSeriesLike", "IntoExpr", "DataFrame", "DataFrameT", @@ -84,9 +80,6 @@ PdSeries = pd.Series[Any] PlSeries = pl.Series - # ListSeriesLike = Union[List[PdSeries], List[PlSeries]] - # SeriesLike = Union[PdSeries, PlSeries] - else: @@ -102,17 +95,9 @@ class PdSeries(AbstractBackend): class PlSeries(AbstractBackend): _backends = [("polars", "Series")] - # class ListSeriesLike(ABC): ... - - # class SeriesLike(ABC): ... - - # ListSeriesLike.register(PdSeries) - # ListSeriesLike.register(PlSeries) - - # SeriesLike.register(PdSeries) - # SeriesLike.register(PlSeries) DataFrame = nw.DataFrame +Series = nw.Series # --------------------------------------------------------------------- From a0681b78a6a395cd39021246b70695c4954656c5 Mon Sep 17 00:00:00 2001 From: Barret Schloerke Date: Tue, 24 Sep 2024 17:11:17 -0400 Subject: [PATCH 34/87] Use latest narwhals (1.8.3) and dev htmltools --- pyproject.toml | 5 +- shiny/render/_data_frame_utils/_html.py | 61 ++++++--- shiny/render/_data_frame_utils/_tbl_data.py | 125 +++++++----------- shiny/render/_data_frame_utils/_types.py | 13 -- .../pytest/test_render_data_frame_tbl_data.py | 9 +- 5 files changed, 102 insertions(+), 111 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 8b07a9a19..0c97a3414 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -34,7 +34,8 @@ dependencies = [ "starlette", "websockets>=10.0", "python-multipart", - "htmltools>=0.5.2", + # "htmltools>=0.5.3.9001", + "htmltools@git+https://github.com/posit-dev/py-htmltools", "click>=8.1.4;platform_system!='Emscripten'", "markdown-it-py>=1.1.0", "mdit-py-plugins>=0.3.0", @@ -47,7 +48,7 @@ dependencies = [ "prompt-toolkit;platform_system!='Emscripten'", "python-multipart>=0.0.7;platform_system!='Emscripten'", "setuptools;python_version>='3.12'", - "narwhals>=1.8.0", + "narwhals>=1.8.3", "orjson>=3.10.7", ] diff --git a/shiny/render/_data_frame_utils/_html.py b/shiny/render/_data_frame_utils/_html.py index 9461a2112..8e2fc9905 100644 --- a/shiny/render/_data_frame_utils/_html.py +++ b/shiny/render/_data_frame_utils/_html.py @@ -1,12 +1,12 @@ from __future__ import annotations -from typing import TYPE_CHECKING, Any, cast, overload +from typing import TYPE_CHECKING, Literal, cast, overload -from htmltools import HTML, MetadataNode, Tagifiable, TagNode +from htmltools import TagNode, is_tag_node -from ..._typing_extensions import TypeGuard +from ..._typing_extensions import TypeIs from ...types import Jsonifiable -from ._types import CellHtml, ReprHtml, Series +from ._types import CellHtml, Series if TYPE_CHECKING: from ...session import Session @@ -16,17 +16,10 @@ def as_cell_html(x: TagNode, *, session: Session) -> CellHtml: return {"isShinyHtml": True, "obj": session._process_ui(x)} -# def is_cell_html(val: Any) -> TypeGuard[CellHtml]: -# return isinstance(val, dict) and ( -# val.get("isShinyHtml", False) # pyright: ignore[reportUnknownMemberType] -# is True -# ) - - @overload def maybe_as_cell_html( # pyright: ignore[reportOverlappingOverload] - x: TagNode, *, session: Session -) -> CellHtml: ... + x: str, *, session: Session +) -> Jsonifiable: ... @overload def maybe_as_cell_html( # pyright: ignore[reportOverlappingOverload] x: TagNode, *, session: Session @@ -36,19 +29,49 @@ def maybe_as_cell_html(x: Jsonifiable, *, session: Session) -> Jsonifiable: ... def maybe_as_cell_html( x: Jsonifiable | TagNode, *, session: Session ) -> Jsonifiable | CellHtml: - if is_shiny_html(x): + if cell_contains_htmltoolslike(x): return as_cell_html(x, session=session) return cast(Jsonifiable, x) -def col_contains_shiny_html(col: Series) -> bool: - for val in col: - if is_shiny_html(val): +def series_contains_htmltoolslike(ser: Series) -> bool: + + for idx, val in enumerate(ser): + # Only check the first 1k elements in the series + # This could lead to false negatives, but it's a reasonable tradeoff of speed. + # If the user has _that_ much missing data and wants HTML support, + # they can preprocess their data to turn `None` values into `htmltools.HTML("")` + if idx > 1000: + return False + + if val is None: + continue + + # Q: Can we short circuit this any quicker? + # A: Not really. We need to check every element in the series + # as the typical dtype is greedy does not enforce a single type. + # Reprex: + # pl.Series([{"y": 2}, {"x": 1}, None, HTML("

Hello

")]).dtype + # #> Struct({'y': Int64}) + if cell_contains_htmltoolslike(val): return True return False # TODO-barret-test; Add test to assert the union type of `TagNode` contains `str` and (HTML | Tagifiable | MetadataNode | ReprHtml). Until a `is tag renderable` method is available in htmltools, we need to check for these types manually and must stay in sync with the `TagNode` union type. # TODO-barret-future; Use `TypeIs[HTML | Tagifiable | MetadataNode | ReprHtml]` when it is available from typing_extensions -def is_shiny_html(val: Any) -> TypeGuard[HTML | Tagifiable | MetadataNode | ReprHtml]: - return isinstance(val, (HTML, Tagifiable, MetadataNode, ReprHtml)) + + +@overload +def cell_contains_htmltoolslike( # pyright: ignore[reportOverlappingOverload] + val: str, +) -> Literal[False]: ... +@overload +def cell_contains_htmltoolslike( + val: TagNode | object, +) -> TypeIs[TagNode]: ... +def cell_contains_htmltoolslike(val: object): + if isinstance(val, str): + return False + + return is_tag_node(val) diff --git a/shiny/render/_data_frame_utils/_tbl_data.py b/shiny/render/_data_frame_utils/_tbl_data.py index 874fe1a80..56961c46d 100644 --- a/shiny/render/_data_frame_utils/_tbl_data.py +++ b/shiny/render/_data_frame_utils/_tbl_data.py @@ -106,81 +106,52 @@ def apply_frame_patches( if len(patches) == 0: return nw_data - # Us an index to know which row we are updating - data_with_index = nw_data.with_row_index() - # Apply the patches - # If multiple `when` statements are possible, then use this code - if True: - # # https://discord.com/channels/1235257048170762310/1235257049626181656/1283415086722977895 - # # Using narwhals >= v1.7.0 - # @nw.narwhalify - # def func(df): - # return df.with_columns( - # df['a'].scatter([0, 1], [999, 888]), - # df['b'].scatter([0, 1], [777, 555]), - # ) - - # Group patches by column - # This allows for a single column to be updated in a single operation (rather than multiple updates to the same column) - - cell_patches_by_column: dict[str, ScatterValues] = {} - for cell_patch in patches: - column_name = nw_data.columns[cell_patch["column_index"]] - if column_name not in cell_patches_by_column: - cell_patches_by_column[column_name] = { - "row_indexes": [], - "values": [], - } - - # Append the row index and value to the column information - cell_patches_by_column[column_name]["row_indexes"].append( - cell_patch["row_index"] - ) - cell_patches_by_column[column_name]["values"].append(cell_patch["value"]) - - # Upgrade the Scatter info to new column Series objects - scatter_columns = [ - nw_data[column_name].scatter( - scatter_values["row_indexes"], scatter_values["values"] - ) - for column_name, scatter_values in cell_patches_by_column.items() - ] - # Apply patches to the nw data - return nw_data.with_columns(*scatter_columns) - - # Documentation for nw.when: https://narwhals-dev.github.io/narwhals/api-reference/narwhals/#narwhals.when - # when_then_otherwise_arr: List[IntoExpr] = [] - - for column_name, cell_patches in cell_patches_by_column.items(): - col_expr = nw.when( - nw.col("index") == cell_patches[0]["row_index"], - ).then(cell_patches[0]["value"]) - - for i, cell_patch in enumerate(cell_patches): - if i == 0: - # Performed above to get typing value - continue - col_expr = col_expr.when( - nw.col("index") == cell_patch["row_index"], - ).then(cell_patch["value"]) - - col_expr = col_expr.alias(column_name) - # when_then_otherwise_arr.append(col_expr) - else: - # https://discord.com/channels/1235257048170762310/1235257049626181656/1283078606775517184 - # Very inefficient code that works to update a cell by making a new column for every patch value - for cell_patch in patches: - data_with_index = data_with_index.with_columns( - nw.when(nw.col("index") == cell_patch["row_index"]) - .then(cell_patch["value"]) - .otherwise(nw.col(nw_data.columns[cell_patch["column_index"]])) - ) - - patched_data = data_with_index.drop("index") + # TODO-future-barret; Might be faster to _always_ store the patches as a + # `cell_patches_by_column` object. Then iff they need the patches would we + # deconstruct them into a flattened list. Where as this conversion is being + # performed on every serialization of the data frame payload + + # # https://discord.com/channels/1235257048170762310/1235257049626181656/1283415086722977895 + # # Using narwhals >= v1.7.0 + # @nw.narwhalify + # def func(df): + # return df.with_columns( + # df['a'].scatter([0, 1], [999, 888]), + # df['b'].scatter([0, 1], [777, 555]), + # ) + + # Group patches by column + # This allows for a single column to be updated in a single operation (rather than multiple updates to the same column) + # + # In; patches: List[Dict[row_index: int, column_index: int, value: Any]] + # Out; cell_patches_by_column: Dict[column_name: str, List[Dict[row_index: int, value: Any]]] + # + cell_patches_by_column: dict[str, ScatterValues] = {} + for cell_patch in patches: + column_name = nw_data.columns[cell_patch["column_index"]] + if column_name not in cell_patches_by_column: + cell_patches_by_column[column_name] = { + "row_indexes": [], + "values": [], + } + + # Append the row index and value to the column information + cell_patches_by_column[column_name]["row_indexes"].append( + cell_patch["row_index"] + ) + cell_patches_by_column[column_name]["values"].append(cell_patch["value"]) - return patched_data + # Upgrade the Scatter info to new column Series objects + scatter_columns = [ + nw_data[column_name].scatter( + scatter_values["row_indexes"], scatter_values["values"] + ) + for column_name, scatter_values in cell_patches_by_column.items() + ] + # Apply patches to the nw data + return nw_data.with_columns(*scatter_columns) # serialize_dtype ---------------------------------------------------------------------- @@ -195,12 +166,12 @@ def apply_frame_patches( def serialize_dtype(col: nw.Series) -> FrameDtype: - from ._html import col_contains_shiny_html + from ._html import series_contains_htmltoolslike dtype: DType = col.dtype if dtype == nw_string: - if col_contains_shiny_html(col): + if series_contains_htmltoolslike(col): type_ = "html" else: type_ = "string" @@ -228,12 +199,12 @@ def serialize_dtype(col: nw.Series) -> FrameDtype: type_ = "datetime" elif dtype == nw_object: type_ = "object" - if col_contains_shiny_html(col): + if series_contains_htmltoolslike(col): type_ = "html" else: type_ = "unknown" - if col_contains_shiny_html(col): + if series_contains_htmltoolslike(col): type_ = "html" return {"type": type_} @@ -247,6 +218,8 @@ def serialize_frame(into_data: IntoDataFrame) -> FrameJson: type_hints = [serialize_dtype(data[col_name]) for col_name in data.columns] type_hints_type = [type_hint["type"] for type_hint in type_hints] + # print("type_hints:", type_hints) + data_rows = data.rows(named=False) # Shiny tag support diff --git a/shiny/render/_data_frame_utils/_types.py b/shiny/render/_data_frame_utils/_types.py index 7f3bf9826..f79cbed84 100644 --- a/shiny/render/_data_frame_utils/_types.py +++ b/shiny/render/_data_frame_utils/_types.py @@ -60,7 +60,6 @@ "StyleInfo", "BrowserStyleInfoBody", "BrowserStyleInfo", - "ReprHtml", "CellValue", "CellPatch", "CellPatchProcessed", @@ -270,18 +269,6 @@ class FrameDtypeCategories(TypedDict): ) BrowserStyleInfo = BrowserStyleInfoBody -# --------------------------------------------------------------------- - - -# TODO-future; Replace this class with `htmltools.ReprHtml` when it is publically available. Even better... there should be a "is tag-like" method in htmltools that determines if the object could be enhanced by rendering -@runtime_checkable -class ReprHtml(Protocol): - """ - Objects with a `_repr_html_()` method. - """ - - def _repr_html_(self) -> str: ... - # Cell patches ---------------------------------------------------------- diff --git a/tests/pytest/test_render_data_frame_tbl_data.py b/tests/pytest/test_render_data_frame_tbl_data.py index 6160031b5..3ca00232f 100644 --- a/tests/pytest/test_render_data_frame_tbl_data.py +++ b/tests/pytest/test_render_data_frame_tbl_data.py @@ -4,6 +4,7 @@ from datetime import datetime from typing import Any, Union, cast +import htmltools import narwhals.stable.v1 as nw import pandas as pd import polars as pl @@ -70,6 +71,12 @@ class D: "object": [C(1), D(2)], } +# Polars.Series is not always a TagNode (as it has a `__repr_html__` method) +# So we need to check if it is a TagNode to determine if it is an `"html"` or `"unknown"` type +polars_series_col_type = ( + "html" if htmltools.is_tag_node(pl.Series([[1, 2], [3, 4]])) else "unknown" +) + def pandas_dict_to_narwhals(d: dict[str, Any]) -> nw.DataFrame[pd.DataFrame]: return nw.from_native(pd.DataFrame(d), eager_only=True) @@ -247,7 +254,7 @@ def test_serialize_frame(df_f: IntoDataFrame): # Polars doesn't have a way to represent a struct, # so Narwhals marks it as unknown {"type": "unknown" if is_polars_backed else "object"}, - {"type": "unknown" if is_polars_backed else "object"}, + {"type": polars_series_col_type if is_polars_backed else "object"}, {"type": "object"}, ], } From d0772e46d999cdf78f62f2b94d9decc178c04381 Mon Sep 17 00:00:00 2001 From: Barret Schloerke Date: Tue, 24 Sep 2024 17:16:45 -0400 Subject: [PATCH 35/87] Remove many TODOs --- shiny/render/_data_frame.py | 4 ---- shiny/render/_data_frame_utils/_html.py | 4 ---- shiny/render/_data_frame_utils/_types.py | 2 +- 3 files changed, 1 insertion(+), 9 deletions(-) diff --git a/shiny/render/_data_frame.py b/shiny/render/_data_frame.py index be66d4f7a..f40fc0e2d 100644 --- a/shiny/render/_data_frame.py +++ b/shiny/render/_data_frame.py @@ -396,8 +396,6 @@ def self_cell_selection() -> CellSelection: selection_modes=self.selection_modes(), nw_data=self._nw_data(), data_view_rows=self.data_view_rows(), - # TODO-barret: replace methods like .shape, .loc. .iat with those from - # _tbl_data.py, test in the playright app. data_view_cols=tuple(range(frame_shape(self._nw_data())[1])), ) @@ -1049,8 +1047,6 @@ def input_cell_selection(self) -> CellSelection | None: # * Call styles fn after each edit (and on init); Send full styles for each cell # Support `rows: List[bool]`? -# r-shinylive: bundle ALL packages, R... it should work out of the box with no internet - # mydf.iloc[row_nums, col_nums] # mydf["mpg"] > 20 diff --git a/shiny/render/_data_frame_utils/_html.py b/shiny/render/_data_frame_utils/_html.py index 8e2fc9905..1ef885104 100644 --- a/shiny/render/_data_frame_utils/_html.py +++ b/shiny/render/_data_frame_utils/_html.py @@ -58,10 +58,6 @@ def series_contains_htmltoolslike(ser: Series) -> bool: return False -# TODO-barret-test; Add test to assert the union type of `TagNode` contains `str` and (HTML | Tagifiable | MetadataNode | ReprHtml). Until a `is tag renderable` method is available in htmltools, we need to check for these types manually and must stay in sync with the `TagNode` union type. -# TODO-barret-future; Use `TypeIs[HTML | Tagifiable | MetadataNode | ReprHtml]` when it is available from typing_extensions - - @overload def cell_contains_htmltoolslike( # pyright: ignore[reportOverlappingOverload] val: str, diff --git a/shiny/render/_data_frame_utils/_types.py b/shiny/render/_data_frame_utils/_types.py index f79cbed84..58641a9ee 100644 --- a/shiny/render/_data_frame_utils/_types.py +++ b/shiny/render/_data_frame_utils/_types.py @@ -1,4 +1,4 @@ -# TODO-barret; Replace all usage of (PdDataFrame, PlDataFrame, etc) with narwhals +# TODO-future-barret; Replace all usage of (PdDataFrame, PlDataFrame, etc) with narwhals from __future__ import annotations From 77d60859dccd26535b135f830319f82b718e127a Mon Sep 17 00:00:00 2001 From: Barret Schloerke Date: Wed, 25 Sep 2024 09:51:33 -0400 Subject: [PATCH 36/87] Update _html.py --- shiny/render/_data_frame_utils/_html.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/shiny/render/_data_frame_utils/_html.py b/shiny/render/_data_frame_utils/_html.py index 1ef885104..450c35b31 100644 --- a/shiny/render/_data_frame_utils/_html.py +++ b/shiny/render/_data_frame_utils/_html.py @@ -66,7 +66,9 @@ def cell_contains_htmltoolslike( # pyright: ignore[reportOverlappingOverload] def cell_contains_htmltoolslike( val: TagNode | object, ) -> TypeIs[TagNode]: ... -def cell_contains_htmltoolslike(val: object): +def cell_contains_htmltoolslike( # pyright: ignore[reportInconsistentOverload] + val: object, +): if isinstance(val, str): return False From d66e1dedf18394d38bb00ea61f23f54c49181795 Mon Sep 17 00:00:00 2001 From: Barret Schloerke Date: Wed, 25 Sep 2024 10:19:45 -0400 Subject: [PATCH 37/87] Update docs --- shiny/_deprecated.py | 4 ++-- shiny/render/_data_frame.py | 19 ++++++++++++------- .../_data_frame_utils/_datagridtable.py | 17 +++++++++-------- shiny/render/_data_frame_utils/_tbl_data.py | 6 ++++-- 4 files changed, 27 insertions(+), 19 deletions(-) diff --git a/shiny/_deprecated.py b/shiny/_deprecated.py index f6be2e40b..d3fad6513 100644 --- a/shiny/_deprecated.py +++ b/shiny/_deprecated.py @@ -23,8 +23,8 @@ class ShinyDeprecationWarning(RuntimeWarning): warnings.simplefilter("always", ShinyDeprecationWarning) -def warn_deprecated(message: str): - warnings.warn(message, ShinyDeprecationWarning, stacklevel=3) +def warn_deprecated(message: str, stacklevel: int = 3): + warnings.warn(message, ShinyDeprecationWarning, stacklevel=stacklevel) def render_text(): diff --git a/shiny/render/_data_frame.py b/shiny/render/_data_frame.py index f40fc0e2d..e583b71a7 100644 --- a/shiny/render/_data_frame.py +++ b/shiny/render/_data_frame.py @@ -64,10 +64,11 @@ class data_frame( ] ): """ - Decorator for a function that returns a [pandas](https://pandas.pydata.org/) or - [polars](https://pola.rs/) `DataFrame` object to render as an interactive table or - grid. Features fast virtualized scrolling, sorting, filtering, and row selection - (single or multiple). + Decorator for a function that returns a [pandas](https://pandas.pydata.org/), + [polars](https://pola.rs/), or eager + [`narwhals`](https://narwhals-dev.github.io/narwhals/) compatible `DataFrame` object + to render as an interactive table or grid. Features fast virtualized scrolling, + sorting, filtering, and row selection (single or multiple). Returns ------- @@ -77,8 +78,10 @@ class data_frame( 1. A :class:`~shiny.render.DataGrid` or :class:`~shiny.render.DataTable` object, which can be used to customize the appearance and behavior of the data frame output. - 2. A pandas `DataFrame` object or a polars `DataFrame` object. This object will - be internally upgraded to `shiny.render.DataGrid(df)`. + 2. A [pandas](https://pandas.pydata.org/), [polars](https://pola.rs/), or eager + [`narwhals`](https://narwhals-dev.github.io/narwhals/) compatible `DataFrame` + object. This object will be internally upgraded to a default + `shiny.render.DataGrid(df)`. Row selection ------------- @@ -228,7 +231,9 @@ def data_view(self, *, selected: bool = False) -> IntoDataFrameT: See Also -------- - * [`pandas.DataFrame.copy` API documentation]h(ttps://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.copy.html) + * [`pandas.DataFrame.copy` API documentation](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.copy.html) + * [`polars.DataFrame.clone` API documentation](https://docs.pola.rs/api/python/stable/reference/dataframe/api/polars.DataFrame.clone.html) + * [`narwhals.DataFrame.clone` API documentation](https://narwhals-dev.github.io/narwhals/api-reference/dataframe/#narwhals.dataframe.DataFrame.clone) """ # Return reactive calculations so that they can be cached for other calculations if selected: diff --git a/shiny/render/_data_frame_utils/_datagridtable.py b/shiny/render/_data_frame_utils/_datagridtable.py index 42812d6f7..04bc9c9da 100644 --- a/shiny/render/_data_frame_utils/_datagridtable.py +++ b/shiny/render/_data_frame_utils/_datagridtable.py @@ -1,3 +1,6 @@ +# TODO-future-barret; Maybe use a `._options()` method to return a `JsonifiableDict` within the DataGrid/DataTable classes? +# TODO-future-barret; Really feals as if we should have a base class that does most of this for us + from __future__ import annotations import abc @@ -39,8 +42,9 @@ class DataGrid(AbstractTabularData, Generic[IntoDataFrameT]): Parameters ---------- data - A pandas or polars `DataFrame` object. If the object has a `.to_pandas()` - method, use the pandas form of your data. + A [pandas](https://pandas.pydata.org/), [polars](https://pola.rs/), or + eager [`narwhals`](https://narwhals-dev.github.io/narwhals/) compatible `DataFrame` + object. width A _maximum_ amount of horizontal space for the data grid to occupy, in CSS units (e.g. `"400px"`) or as a number, which will be interpreted as pixels. The @@ -136,10 +140,6 @@ def __init__( styles: StyleInfo | list[StyleInfo] | StyleFn[IntoDataFrameT] | None = None, row_selection_mode: RowSelectionModeDeprecated = "deprecated", ): - - # self._data_is_nw = isinstance(data, NwDataFrameRaw) - # self.data = as_narwhals(data) - # self.data = as_nw_friendly_data_frame(data) self.data = data self.width = width @@ -201,8 +201,9 @@ class DataTable(AbstractTabularData, Generic[IntoDataFrameT]): Parameters ---------- data - A pandas or polars `DataFrame` object. If the object has a `.to_pandas()` - method, use the pandas form of your data. + A [pandas](https://pandas.pydata.org/), [polars](https://pola.rs/), or + eager [`narwhals`](https://narwhals-dev.github.io/narwhals/) compatible `DataFrame` + object. width A _maximum_ amount of vertical space for the data table to occupy, in CSS units (e.g. `"400px"`) or as a number, which will be interpreted as pixels. The diff --git a/shiny/render/_data_frame_utils/_tbl_data.py b/shiny/render/_data_frame_utils/_tbl_data.py index 56961c46d..69ef54eed 100644 --- a/shiny/render/_data_frame_utils/_tbl_data.py +++ b/shiny/render/_data_frame_utils/_tbl_data.py @@ -55,7 +55,8 @@ def as_data_frame( return nw.from_native(data, eager_only=True) except TypeError as e: try: - return nw.from_native(compatible_to_pandas(data), eager_only=True) + compatible_data = compatible_to_pandas(data) + return nw.from_native(compatible_data, eager_only=True) except TypeError: # Couldn't convert to pandas, so raise the original error raise e @@ -79,7 +80,8 @@ def compatible_to_pandas( "A `.to_pandas()` was found on your object and will be called. " "To remove this warning, please call `.to_pandas()` on your data " "and use the pandas result in your returned value. " - "In the future, this will raise an error." + "In the future, this will raise an error.", + stacklevel=3, ) return data.to_pandas() From a950d7d1db3efe7ebb2e198a74becaf7d1210192 Mon Sep 17 00:00:00 2001 From: Barret Schloerke Date: Wed, 25 Sep 2024 16:35:59 -0400 Subject: [PATCH 38/87] Test more narwhals types. Add comment for file. --- shiny/render/_data_frame_utils/_tbl_data.py | 73 +++++----- shiny/render/_data_frame_utils/_types.py | 36 ++--- .../pytest/test_render_data_frame_tbl_data.py | 135 +++++++++++++++--- 3 files changed, 168 insertions(+), 76 deletions(-) diff --git a/shiny/render/_data_frame_utils/_tbl_data.py b/shiny/render/_data_frame_utils/_tbl_data.py index 69ef54eed..cecf67ccd 100644 --- a/shiny/render/_data_frame_utils/_tbl_data.py +++ b/shiny/render/_data_frame_utils/_tbl_data.py @@ -3,6 +3,7 @@ from typing import Any, List, Tuple, TypedDict import narwhals.stable.v1 as nw +import orjson from htmltools import TagNode from ..._typing_extensions import TypeIs @@ -20,7 +21,6 @@ IntoDataFrame, IntoDataFrameT, PandasCompatible, - PdDataFrame, RowsList, ) @@ -38,6 +38,29 @@ "frame_column_names", ) +######################################################################################## +# Narwhals +# +# This module contains functions for working with data frames. It is a wrapper +# around the Narwhals library, which provides a unified interface for working with +# data frames (e.g. Pandas and Polars). +# +# The functions in this module are used to: +# * convert data frames to and from the Narwhals format, +# * apply patches to data frames, +# * serialize data frames to JSON, +# * subset data frames, +# * and get information about data frames (e.g. shape, column names). +# +# The functions in this module are used by the Shiny framework to work with data frames. +# +# For more information on the Narwhals library, see: +# * Intro https://narwhals-dev.github.io/narwhals/basics/dataframe/ +# * `nw.DataFrame`: https://narwhals-dev.github.io/narwhals/api-reference/dataframe/ +# * `nw.typing.IntoDataFrameT`: https://narwhals-dev.github.io/narwhals/api-reference/typing/#intodataframet +# +######################################################################################## + # as_frame ----------------------------------------------------------------------------- @@ -159,10 +182,11 @@ def apply_frame_patches( # serialize_dtype ---------------------------------------------------------------------- nw_boolean = nw.Boolean() nw_categorical = nw.Categorical() +nw_duration = nw.Duration() nw_enum = nw.Enum() nw_string = nw.String() +nw_date = nw.Date() nw_datetime = nw.Datetime() -nw_duration = nw.Duration() nw_object = nw.Object() @@ -173,10 +197,8 @@ def serialize_dtype(col: nw.Series) -> FrameDtype: dtype: DType = col.dtype if dtype == nw_string: - if series_contains_htmltoolslike(col): - type_ = "html" - else: - type_ = "string" + type_ = "string" + elif dtype.is_numeric(): type_ = "numeric" @@ -184,21 +206,16 @@ def serialize_dtype(col: nw.Series) -> FrameDtype: categories = col.cat.get_categories().to_list() return {"type": "categorical", "categories": categories} elif dtype == nw_enum: - raise NotImplementedError("TODO-barret; enum type not tested") - cat_col = col.cast(nw.Categorical) - categories = cat_col.cat.get_categories().to_list() + categories = col.cat.get_categories().to_list() return {"type": "categorical", "categories": categories} - elif dtype == nw_boolean: - raise NotImplementedError("TODO-barret; boolean type not tested") type_ = "boolean" - elif dtype == nw_duration: - raise NotImplementedError( - "TODO-barret; duration type not tested. Look at pandas timedelta" - ) - type_ = "duration" + elif dtype == nw_date: + type_ = "date" elif dtype == nw_datetime: type_ = "datetime" + elif dtype == nw_duration: + type_ = "duration" elif dtype == nw_object: type_ = "object" if series_contains_htmltoolslike(col): @@ -220,8 +237,6 @@ def serialize_frame(into_data: IntoDataFrame) -> FrameJson: type_hints = [serialize_dtype(data[col_name]) for col_name in data.columns] type_hints_type = [type_hint["type"] for type_hint in type_hints] - # print("type_hints:", type_hints) - data_rows = data.rows(named=False) # Shiny tag support @@ -248,30 +263,12 @@ def wrap_shiny_html_with_session(x: TagNode): data_rows = new_rows - import orjson - - # TODO-barret; Remove debug! Maybe? - native_data = nw.to_native(data) - if isinstance(native_data, PdDataFrame): - # print("types:", type_hints_type, type_hints) - from pandas import Timestamp - - def my_str(x: Any) -> str: - # print("barret-pandas value!", x) - if isinstance(x, Timestamp): - return x.isoformat() - - return str(x) - - else: - - def my_str(x: Any) -> str: - return str(x) + # _ = datetime(5) data_val = orjson.loads( orjson.dumps( data_rows, - default=my_str, + default=str, # option=(orjson.OPT_NAIVE_UTC), ) ) diff --git a/shiny/render/_data_frame_utils/_types.py b/shiny/render/_data_frame_utils/_types.py index 58641a9ee..f2ba9c6e8 100644 --- a/shiny/render/_data_frame_utils/_types.py +++ b/shiny/render/_data_frame_utils/_types.py @@ -4,7 +4,6 @@ from typing import ( TYPE_CHECKING, - Any, Dict, Literal, Optional, @@ -29,9 +28,9 @@ __all__ = ( "PdDataFrame", - "PlDataFrame", - "PdSeries", - "PlSeries", + # "PlDataFrame", + # "PdSeries", + # "PlSeries", "IntoExpr", "DataFrame", "DataFrameT", @@ -70,14 +69,15 @@ if TYPE_CHECKING: import pandas as pd - import polars as pl + # import polars as pl from ...session._utils import RenderedDeps PdDataFrame = pd.DataFrame - PlDataFrame = pl.DataFrame - PdSeries = pd.Series[Any] - PlSeries = pl.Series + + # PlDataFrame = pl.DataFrame + # PdSeries = pd.Series[Any] + # PlSeries = pl.Series else: @@ -85,14 +85,14 @@ class PdDataFrame(AbstractBackend): _backends = [("pandas", "DataFrame")] - class PlDataFrame(AbstractBackend): - _backends = [("polars", "DataFrame")] + # class PlDataFrame(AbstractBackend): + # _backends = [("polars", "DataFrame")] - class PdSeries(AbstractBackend): - _backends = [("pandas", "Series")] + # class PdSeries(AbstractBackend): + # _backends = [("pandas", "Series")] - class PlSeries(AbstractBackend): - _backends = [("polars", "Series")] + # class PlSeries(AbstractBackend): + # _backends = [("polars", "Series")] DataFrame = nw.DataFrame @@ -203,15 +203,15 @@ class FrameJson(TypedDict): class FrameDtypeSubset(TypedDict): type: Literal[ - "boolean", - "numeric", "string", - "html", + "numeric", + "boolean", + "date", "datetime", - # "timedelta", "duration", "object", "unknown", + "html", ] diff --git a/tests/pytest/test_render_data_frame_tbl_data.py b/tests/pytest/test_render_data_frame_tbl_data.py index 3ca00232f..758c7b049 100644 --- a/tests/pytest/test_render_data_frame_tbl_data.py +++ b/tests/pytest/test_render_data_frame_tbl_data.py @@ -1,7 +1,9 @@ +# TODO-barret: ts code to stringify objects? + from __future__ import annotations from dataclasses import dataclass -from datetime import datetime +from datetime import datetime, timedelta from typing import Any, Union, cast import htmltools @@ -62,10 +64,11 @@ class D: "num": [1, 2], "chr": ["a", "b"], "cat": ["a", "a"], + "bool": [True, False], "dt": [datetime(2000, 1, 2)] * 2, + "duration": [timedelta(weeks=1), timedelta(days=7)], "html": [span("span content")] * 2, "html_str": [HTML("bolded")] * 2, - # TODO-barret: ts code to stringify objects? "struct": [{"x": 1}, {"x": 2}], "arr": [[1, 2], [3, 4]], "object": [C(1), D(2)], @@ -140,7 +143,6 @@ def assert_frame_equal2( assert_frame_equal(src_native, target_native, use_index) -# TODO: explicitly pass dtype= when doing Series construction @pytest.mark.parametrize( "ser, res_type", [ # pyright: ignore[reportUnknownArgumentType] # We are explicitly setting some values to `unkown` @@ -148,20 +150,60 @@ def assert_frame_equal2( (pl.Series([1]), "numeric"), (pl.Series([1.1]), "numeric"), (pl.Series(["a"]), "string"), + (pl.Series([True, False]), "boolean"), (pl.Series([datetime.now()]), "datetime"), - (pl.Series(["a"], dtype=pl.Categorical), "categorical"), + (pl.Series([timedelta(weeks=1)]), "duration"), + ( + pl.Series(["a", "b", "b", "c"], dtype=pl.Categorical), + ("categorical", ["a", "b", "c"]), + ), + ( + pl.Series( + ["Panda", "Polar", "Brown", "Brown", "Polar"], + dtype=pl.Enum(["Polar", "Panda", "Brown"]), + ), + ("categorical", ["Polar", "Panda", "Brown"]), + ), (pl.Series([{"x": 1}]), "unknown"), (pl.Series([h1("yo")]), "html"), - # TODO-barret; Need https://github.com/posit-dev/py-htmltools/pull/86 to be merged to remove custom dtype - (pl.Series([HTML("yo")], dtype=pl.Object), "html"), + (pl.Series([HTML("yo")]), "html"), # pandas ---- (pd.Series([1]), "numeric"), (pd.Series([1.1]), "numeric"), - (pd.Series(["a"], dtype="object"), "string"), - (pd.Series(["a"], dtype="string"), "string"), - (pd.Series([datetime.now()], dtype="datetime64[ns]"), "datetime"), - # (pd.Series([pd.Timedelta(days=1)]), "timedelta"), - (pd.Series(["a"], dtype="category"), "categorical"), + (pd.Series(["a"]), "string"), + (pd.Series([True, False]), "boolean"), + (pd.Series([datetime.now()]), "datetime"), + (pd.Series([timedelta(weeks=1)]), "duration"), + ( + pd.Series(["a", "b", "b", "c"], dtype="category"), + ("categorical", ["a", "b", "c"]), + ), + ( + pd.Series( + pd.Categorical( + ["Panda", "Polar", "Brown", "Brown", "Polar"], + categories=["Polar", "Panda", "Brown"], + ) + ), + ("categorical", ["Polar", "Panda", "Brown"]), + ), + ( + pd.Series( + pd.CategoricalIndex( + ["Panda", "Polar", "Brown", "Brown", "Polar"], + ) + ), + ("categorical", ["Brown", "Panda", "Polar"]), + ), + ( + pd.Series( + pd.CategoricalIndex( + ["Panda", "Polar", "Brown", "Brown", "Polar"], + categories=["Polar", "Panda", "Brown"], + ) + ), + ("categorical", ["Polar", "Panda", "Brown"]), + ), (pd.Series([{"x": 1}]), "object"), (pd.Series([h1("yo")]), "html"), (pd.Series([HTML("yo")]), "html"), @@ -172,10 +214,15 @@ def test_serialize_dtype( "pd.Series[Any]", pl.Series, ], - res_type: str, + res_type: str | tuple[str, list[str]], ): nw_ser = series_to_narwhals(ser) - assert serialize_dtype(nw_ser)["type"] == res_type + dtype_info = serialize_dtype(nw_ser) + ex_type = res_type if isinstance(res_type, str) else res_type[0] + assert dtype_info["type"] == ex_type + if dtype_info["type"] == "categorical": + assert isinstance(res_type, tuple) + assert dtype_info["categories"] == res_type[1] def test_serialize_frame(df_f: IntoDataFrame): @@ -185,11 +232,6 @@ def test_serialize_frame(df_f: IntoDataFrame): df_nw = as_data_frame(df_f) - # # TODO: pandas converts datetime entries to int, but Polars - # # preserves the datetime object. - # if isinstance(df_f, pl.DataFrame): - # pytest.xfail() - is_polars_backed = isinstance( nw.to_native(nw.from_native(df_f, eager_only=True)), pl.DataFrame ) @@ -201,7 +243,9 @@ def test_serialize_frame(df_f: IntoDataFrame): "num", "chr", "cat", + "bool", "dt", + "duration", "html", "html_str", "struct", @@ -213,7 +257,9 @@ def test_serialize_frame(df_f: IntoDataFrame): 1, "a", "a", - "2000-01-02T00:00:00", + True, + "2000-01-02T00:00:00" if is_polars_backed else "2000-01-02 00:00:00", + "7 days, 0:00:00" if is_polars_backed else "7 days 00:00:00", { "isShinyHtml": True, "obj": {"deps": [], "html": "span content"}, @@ -230,7 +276,9 @@ def test_serialize_frame(df_f: IntoDataFrame): 2, "b", "a", - "2000-01-02T00:00:00", + False, + "2000-01-02T00:00:00" if is_polars_backed else "2000-01-02 00:00:00", + "7 days, 0:00:00" if is_polars_backed else "7 days 00:00:00", { "isShinyHtml": True, "obj": {"deps": [], "html": "span content"}, @@ -248,7 +296,9 @@ def test_serialize_frame(df_f: IntoDataFrame): {"type": "numeric"}, {"type": "string"}, {"type": "string"}, + {"type": "boolean"}, {"type": "datetime"}, + {"type": "duration"}, {"type": "html"}, {"type": "html"}, # Polars doesn't have a way to represent a struct, @@ -299,3 +349,48 @@ def test_subset_frame_cols_single(small_df_f: IntoDataFrame): def test_shape(small_df_f: IntoDataFrame): assert frame_shape(small_df_f) == (2, 2) + + +def test_dtype_coverage(): + from pathlib import Path + + from narwhals import dtypes as nw_dtypes + + # Copy from https://github.com/narwhals-dev/narwhals/blob/2c9e2e7a308ebb30c6f672e27c1da2086ebbecbc/utils/check_api_reference.py#L144-L146 + dtype_names = [ + i + for i in cast(str, nw_dtypes.__dir__()) # pyright: ignore + if i[0].isupper() and not i.isupper() and i[0] != "_" + ] + + with open( + Path(__file__).parent.parent.parent # Repo root + / "shiny" + / "render" + / "_data_frame_utils" + / "_tbl_data.py" + ) as f: + tbl_data_lines = f.readlines() + + tbl_data_lines = [line for line in tbl_data_lines if "nw." in line] + + errs: list[str] = [] + + for dtype_name in dtype_names: + + if dtype_name in ("DType", "NumericType", "TemporalType", "Unknown"): + continue + + dtype_cls = getattr(nw_dtypes, dtype_name) + if not issubclass(dtype_cls, nw_dtypes.DType): + continue + + if dtype_cls.is_numeric(): + continue + + if f"nw.{dtype_name}()" in "".join(tbl_data_lines): + continue + + errs.append(f"Missing: {dtype_name}") + + assert not errs, "Missing narwhals dtype implementations:\n" + "\n".join(errs) From baed7f98db3377d61277dd8a3c26f018c27bf361 Mon Sep 17 00:00:00 2001 From: Barret Schloerke Date: Wed, 25 Sep 2024 17:27:48 -0400 Subject: [PATCH 39/87] Add more cell types to data frame js. Add test app for all types and content Boolean, object, and arr columns were broken --- js/data-frame/cell.tsx | 2 +- js/data-frame/index.tsx | 25 ++++++- js/data-frame/types.ts | 12 ++- shiny/www/py-shiny/data-frame/data-frame.js | 8 +- .../www/py-shiny/data-frame/data-frame.js.map | 6 +- .../shiny/components/data_frame/dtypes/app.py | 61 +++++++++++++++ .../data_frame/dtypes/test_df_dtypes.py | 75 +++++++++++++++++++ 7 files changed, 179 insertions(+), 10 deletions(-) create mode 100644 tests/playwright/shiny/components/data_frame/dtypes/app.py create mode 100644 tests/playwright/shiny/components/data_frame/dtypes/test_df_dtypes.py diff --git a/js/data-frame/cell.tsx b/js/data-frame/cell.tsx index 29d6d7293..ef427a393 100644 --- a/js/data-frame/cell.tsx +++ b/js/data-frame/cell.tsx @@ -64,7 +64,7 @@ type CellValue = string | CellHtmlValue | null; const getCellValueText = (cellValue: CellValue) => { if (isShinyHtml(cellValue)) return cellValue.obj.html; if (cellValue === null) return ""; - return cellValue as string; + return cellValue; }; interface TableBodyCellProps { diff --git a/js/data-frame/index.tsx b/js/data-frame/index.tsx index 4903939ae..9d4418b60 100644 --- a/js/data-frame/index.tsx +++ b/js/data-frame/index.tsx @@ -197,7 +197,30 @@ const ShinyDataGrid: FC> = ({ typeHint, }, cell: ({ getValue }) => { - return getValue() as string; + const ret = getValue(); + switch (typeHint?.type) { + // Return the value as is + case "numeric": + case "date": + case "datetime": + case "duration": + case "categorical": + case "html": + return ret; + // Convert the value to a string + case "string": + case "boolean": + return String(ret); + // Convert the value to a JSON string if it isn't a string already + case "unknown": + case "object": + if (typeof ret === "string") { + return ret; + } + return JSON.stringify(ret); + default: + return ret; + } }, enableSorting, }; diff --git a/js/data-frame/types.ts b/js/data-frame/types.ts index 8e95a46d4..72cb97814 100644 --- a/js/data-frame/types.ts +++ b/js/data-frame/types.ts @@ -9,7 +9,17 @@ export const EditModeEnum = { export type EditMode = ValueOf; export interface TypeHint { - type: "string" | "numeric" | "categorical" | "unknown" | "html"; + type: + | "string" + | "numeric" + | "boolean" + | "date" + | "datetime" + | "duration" + | "object" + | "unknown" + | "html" + | "categorical"; } export interface CategoricalTypeHint extends TypeHint { diff --git a/shiny/www/py-shiny/data-frame/data-frame.js b/shiny/www/py-shiny/data-frame/data-frame.js index 6d6bf9201..442b186c9 100644 --- a/shiny/www/py-shiny/data-frame/data-frame.js +++ b/shiny/www/py-shiny/data-frame/data-frame.js @@ -1,10 +1,10 @@ -var je,M,On,jo,Ee,Vn,Ln,xt,Pt,Mt,Ft,kn,Ke={},Hn=[],qo=/acit|ex(?:s|g|n|p|$)|rph|grid|ows|mnc|ntw|ine[ch]|zoo|^ord|itera/i,ot=Array.isArray;function he(e,n){for(var t in n)e[t]=n[t];return e}function An(e){var n=e.parentNode;n&&n.removeChild(e)}function J(e,n,t){var r,o,i,s={};for(i in n)i=="key"?r=n[i]:i=="ref"?o=n[i]:s[i]=n[i];if(arguments.length>2&&(s.children=arguments.length>3?je.call(arguments,2):t),typeof e=="function"&&e.defaultProps!=null)for(i in e.defaultProps)s[i]===void 0&&(s[i]=e.defaultProps[i]);return Ue(e,s,r,o,null)}function Ue(e,n,t,r,o){var i={type:e,props:n,key:t,ref:r,__k:null,__:null,__b:0,__e:null,__d:void 0,__c:null,constructor:void 0,__v:o??++On,__i:-1,__u:0};return o==null&&M.vnode!=null&&M.vnode(i),i}function Vt(){return{current:null}}function ue(e){return e.children}function ne(e,n){this.props=e,this.context=n}function Re(e,n){if(n==null)return e.__?Re(e.__,e.__i+1):null;for(var t;nn&&Ee.sort(xt));rt.__r=0}function zn(e,n,t,r,o,i,s,a,l,u,f){var c,g,d,p,h,_=r&&r.__k||Hn,m=n.length;for(t.__d=l,Wo(t,n,_),l=t.__d,c=0;c0?Ue(o.type,o.props,o.key,o.ref?o.ref:null,o.__v):o)!=null?(o.__=e,o.__b=e.__b+1,a=Xo(o,t,s,f),o.__i=a,i=null,a!==-1&&(f--,(i=t[a])&&(i.__u|=131072)),i==null||i.__v===null?(a==-1&&c--,typeof o.type!="function"&&(o.__u|=65536)):a!==s&&(a==s-1?c=a-s:a==s+1?c++:a>s?f>l-s?c+=a-s:c--:a(l!=null&&!(131072&l.__u)?1:0))for(;s>=0||a=0){if((l=n[s])&&!(131072&l.__u)&&o==l.key&&i===l.type)return s;s--}if(a2&&(a.children=arguments.length>3?je.call(arguments,2):t),Ue(e.type,a,r||e.key,o||e.ref,null)}function Lt(e,n){var t={__c:n="__cC"+kn++,__:e,Consumer:function(r,o){return r.children(o)},Provider:function(r){var o,i;return this.getChildContext||(o=[],(i={})[n]=this,this.getChildContext=function(){return i},this.componentWillUnmount=function(){o=null},this.shouldComponentUpdate=function(s){this.props.value!==s.value&&o.some(function(a){a.__e=!0,It(a)})},this.sub=function(s){o.push(s);var a=s.componentWillUnmount;s.componentWillUnmount=function(){o&&o.splice(o.indexOf(s),1),a&&a.call(s)}}),r.children}};return t.Provider.__=t.Consumer.contextType=t}je=Hn.slice,M={__e:function(e,n,t,r){for(var o,i,s;n=n.__;)if((o=n.__c)&&!o.__)try{if((i=o.constructor)&&i.getDerivedStateFromError!=null&&(o.setState(i.getDerivedStateFromError(e)),s=o.__d),o.componentDidCatch!=null&&(o.componentDidCatch(e,r||{}),s=o.__d),s)return o.__E=o}catch(a){e=a}throw e}},On=0,jo=function(e){return e!=null&&e.constructor==null},ne.prototype.setState=function(e,n){var t;t=this.__s!=null&&this.__s!==this.state?this.__s:this.__s=he({},this.state),typeof e=="function"&&(e=e(he({},t),this.props)),e&&he(t,e),e!=null&&this.__v&&(n&&this._sb.push(n),It(this))},ne.prototype.forceUpdate=function(e){this.__v&&(this.__e=!0,e&&this.__h.push(e),It(this))},ne.prototype.render=ue,Ee=[],Ln=typeof Promise=="function"?Promise.prototype.then.bind(Promise.resolve()):setTimeout,xt=function(e,n){return e.__v.__b-n.__v.__b},rt.__r=0,Pt=0,Mt=$n(!1),Ft=$n(!0),kn=0;var ve,O,kt,Kn,Te=0,Zn=[],k=M,jn=k.__b,qn=k.__r,Wn=k.diffed,Xn=k.__c,Yn=k.unmount,Jn=k.__;function Pe(e,n){k.__h&&k.__h(O,e,Te||n),Te=0;var t=O.__H||(O.__H={__:[],__h:[]});return e>=t.__.length&&t.__.push({}),t.__[e]}function H(e){return Te=1,be(er,e)}function be(e,n,t){var r=Pe(ve++,2);if(r.t=e,!r.__c&&(r.__=[t?t(n):er(void 0,n),function(a){var l=r.__N?r.__N[0]:r.__[0],u=r.t(l,a);l!==u&&(r.__N=[u,r.__[1]],r.__c.setState({}))}],r.__c=O,!O.u)){var o=function(a,l,u){if(!r.__c.__H)return!0;var f=r.__c.__H.__.filter(function(g){return!!g.__c});if(f.every(function(g){return!g.__N}))return!i||i.call(this,a,l,u);var c=!1;return f.forEach(function(g){if(g.__N){var d=g.__[0];g.__=g.__N,g.__N=void 0,d!==g.__[0]&&(c=!0)}}),!(!c&&r.__c.props===a)&&(!i||i.call(this,a,l,u))};O.u=!0;var i=O.shouldComponentUpdate,s=O.componentWillUpdate;O.componentWillUpdate=function(a,l,u){if(this.__e){var f=i;i=void 0,o(a,l,u),i=f}s&&s.call(this,a,l,u)},O.shouldComponentUpdate=o}return r.__N||r.__}function L(e,n){var t=Pe(ve++,3);!k.__s&&Bt(t.__H,n)&&(t.__=e,t.i=n,O.__H.__h.push(t))}function re(e,n){var t=Pe(ve++,4);!k.__s&&Bt(t.__H,n)&&(t.__=e,t.i=n,O.__h.push(t))}function X(e){return Te=5,oe(function(){return{current:e}},[])}function At(e,n,t){Te=6,re(function(){return typeof e=="function"?(e(n()),function(){return e(null)}):e?(e.current=n(),function(){return e.current=null}):void 0},t==null?t:t.concat(e))}function oe(e,n){var t=Pe(ve++,7);return Bt(t.__H,n)&&(t.__=e(),t.__H=n,t.__h=e),t.__}function Y(e,n){return Te=8,oe(function(){return e},n)}function Nt(e){var n=O.context[e.__c],t=Pe(ve++,9);return t.c=e,n?(t.__==null&&(t.__=!0,n.sub(O)),n.props.value):e.__}function zt(e,n){k.useDebugValue&&k.useDebugValue(n?n(e):e)}function Gt(){var e=Pe(ve++,11);if(!e.__){for(var n=O.__v;n!==null&&!n.__m&&n.__!==null;)n=n.__;var t=n.__m||(n.__m=[0,0]);e.__="P"+t[0]+"-"+t[1]++}return e.__}function Qo(){for(var e;e=Zn.shift();)if(e.__P&&e.__H)try{e.__H.__h.forEach(it),e.__H.__h.forEach(Ht),e.__H.__h=[]}catch(n){e.__H.__h=[],k.__e(n,e.__v)}}k.__b=function(e){O=null,jn&&jn(e)},k.__=function(e,n){e&&n.__k&&n.__k.__m&&(e.__m=n.__k.__m),Jn&&Jn(e,n)},k.__r=function(e){qn&&qn(e),ve=0;var n=(O=e.__c).__H;n&&(kt===O?(n.__h=[],O.__h=[],n.__.forEach(function(t){t.__N&&(t.__=t.__N),t.i=t.__N=void 0})):(n.__h.forEach(it),n.__h.forEach(Ht),n.__h=[],ve=0)),kt=O},k.diffed=function(e){Wn&&Wn(e);var n=e.__c;n&&n.__H&&(n.__H.__h.length&&(Zn.push(n)!==1&&Kn===k.requestAnimationFrame||((Kn=k.requestAnimationFrame)||Zo)(Qo)),n.__H.__.forEach(function(t){t.i&&(t.__H=t.i),t.i=void 0})),kt=O=null},k.__c=function(e,n){n.some(function(t){try{t.__h.forEach(it),t.__h=t.__h.filter(function(r){return!r.__||Ht(r)})}catch(r){n.some(function(o){o.__h&&(o.__h=[])}),n=[],k.__e(r,t.__v)}}),Xn&&Xn(e,n)},k.unmount=function(e){Yn&&Yn(e);var n,t=e.__c;t&&t.__H&&(t.__H.__.forEach(function(r){try{it(r)}catch(o){n=o}}),t.__H=void 0,n&&k.__e(n,t.__v))};var Qn=typeof requestAnimationFrame=="function";function Zo(e){var n,t=function(){clearTimeout(r),Qn&&cancelAnimationFrame(n),setTimeout(e)},r=setTimeout(t,100);Qn&&(n=requestAnimationFrame(t))}function it(e){var n=O,t=e.__c;typeof t=="function"&&(e.__c=void 0,t()),O=n}function Ht(e){var n=O;e.__c=e.__(),O=n}function Bt(e,n){return!e||e.length!==n.length||n.some(function(t,r){return t!==e[r]})}function er(e,n){return typeof n=="function"?n(e):n}function ur(e,n){for(var t in n)e[t]=n[t];return e}function Kt(e,n){for(var t in e)if(t!=="__source"&&!(t in n))return!0;for(var r in n)if(r!=="__source"&&e[r]!==n[r])return!0;return!1}function jt(e,n){this.props=e,this.context=n}function ei(e,n){function t(o){var i=this.props.ref,s=i==o.ref;return!s&&i&&(i.call?i(null):i.current=null),n?!n(this.props,o)||!s:Kt(this.props,o)}function r(o){return this.shouldComponentUpdate=t,J(e,o)}return r.displayName="Memo("+(e.displayName||e.name)+")",r.prototype.isReactComponent=!0,r.__f=!0,r}(jt.prototype=new ne).isPureReactComponent=!0,jt.prototype.shouldComponentUpdate=function(e,n){return Kt(this.props,e)||Kt(this.state,n)};var tr=M.__b;M.__b=function(e){e.type&&e.type.__f&&e.ref&&(e.props.ref=e.ref,e.ref=null),tr&&tr(e)};var ti=typeof Symbol<"u"&&Symbol.for&&Symbol.for("react.forward_ref")||3911;function ni(e){function n(t){var r=ur({},t);return delete r.ref,e(r,t.ref||null)}return n.$$typeof=ti,n.render=n,n.prototype.isReactComponent=n.__f=!0,n.displayName="ForwardRef("+(e.displayName||e.name)+")",n}var nr=function(e,n){return e==null?null:fe(fe(e).map(n))},ri={map:nr,forEach:nr,count:function(e){return e?fe(e).length:0},only:function(e){var n=fe(e);if(n.length!==1)throw"Children.only";return n[0]},toArray:fe},oi=M.__e;M.__e=function(e,n,t,r){if(e.then){for(var o,i=n;i=i.__;)if((o=i.__c)&&o.__c)return n.__e==null&&(n.__e=t.__e,n.__k=t.__k),o.__c(e,n)}oi(e,n,t,r)};var rr=M.unmount;function dr(e,n,t){return e&&(e.__c&&e.__c.__H&&(e.__c.__H.__.forEach(function(r){typeof r.__c=="function"&&r.__c()}),e.__c.__H=null),(e=ur({},e)).__c!=null&&(e.__c.__P===t&&(e.__c.__P=n),e.__c=null),e.__k=e.__k&&e.__k.map(function(r){return dr(r,n,t)})),e}function cr(e,n,t){return e&&t&&(e.__v=null,e.__k=e.__k&&e.__k.map(function(r){return cr(r,n,t)}),e.__c&&e.__c.__P===n&&(e.__e&&t.appendChild(e.__e),e.__c.__e=!0,e.__c.__P=t)),e}function st(){this.__u=0,this.t=null,this.__b=null}function fr(e){var n=e.__.__c;return n&&n.__a&&n.__a(e)}function ii(e){var n,t,r;function o(i){if(n||(n=e()).then(function(s){t=s.default||s},function(s){r=s}),r)throw r;if(!t)throw n;return J(t,i)}return o.displayName="Lazy",o.__f=!0,o}function qe(){this.u=null,this.o=null}M.unmount=function(e){var n=e.__c;n&&n.__R&&n.__R(),n&&32&e.__u&&(e.type=null),rr&&rr(e)},(st.prototype=new ne).__c=function(e,n){var t=n.__c,r=this;r.t==null&&(r.t=[]),r.t.push(t);var o=fr(r.__v),i=!1,s=function(){i||(i=!0,t.__R=null,o?o(a):a())};t.__R=s;var a=function(){if(!--r.__u){if(r.state.__a){var l=r.state.__a;r.__v.__k[0]=cr(l,l.__c.__P,l.__c.__O)}var u;for(r.setState({__a:r.__b=null});u=r.t.pop();)u.forceUpdate()}};r.__u++||32&n.__u||r.setState({__a:r.__b=r.__v.__k[0]}),e.then(s,s)},st.prototype.componentWillUnmount=function(){this.t=[]},st.prototype.render=function(e,n){if(this.__b){if(this.__v.__k){var t=document.createElement("div"),r=this.__v.__k[0].__c;this.__v.__k[0]=dr(this.__b,t,r.__O=r.__P)}this.__b=null}var o=n.__a&&J(ue,null,e.fallback);return o&&(o.__u&=-33),[J(ue,null,n.__a?null:e.children),o]};var or=function(e,n,t){if(++t[1]===t[0]&&e.o.delete(n),e.props.revealOrder&&(e.props.revealOrder[0]!=="t"||!e.o.size))for(t=e.u;t;){for(;t.length>3;)t.pop()();if(t[1]>>1,1),n.i.removeChild(r)}}),Ie(J(si,{context:n.context},e.__v),n.l)}function ai(e,n){var t=J(li,{__v:e,i:n});return t.containerInfo=n,t}(qe.prototype=new ne).__a=function(e){var n=this,t=fr(n.__v),r=n.o.get(e);return r[0]++,function(o){var i=function(){n.props.revealOrder?(r.push(o),or(n,e,r)):o()};t?t(i):i()}},qe.prototype.render=function(e){this.u=null,this.o=new Map;var n=fe(e.children);e.revealOrder&&e.revealOrder[0]==="b"&&n.reverse();for(var t=n.length;t--;)this.o.set(n[t],this.u=[1,0,this.u]);return e.children},qe.prototype.componentDidUpdate=qe.prototype.componentDidMount=function(){var e=this;this.o.forEach(function(n,t){or(e,t,n)})};var gr=typeof Symbol<"u"&&Symbol.for&&Symbol.for("react.element")||60103,ui=/^(?:accent|alignment|arabic|baseline|cap|clip(?!PathU)|color|dominant|fill|flood|font|glyph(?!R)|horiz|image(!S)|letter|lighting|marker(?!H|W|U)|overline|paint|pointer|shape|stop|strikethrough|stroke|text(?!L)|transform|underline|unicode|units|v|vector|vert|word|writing|x(?!C))[A-Z]/,di=/^on(Ani|Tra|Tou|BeforeInp|Compo)/,ci=/[A-Z0-9]/g,fi=typeof document<"u",gi=function(e){return(typeof Symbol<"u"&&typeof Symbol()=="symbol"?/fil|che|rad/:/fil|che|ra/).test(e)};function qt(e,n,t){return n.__k==null&&(n.textContent=""),Ie(e,n),typeof t=="function"&&t(),e?e.__c:null}function pr(e,n,t){return Ot(e,n),typeof t=="function"&&t(),e?e.__c:null}ne.prototype.isReactComponent={},["componentWillMount","componentWillReceiveProps","componentWillUpdate"].forEach(function(e){Object.defineProperty(ne.prototype,e,{configurable:!0,get:function(){return this["UNSAFE_"+e]},set:function(n){Object.defineProperty(this,e,{configurable:!0,writable:!0,value:n})}})});var ir=M.event;function pi(){}function hi(){return this.cancelBubble}function mi(){return this.defaultPrevented}M.event=function(e){return ir&&(e=ir(e)),e.persist=pi,e.isPropagationStopped=hi,e.isDefaultPrevented=mi,e.nativeEvent=e};var Wt,_i={enumerable:!1,configurable:!0,get:function(){return this.class}},sr=M.vnode;M.vnode=function(e){typeof e.type=="string"&&function(n){var t=n.props,r=n.type,o={};for(var i in t){var s=t[i];if(!(i==="value"&&"defaultValue"in t&&s==null||fi&&i==="children"&&r==="noscript"||i==="class"||i==="className")){var a=i.toLowerCase();i==="defaultValue"&&"value"in t&&t.value==null?i="value":i==="download"&&s===!0?s="":a==="translate"&&s==="no"?s=!1:a==="ondoubleclick"?i="ondblclick":a!=="onchange"||r!=="input"&&r!=="textarea"||gi(t.type)?a==="onfocus"?i="onfocusin":a==="onblur"?i="onfocusout":di.test(i)?i=a:r.indexOf("-")===-1&&ui.test(i)?i=i.replace(ci,"-$&").toLowerCase():s===null&&(s=void 0):a=i="oninput",a==="oninput"&&o[i=a]&&(i="oninputCapture"),o[i]=s}}r=="select"&&o.multiple&&Array.isArray(o.value)&&(o.value=fe(t.children).forEach(function(l){l.props.selected=o.value.indexOf(l.props.value)!=-1})),r=="select"&&o.defaultValue!=null&&(o.value=fe(t.children).forEach(function(l){l.props.selected=o.multiple?o.defaultValue.indexOf(l.props.value)!=-1:o.defaultValue==l.props.value})),t.class&&!t.className?(o.class=t.class,Object.defineProperty(o,"className",_i)):(t.className&&!t.class||t.class&&t.className)&&(o.class=o.className=t.className),n.props=o}(e),e.$$typeof=gr,sr&&sr(e)};var lr=M.__r;M.__r=function(e){lr&&lr(e),Wt=e.__c};var ar=M.diffed;M.diffed=function(e){ar&&ar(e);var n=e.props,t=e.__e;t!=null&&e.type==="textarea"&&"value"in n&&n.value!==t.value&&(t.value=n.value==null?"":n.value),Wt=null};var yi={ReactCurrentDispatcher:{current:{readContext:function(e){return Wt.__n[e.__c].props.value},useCallback:Y,useContext:Nt,useDebugValue:zt,useDeferredValue:mr,useEffect:L,useId:Gt,useImperativeHandle:At,useInsertionEffect:yr,useLayoutEffect:re,useMemo:oe,useReducer:be,useRef:X,useState:H,useSyncExternalStore:vr,useTransition:_r}}};function vi(e){return J.bind(null,e)}function lt(e){return!!e&&e.$$typeof===gr}function Si(e){return lt(e)&&e.type===ue}function wi(e){return!!e&&!!e.displayName&&(typeof e.displayName=="string"||e.displayName instanceof String)&&e.displayName.startsWith("Memo(")}function Ci(e){return lt(e)?Un.apply(null,arguments):e}function Xt(e){return!!e.__k&&(Ie(null,e),!0)}function Ei(e){return e&&(e.base||e.nodeType===1&&e)||null}var Ri=function(e,n){return e(n)},Yt=function(e,n){return e(n)},Jt=ue;function hr(e){e()}function mr(e){return e}function _r(){return[!1,hr]}var yr=re,bi=lt;function vr(e,n){var t=n(),r=H({h:{__:t,v:n}}),o=r[0].h,i=r[1];return re(function(){o.__=t,o.v=n,Ut(o)&&i({h:o})},[e,t,n]),L(function(){return Ut(o)&&i({h:o}),e(function(){Ut(o)&&i({h:o})})},[e]),t}function Ut(e){var n,t,r=e.v,o=e.__;try{var i=r();return!((n=o)===(t=i)&&(n!==0||1/n==1/t)||n!=n&&t!=t)}catch{return!0}}var b={useState:H,useId:Gt,useReducer:be,useEffect:L,useLayoutEffect:re,useInsertionEffect:yr,useTransition:_r,useDeferredValue:mr,useSyncExternalStore:vr,startTransition:hr,useRef:X,useImperativeHandle:At,useMemo:oe,useCallback:Y,useContext:Nt,useDebugValue:zt,version:"17.0.2",Children:ri,render:qt,hydrate:pr,unmountComponentAtNode:Xt,createPortal:ai,createElement:J,createContext:Lt,createFactory:vi,cloneElement:Ci,createRef:Vt,Fragment:ue,isValidElement:lt,isElement:bi,isFragment:Si,isMemo:wi,findDOMNode:Ei,Component:ne,PureComponent:jt,memo:ei,forwardRef:ni,flushSync:Yt,unstable_batchedUpdates:Ri,StrictMode:Jt,Suspense:st,SuspenseList:qe,lazy:ii,__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED:yi};function Se(e,n){return typeof e=="function"?e(n):e}function Q(e,n){return t=>{n.setState(r=>({...r,[e]:Se(t,r[e])}))}}function ct(e){return e instanceof Function}function xi(e){return Array.isArray(e)&&e.every(n=>typeof n=="number")}function Mi(e,n){let t=[],r=o=>{o.forEach(i=>{t.push(i);let s=n(i);s!=null&&s.length&&r(s)})};return r(e),t}function w(e,n,t){let r=[],o;return i=>{let s;t.key&&t.debug&&(s=Date.now());let a=e(i);if(!(a.length!==r.length||a.some((f,c)=>r[c]!==f)))return o;r=a;let u;if(t.key&&t.debug&&(u=Date.now()),o=n(...a),t==null||t.onChange==null||t.onChange(o),t.key&&t.debug&&t!=null&&t.debug()){let f=Math.round((Date.now()-s)*100)/100,c=Math.round((Date.now()-u)*100)/100,g=c/16,d=(p,h)=>{for(p=String(p);p.length2&&(s.children=arguments.length>3?qe.call(arguments,2):t),typeof e=="function"&&e.defaultProps!=null)for(i in e.defaultProps)s[i]===void 0&&(s[i]=e.defaultProps[i]);return Ke(e,s,r,o,null)}function Ke(e,n,t,r,o){var i={type:e,props:n,key:t,ref:r,__k:null,__:null,__b:0,__e:null,__d:void 0,__c:null,constructor:void 0,__v:o??++Ln,__i:-1,__u:0};return o==null&&M.vnode!=null&&M.vnode(i),i}function Dt(){return{current:null}}function ue(e){return e.children}function ne(e,n){this.props=e,this.context=n}function be(e,n){if(n==null)return e.__?be(e.__,e.__i+1):null;for(var t;nn&&Re.sort(Mt));ot.__r=0}function Gn(e,n,t,r,o,i,s,a,l,u,f){var c,g,d,p,m,_=r&&r.__k||An,h=n.length;for(t.__d=l,Wo(t,n,_),l=t.__d,c=0;c0?Ke(o.type,o.props,o.key,o.ref?o.ref:null,o.__v):o)!=null?(o.__=e,o.__b=e.__b+1,a=Xo(o,t,s,f),o.__i=a,i=null,a!==-1&&(f--,(i=t[a])&&(i.__u|=131072)),i==null||i.__v===null?(a==-1&&c--,typeof o.type!="function"&&(o.__u|=65536)):a!==s&&(a==s-1?c=a-s:a==s+1?c++:a>s?f>l-s?c+=a-s:c--:a(l!=null&&!(131072&l.__u)?1:0))for(;s>=0||a=0){if((l=n[s])&&!(131072&l.__u)&&o==l.key&&i===l.type)return s;s--}if(a2&&(a.children=arguments.length>3?qe.call(arguments,2):t),Ke(e.type,a,r||e.key,o||e.ref,null)}function kt(e,n){var t={__c:n="__cC"+Hn++,__:e,Consumer:function(r,o){return r.children(o)},Provider:function(r){var o,i;return this.getChildContext||(o=[],(i={})[n]=this,this.getChildContext=function(){return i},this.componentWillUnmount=function(){o=null},this.shouldComponentUpdate=function(s){this.props.value!==s.value&&o.some(function(a){a.__e=!0,Tt(a)})},this.sub=function(s){o.push(s);var a=s.componentWillUnmount;s.componentWillUnmount=function(){o&&o.splice(o.indexOf(s),1),a&&a.call(s)}}),r.children}};return t.Provider.__=t.Consumer.contextType=t}qe=An.slice,M={__e:function(e,n,t,r){for(var o,i,s;n=n.__;)if((o=n.__c)&&!o.__)try{if((i=o.constructor)&&i.getDerivedStateFromError!=null&&(o.setState(i.getDerivedStateFromError(e)),s=o.__d),o.componentDidCatch!=null&&(o.componentDidCatch(e,r||{}),s=o.__d),s)return o.__E=o}catch(a){e=a}throw e}},Ln=0,jo=function(e){return e!=null&&e.constructor==null},ne.prototype.setState=function(e,n){var t;t=this.__s!=null&&this.__s!==this.state?this.__s:this.__s=me({},this.state),typeof e=="function"&&(e=e(me({},t),this.props)),e&&me(t,e),e!=null&&this.__v&&(n&&this._sb.push(n),Tt(this))},ne.prototype.forceUpdate=function(e){this.__v&&(this.__e=!0,e&&this.__h.push(e),Tt(this))},ne.prototype.render=ue,Re=[],kn=typeof Promise=="function"?Promise.prototype.then.bind(Promise.resolve()):setTimeout,Mt=function(e,n){return e.__v.__b-n.__v.__b},ot.__r=0,Vt=0,Ft=On(!1),It=On(!0),Hn=0;var Se,O,Ht,jn,Pe=0,er=[],k=M,qn=k.__b,Wn=k.__r,Xn=k.diffed,Yn=k.__c,Jn=k.unmount,Qn=k.__;function Ve(e,n){k.__h&&k.__h(O,e,Pe||n),Pe=0;var t=O.__H||(O.__H={__:[],__h:[]});return e>=t.__.length&&t.__.push({}),t.__[e]}function H(e){return Pe=1,xe(tr,e)}function xe(e,n,t){var r=Ve(Se++,2);if(r.t=e,!r.__c&&(r.__=[t?t(n):tr(void 0,n),function(a){var l=r.__N?r.__N[0]:r.__[0],u=r.t(l,a);l!==u&&(r.__N=[u,r.__[1]],r.__c.setState({}))}],r.__c=O,!O.u)){var o=function(a,l,u){if(!r.__c.__H)return!0;var f=r.__c.__H.__.filter(function(g){return!!g.__c});if(f.every(function(g){return!g.__N}))return!i||i.call(this,a,l,u);var c=!1;return f.forEach(function(g){if(g.__N){var d=g.__[0];g.__=g.__N,g.__N=void 0,d!==g.__[0]&&(c=!0)}}),!(!c&&r.__c.props===a)&&(!i||i.call(this,a,l,u))};O.u=!0;var i=O.shouldComponentUpdate,s=O.componentWillUpdate;O.componentWillUpdate=function(a,l,u){if(this.__e){var f=i;i=void 0,o(a,l,u),i=f}s&&s.call(this,a,l,u)},O.shouldComponentUpdate=o}return r.__N||r.__}function L(e,n){var t=Ve(Se++,3);!k.__s&&Ut(t.__H,n)&&(t.__=e,t.i=n,O.__H.__h.push(t))}function re(e,n){var t=Ve(Se++,4);!k.__s&&Ut(t.__H,n)&&(t.__=e,t.i=n,O.__h.push(t))}function X(e){return Pe=5,oe(function(){return{current:e}},[])}function Nt(e,n,t){Pe=6,re(function(){return typeof e=="function"?(e(n()),function(){return e(null)}):e?(e.current=n(),function(){return e.current=null}):void 0},t==null?t:t.concat(e))}function oe(e,n){var t=Ve(Se++,7);return Ut(t.__H,n)&&(t.__=e(),t.__H=n,t.__h=e),t.__}function Y(e,n){return Pe=8,oe(function(){return e},n)}function zt(e){var n=O.context[e.__c],t=Ve(Se++,9);return t.c=e,n?(t.__==null&&(t.__=!0,n.sub(O)),n.props.value):e.__}function Gt(e,n){k.useDebugValue&&k.useDebugValue(n?n(e):e)}function Bt(){var e=Ve(Se++,11);if(!e.__){for(var n=O.__v;n!==null&&!n.__m&&n.__!==null;)n=n.__;var t=n.__m||(n.__m=[0,0]);e.__="P"+t[0]+"-"+t[1]++}return e.__}function Qo(){for(var e;e=er.shift();)if(e.__P&&e.__H)try{e.__H.__h.forEach(st),e.__H.__h.forEach(At),e.__H.__h=[]}catch(n){e.__H.__h=[],k.__e(n,e.__v)}}k.__b=function(e){O=null,qn&&qn(e)},k.__=function(e,n){e&&n.__k&&n.__k.__m&&(e.__m=n.__k.__m),Qn&&Qn(e,n)},k.__r=function(e){Wn&&Wn(e),Se=0;var n=(O=e.__c).__H;n&&(Ht===O?(n.__h=[],O.__h=[],n.__.forEach(function(t){t.__N&&(t.__=t.__N),t.i=t.__N=void 0})):(n.__h.forEach(st),n.__h.forEach(At),n.__h=[],Se=0)),Ht=O},k.diffed=function(e){Xn&&Xn(e);var n=e.__c;n&&n.__H&&(n.__H.__h.length&&(er.push(n)!==1&&jn===k.requestAnimationFrame||((jn=k.requestAnimationFrame)||Zo)(Qo)),n.__H.__.forEach(function(t){t.i&&(t.__H=t.i),t.i=void 0})),Ht=O=null},k.__c=function(e,n){n.some(function(t){try{t.__h.forEach(st),t.__h=t.__h.filter(function(r){return!r.__||At(r)})}catch(r){n.some(function(o){o.__h&&(o.__h=[])}),n=[],k.__e(r,t.__v)}}),Yn&&Yn(e,n)},k.unmount=function(e){Jn&&Jn(e);var n,t=e.__c;t&&t.__H&&(t.__H.__.forEach(function(r){try{st(r)}catch(o){n=o}}),t.__H=void 0,n&&k.__e(n,t.__v))};var Zn=typeof requestAnimationFrame=="function";function Zo(e){var n,t=function(){clearTimeout(r),Zn&&cancelAnimationFrame(n),setTimeout(e)},r=setTimeout(t,100);Zn&&(n=requestAnimationFrame(t))}function st(e){var n=O,t=e.__c;typeof t=="function"&&(e.__c=void 0,t()),O=n}function At(e){var n=O;e.__c=e.__(),O=n}function Ut(e,n){return!e||e.length!==n.length||n.some(function(t,r){return t!==e[r]})}function tr(e,n){return typeof n=="function"?n(e):n}function dr(e,n){for(var t in n)e[t]=n[t];return e}function jt(e,n){for(var t in e)if(t!=="__source"&&!(t in n))return!0;for(var r in n)if(r!=="__source"&&e[r]!==n[r])return!0;return!1}function qt(e,n){this.props=e,this.context=n}function ei(e,n){function t(o){var i=this.props.ref,s=i==o.ref;return!s&&i&&(i.call?i(null):i.current=null),n?!n(this.props,o)||!s:jt(this.props,o)}function r(o){return this.shouldComponentUpdate=t,J(e,o)}return r.displayName="Memo("+(e.displayName||e.name)+")",r.prototype.isReactComponent=!0,r.__f=!0,r}(qt.prototype=new ne).isPureReactComponent=!0,qt.prototype.shouldComponentUpdate=function(e,n){return jt(this.props,e)||jt(this.state,n)};var nr=M.__b;M.__b=function(e){e.type&&e.type.__f&&e.ref&&(e.props.ref=e.ref,e.ref=null),nr&&nr(e)};var ti=typeof Symbol<"u"&&Symbol.for&&Symbol.for("react.forward_ref")||3911;function ni(e){function n(t){var r=dr({},t);return delete r.ref,e(r,t.ref||null)}return n.$$typeof=ti,n.render=n,n.prototype.isReactComponent=n.__f=!0,n.displayName="ForwardRef("+(e.displayName||e.name)+")",n}var rr=function(e,n){return e==null?null:fe(fe(e).map(n))},ri={map:rr,forEach:rr,count:function(e){return e?fe(e).length:0},only:function(e){var n=fe(e);if(n.length!==1)throw"Children.only";return n[0]},toArray:fe},oi=M.__e;M.__e=function(e,n,t,r){if(e.then){for(var o,i=n;i=i.__;)if((o=i.__c)&&o.__c)return n.__e==null&&(n.__e=t.__e,n.__k=t.__k),o.__c(e,n)}oi(e,n,t,r)};var or=M.unmount;function cr(e,n,t){return e&&(e.__c&&e.__c.__H&&(e.__c.__H.__.forEach(function(r){typeof r.__c=="function"&&r.__c()}),e.__c.__H=null),(e=dr({},e)).__c!=null&&(e.__c.__P===t&&(e.__c.__P=n),e.__c=null),e.__k=e.__k&&e.__k.map(function(r){return cr(r,n,t)})),e}function fr(e,n,t){return e&&t&&(e.__v=null,e.__k=e.__k&&e.__k.map(function(r){return fr(r,n,t)}),e.__c&&e.__c.__P===n&&(e.__e&&t.appendChild(e.__e),e.__c.__e=!0,e.__c.__P=t)),e}function lt(){this.__u=0,this.t=null,this.__b=null}function gr(e){var n=e.__.__c;return n&&n.__a&&n.__a(e)}function ii(e){var n,t,r;function o(i){if(n||(n=e()).then(function(s){t=s.default||s},function(s){r=s}),r)throw r;if(!t)throw n;return J(t,i)}return o.displayName="Lazy",o.__f=!0,o}function We(){this.u=null,this.o=null}M.unmount=function(e){var n=e.__c;n&&n.__R&&n.__R(),n&&32&e.__u&&(e.type=null),or&&or(e)},(lt.prototype=new ne).__c=function(e,n){var t=n.__c,r=this;r.t==null&&(r.t=[]),r.t.push(t);var o=gr(r.__v),i=!1,s=function(){i||(i=!0,t.__R=null,o?o(a):a())};t.__R=s;var a=function(){if(!--r.__u){if(r.state.__a){var l=r.state.__a;r.__v.__k[0]=fr(l,l.__c.__P,l.__c.__O)}var u;for(r.setState({__a:r.__b=null});u=r.t.pop();)u.forceUpdate()}};r.__u++||32&n.__u||r.setState({__a:r.__b=r.__v.__k[0]}),e.then(s,s)},lt.prototype.componentWillUnmount=function(){this.t=[]},lt.prototype.render=function(e,n){if(this.__b){if(this.__v.__k){var t=document.createElement("div"),r=this.__v.__k[0].__c;this.__v.__k[0]=cr(this.__b,t,r.__O=r.__P)}this.__b=null}var o=n.__a&&J(ue,null,e.fallback);return o&&(o.__u&=-33),[J(ue,null,n.__a?null:e.children),o]};var ir=function(e,n,t){if(++t[1]===t[0]&&e.o.delete(n),e.props.revealOrder&&(e.props.revealOrder[0]!=="t"||!e.o.size))for(t=e.u;t;){for(;t.length>3;)t.pop()();if(t[1]>>1,1),n.i.removeChild(r)}}),Te(J(si,{context:n.context},e.__v),n.l)}function ai(e,n){var t=J(li,{__v:e,i:n});return t.containerInfo=n,t}(We.prototype=new ne).__a=function(e){var n=this,t=gr(n.__v),r=n.o.get(e);return r[0]++,function(o){var i=function(){n.props.revealOrder?(r.push(o),ir(n,e,r)):o()};t?t(i):i()}},We.prototype.render=function(e){this.u=null,this.o=new Map;var n=fe(e.children);e.revealOrder&&e.revealOrder[0]==="b"&&n.reverse();for(var t=n.length;t--;)this.o.set(n[t],this.u=[1,0,this.u]);return e.children},We.prototype.componentDidUpdate=We.prototype.componentDidMount=function(){var e=this;this.o.forEach(function(n,t){ir(e,t,n)})};var pr=typeof Symbol<"u"&&Symbol.for&&Symbol.for("react.element")||60103,ui=/^(?:accent|alignment|arabic|baseline|cap|clip(?!PathU)|color|dominant|fill|flood|font|glyph(?!R)|horiz|image(!S)|letter|lighting|marker(?!H|W|U)|overline|paint|pointer|shape|stop|strikethrough|stroke|text(?!L)|transform|underline|unicode|units|v|vector|vert|word|writing|x(?!C))[A-Z]/,di=/^on(Ani|Tra|Tou|BeforeInp|Compo)/,ci=/[A-Z0-9]/g,fi=typeof document<"u",gi=function(e){return(typeof Symbol<"u"&&typeof Symbol()=="symbol"?/fil|che|rad/:/fil|che|ra/).test(e)};function Wt(e,n,t){return n.__k==null&&(n.textContent=""),Te(e,n),typeof t=="function"&&t(),e?e.__c:null}function mr(e,n,t){return Lt(e,n),typeof t=="function"&&t(),e?e.__c:null}ne.prototype.isReactComponent={},["componentWillMount","componentWillReceiveProps","componentWillUpdate"].forEach(function(e){Object.defineProperty(ne.prototype,e,{configurable:!0,get:function(){return this["UNSAFE_"+e]},set:function(n){Object.defineProperty(this,e,{configurable:!0,writable:!0,value:n})}})});var sr=M.event;function pi(){}function mi(){return this.cancelBubble}function hi(){return this.defaultPrevented}M.event=function(e){return sr&&(e=sr(e)),e.persist=pi,e.isPropagationStopped=mi,e.isDefaultPrevented=hi,e.nativeEvent=e};var Xt,_i={enumerable:!1,configurable:!0,get:function(){return this.class}},lr=M.vnode;M.vnode=function(e){typeof e.type=="string"&&function(n){var t=n.props,r=n.type,o={};for(var i in t){var s=t[i];if(!(i==="value"&&"defaultValue"in t&&s==null||fi&&i==="children"&&r==="noscript"||i==="class"||i==="className")){var a=i.toLowerCase();i==="defaultValue"&&"value"in t&&t.value==null?i="value":i==="download"&&s===!0?s="":a==="translate"&&s==="no"?s=!1:a==="ondoubleclick"?i="ondblclick":a!=="onchange"||r!=="input"&&r!=="textarea"||gi(t.type)?a==="onfocus"?i="onfocusin":a==="onblur"?i="onfocusout":di.test(i)?i=a:r.indexOf("-")===-1&&ui.test(i)?i=i.replace(ci,"-$&").toLowerCase():s===null&&(s=void 0):a=i="oninput",a==="oninput"&&o[i=a]&&(i="oninputCapture"),o[i]=s}}r=="select"&&o.multiple&&Array.isArray(o.value)&&(o.value=fe(t.children).forEach(function(l){l.props.selected=o.value.indexOf(l.props.value)!=-1})),r=="select"&&o.defaultValue!=null&&(o.value=fe(t.children).forEach(function(l){l.props.selected=o.multiple?o.defaultValue.indexOf(l.props.value)!=-1:o.defaultValue==l.props.value})),t.class&&!t.className?(o.class=t.class,Object.defineProperty(o,"className",_i)):(t.className&&!t.class||t.class&&t.className)&&(o.class=o.className=t.className),n.props=o}(e),e.$$typeof=pr,lr&&lr(e)};var ar=M.__r;M.__r=function(e){ar&&ar(e),Xt=e.__c};var ur=M.diffed;M.diffed=function(e){ur&&ur(e);var n=e.props,t=e.__e;t!=null&&e.type==="textarea"&&"value"in n&&n.value!==t.value&&(t.value=n.value==null?"":n.value),Xt=null};var yi={ReactCurrentDispatcher:{current:{readContext:function(e){return Xt.__n[e.__c].props.value},useCallback:Y,useContext:zt,useDebugValue:Gt,useDeferredValue:_r,useEffect:L,useId:Bt,useImperativeHandle:Nt,useInsertionEffect:vr,useLayoutEffect:re,useMemo:oe,useReducer:xe,useRef:X,useState:H,useSyncExternalStore:Sr,useTransition:yr}}};function vi(e){return J.bind(null,e)}function at(e){return!!e&&e.$$typeof===pr}function Si(e){return at(e)&&e.type===ue}function wi(e){return!!e&&!!e.displayName&&(typeof e.displayName=="string"||e.displayName instanceof String)&&e.displayName.startsWith("Memo(")}function Ci(e){return at(e)?Kn.apply(null,arguments):e}function Yt(e){return!!e.__k&&(Te(null,e),!0)}function Ei(e){return e&&(e.base||e.nodeType===1&&e)||null}var Ri=function(e,n){return e(n)},Jt=function(e,n){return e(n)},Qt=ue;function hr(e){e()}function _r(e){return e}function yr(){return[!1,hr]}var vr=re,bi=at;function Sr(e,n){var t=n(),r=H({h:{__:t,v:n}}),o=r[0].h,i=r[1];return re(function(){o.__=t,o.v=n,Kt(o)&&i({h:o})},[e,t,n]),L(function(){return Kt(o)&&i({h:o}),e(function(){Kt(o)&&i({h:o})})},[e]),t}function Kt(e){var n,t,r=e.v,o=e.__;try{var i=r();return!((n=o)===(t=i)&&(n!==0||1/n==1/t)||n!=n&&t!=t)}catch{return!0}}var b={useState:H,useId:Bt,useReducer:xe,useEffect:L,useLayoutEffect:re,useInsertionEffect:vr,useTransition:yr,useDeferredValue:_r,useSyncExternalStore:Sr,startTransition:hr,useRef:X,useImperativeHandle:Nt,useMemo:oe,useCallback:Y,useContext:zt,useDebugValue:Gt,version:"17.0.2",Children:ri,render:Wt,hydrate:mr,unmountComponentAtNode:Yt,createPortal:ai,createElement:J,createContext:kt,createFactory:vi,cloneElement:Ci,createRef:Dt,Fragment:ue,isValidElement:at,isElement:bi,isFragment:Si,isMemo:wi,findDOMNode:Ei,Component:ne,PureComponent:qt,memo:ei,forwardRef:ni,flushSync:Jt,unstable_batchedUpdates:Ri,StrictMode:Qt,Suspense:lt,SuspenseList:We,lazy:ii,__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED:yi};function we(e,n){return typeof e=="function"?e(n):e}function Q(e,n){return t=>{n.setState(r=>({...r,[e]:we(t,r[e])}))}}function ft(e){return e instanceof Function}function xi(e){return Array.isArray(e)&&e.every(n=>typeof n=="number")}function Mi(e,n){let t=[],r=o=>{o.forEach(i=>{t.push(i);let s=n(i);s!=null&&s.length&&r(s)})};return r(e),t}function w(e,n,t){let r=[],o;return i=>{let s;t.key&&t.debug&&(s=Date.now());let a=e(i);if(!(a.length!==r.length||a.some((f,c)=>r[c]!==f)))return o;r=a;let u;if(t.key&&t.debug&&(u=Date.now()),o=n(...a),t==null||t.onChange==null||t.onChange(o),t.key&&t.debug&&t!=null&&t.debug()){let f=Math.round((Date.now()-s)*100)/100,c=Math.round((Date.now()-u)*100)/100,g=c/16,d=(p,m)=>{for(p=String(p);p.length{var o;return(o=e?.debugAll)!=null?o:e[n]},key:!1,onChange:r}}function Fi(e,n,t,r){let o=()=>{var s;return(s=i.getValue())!=null?s:e.options.renderFallbackValue},i={id:`${n.id}_${t.id}`,row:n,column:t,getValue:()=>n.getValue(r),renderValue:o,getContext:w(()=>[e,t,n,i],(s,a,l,u)=>({table:s,column:a,row:l,cell:u,getValue:u.getValue,renderValue:u.renderValue}),C(e.options,"debugCells","cell.getContext"))};return e._features.forEach(s=>{s.createCell==null||s.createCell(i,t,n,e)},{}),i}function Ii(e,n,t,r){var o,i;let a={...e._getDefaultColumnDef(),...n},l=a.accessorKey,u=(o=(i=a.id)!=null?i:l?l.replace(".","_"):void 0)!=null?o:typeof a.header=="string"?a.header:void 0,f;if(a.accessorFn?f=a.accessorFn:l&&(l.includes(".")?f=g=>{let d=g;for(let h of l.split(".")){var p;d=(p=d)==null?void 0:p[h]}return d}:f=g=>g[a.accessorKey]),!u)throw new Error;let c={id:`${String(u)}`,accessorFn:f,parent:r,depth:t,columnDef:a,columns:[],getFlatColumns:w(()=>[!0],()=>{var g;return[c,...(g=c.columns)==null?void 0:g.flatMap(d=>d.getFlatColumns())]},C(e.options,"debugColumns","column.getFlatColumns")),getLeafColumns:w(()=>[e._getOrderColumnsFn()],g=>{var d;if((d=c.columns)!=null&&d.length){let p=c.columns.flatMap(h=>h.getLeafColumns());return g(p)}return[c]},C(e.options,"debugColumns","column.getLeafColumns"))};for(let g of e._features)g.createColumn==null||g.createColumn(c,e);return c}var j="debugHeaders";function wr(e,n,t){var r;let i={id:(r=t.id)!=null?r:n.id,column:n,index:t.index,isPlaceholder:!!t.isPlaceholder,placeholderId:t.placeholderId,depth:t.depth,subHeaders:[],colSpan:0,rowSpan:0,headerGroup:null,getLeafHeaders:()=>{let s=[],a=l=>{l.subHeaders&&l.subHeaders.length&&l.subHeaders.map(a),s.push(l)};return a(i),s},getContext:()=>({table:e,header:i,column:n})};return e._features.forEach(s=>{s.createHeader==null||s.createHeader(i,e)}),i}var Ti={createTable:e=>{e.getHeaderGroups=w(()=>[e.getAllColumns(),e.getVisibleLeafColumns(),e.getState().columnPinning.left,e.getState().columnPinning.right],(n,t,r,o)=>{var i,s;let a=(i=r?.map(c=>t.find(g=>g.id===c)).filter(Boolean))!=null?i:[],l=(s=o?.map(c=>t.find(g=>g.id===c)).filter(Boolean))!=null?s:[],u=t.filter(c=>!(r!=null&&r.includes(c.id))&&!(o!=null&&o.includes(c.id)));return at(n,[...a,...u,...l],e)},C(e.options,j,"getHeaderGroups")),e.getCenterHeaderGroups=w(()=>[e.getAllColumns(),e.getVisibleLeafColumns(),e.getState().columnPinning.left,e.getState().columnPinning.right],(n,t,r,o)=>(t=t.filter(i=>!(r!=null&&r.includes(i.id))&&!(o!=null&&o.includes(i.id))),at(n,t,e,"center")),C(e.options,j,"getCenterHeaderGroups")),e.getLeftHeaderGroups=w(()=>[e.getAllColumns(),e.getVisibleLeafColumns(),e.getState().columnPinning.left],(n,t,r)=>{var o;let i=(o=r?.map(s=>t.find(a=>a.id===s)).filter(Boolean))!=null?o:[];return at(n,i,e,"left")},C(e.options,j,"getLeftHeaderGroups")),e.getRightHeaderGroups=w(()=>[e.getAllColumns(),e.getVisibleLeafColumns(),e.getState().columnPinning.right],(n,t,r)=>{var o;let i=(o=r?.map(s=>t.find(a=>a.id===s)).filter(Boolean))!=null?o:[];return at(n,i,e,"right")},C(e.options,j,"getRightHeaderGroups")),e.getFooterGroups=w(()=>[e.getHeaderGroups()],n=>[...n].reverse(),C(e.options,j,"getFooterGroups")),e.getLeftFooterGroups=w(()=>[e.getLeftHeaderGroups()],n=>[...n].reverse(),C(e.options,j,"getLeftFooterGroups")),e.getCenterFooterGroups=w(()=>[e.getCenterHeaderGroups()],n=>[...n].reverse(),C(e.options,j,"getCenterFooterGroups")),e.getRightFooterGroups=w(()=>[e.getRightHeaderGroups()],n=>[...n].reverse(),C(e.options,j,"getRightFooterGroups")),e.getFlatHeaders=w(()=>[e.getHeaderGroups()],n=>n.map(t=>t.headers).flat(),C(e.options,j,"getFlatHeaders")),e.getLeftFlatHeaders=w(()=>[e.getLeftHeaderGroups()],n=>n.map(t=>t.headers).flat(),C(e.options,j,"getLeftFlatHeaders")),e.getCenterFlatHeaders=w(()=>[e.getCenterHeaderGroups()],n=>n.map(t=>t.headers).flat(),C(e.options,j,"getCenterFlatHeaders")),e.getRightFlatHeaders=w(()=>[e.getRightHeaderGroups()],n=>n.map(t=>t.headers).flat(),C(e.options,j,"getRightFlatHeaders")),e.getCenterLeafHeaders=w(()=>[e.getCenterFlatHeaders()],n=>n.filter(t=>{var r;return!((r=t.subHeaders)!=null&&r.length)}),C(e.options,j,"getCenterLeafHeaders")),e.getLeftLeafHeaders=w(()=>[e.getLeftFlatHeaders()],n=>n.filter(t=>{var r;return!((r=t.subHeaders)!=null&&r.length)}),C(e.options,j,"getLeftLeafHeaders")),e.getRightLeafHeaders=w(()=>[e.getRightFlatHeaders()],n=>n.filter(t=>{var r;return!((r=t.subHeaders)!=null&&r.length)}),C(e.options,j,"getRightLeafHeaders")),e.getLeafHeaders=w(()=>[e.getLeftHeaderGroups(),e.getCenterHeaderGroups(),e.getRightHeaderGroups()],(n,t,r)=>{var o,i,s,a,l,u;return[...(o=(i=n[0])==null?void 0:i.headers)!=null?o:[],...(s=(a=t[0])==null?void 0:a.headers)!=null?s:[],...(l=(u=r[0])==null?void 0:u.headers)!=null?l:[]].map(f=>f.getLeafHeaders()).flat()},C(e.options,j,"getLeafHeaders"))}};function at(e,n,t,r){var o,i;let s=0,a=function(g,d){d===void 0&&(d=1),s=Math.max(s,d),g.filter(p=>p.getIsVisible()).forEach(p=>{var h;(h=p.columns)!=null&&h.length&&a(p.columns,d+1)},0)};a(e);let l=[],u=(g,d)=>{let p={depth:d,id:[r,`${d}`].filter(Boolean).join("_"),headers:[]},h=[];g.forEach(_=>{let m=[...h].reverse()[0],y=_.column.depth===p.depth,R,V=!1;if(y&&_.column.parent?R=_.column.parent:(R=_.column,V=!0),m&&m?.column===R)m.subHeaders.push(_);else{let T=wr(t,R,{id:[r,d,R.id,_?.id].filter(Boolean).join("_"),isPlaceholder:V,placeholderId:V?`${h.filter(D=>D.column===R).length}`:void 0,depth:d,index:h.length});T.subHeaders.push(_),h.push(T)}p.headers.push(_),_.headerGroup=p}),l.push(p),d>0&&u(h,d-1)},f=n.map((g,d)=>wr(t,g,{depth:s,index:d}));u(f,s-1),l.reverse();let c=g=>g.filter(p=>p.column.getIsVisible()).map(p=>{let h=0,_=0,m=[0];p.subHeaders&&p.subHeaders.length?(m=[],c(p.subHeaders).forEach(R=>{let{colSpan:V,rowSpan:T}=R;h+=V,m.push(T)})):h=1;let y=Math.min(...m);return _=_+y,p.colSpan=h,p.rowSpan=_,{colSpan:h,rowSpan:_}});return c((o=(i=l[0])==null?void 0:i.headers)!=null?o:[]),l}var cn=(e,n,t,r,o,i,s)=>{let a={id:n,index:r,original:t,depth:o,parentId:s,_valuesCache:{},_uniqueValuesCache:{},getValue:l=>{if(a._valuesCache.hasOwnProperty(l))return a._valuesCache[l];let u=e.getColumn(l);if(u!=null&&u.accessorFn)return a._valuesCache[l]=u.accessorFn(a.original,r),a._valuesCache[l]},getUniqueValues:l=>{if(a._uniqueValuesCache.hasOwnProperty(l))return a._uniqueValuesCache[l];let u=e.getColumn(l);if(u!=null&&u.accessorFn)return u.columnDef.getUniqueValues?(a._uniqueValuesCache[l]=u.columnDef.getUniqueValues(a.original,r),a._uniqueValuesCache[l]):(a._uniqueValuesCache[l]=[a.getValue(l)],a._uniqueValuesCache[l])},renderValue:l=>{var u;return(u=a.getValue(l))!=null?u:e.options.renderFallbackValue},subRows:i??[],getLeafRows:()=>Mi(a.subRows,l=>l.subRows),getParentRow:()=>a.parentId?e.getRow(a.parentId,!0):void 0,getParentRows:()=>{let l=[],u=a;for(;;){let f=u.getParentRow();if(!f)break;l.push(f),u=f}return l.reverse()},getAllCells:w(()=>[e.getAllLeafColumns()],l=>l.map(u=>Fi(e,a,u,u.id)),C(e.options,"debugRows","getAllCells")),_getAllCellsByColumnId:w(()=>[a.getAllCells()],l=>l.reduce((u,f)=>(u[f.column.id]=f,u),{}),C(e.options,"debugRows","getAllCellsByColumnId"))};for(let l=0;l{e._getFacetedRowModel=n.options.getFacetedRowModel&&n.options.getFacetedRowModel(n,e.id),e.getFacetedRowModel=()=>e._getFacetedRowModel?e._getFacetedRowModel():n.getPreFilteredRowModel(),e._getFacetedUniqueValues=n.options.getFacetedUniqueValues&&n.options.getFacetedUniqueValues(n,e.id),e.getFacetedUniqueValues=()=>e._getFacetedUniqueValues?e._getFacetedUniqueValues():new Map,e._getFacetedMinMaxValues=n.options.getFacetedMinMaxValues&&n.options.getFacetedMinMaxValues(n,e.id),e.getFacetedMinMaxValues=()=>{if(e._getFacetedMinMaxValues)return e._getFacetedMinMaxValues()}}},Er=(e,n,t)=>{var r;let o=t.toLowerCase();return!!(!((r=e.getValue(n))==null||(r=r.toString())==null||(r=r.toLowerCase())==null)&&r.includes(o))};Er.autoRemove=e=>de(e);var Rr=(e,n,t)=>{var r;return!!(!((r=e.getValue(n))==null||(r=r.toString())==null)&&r.includes(t))};Rr.autoRemove=e=>de(e);var br=(e,n,t)=>{var r;return((r=e.getValue(n))==null||(r=r.toString())==null?void 0:r.toLowerCase())===t?.toLowerCase()};br.autoRemove=e=>de(e);var xr=(e,n,t)=>{var r;return(r=e.getValue(n))==null?void 0:r.includes(t)};xr.autoRemove=e=>de(e)||!(e!=null&&e.length);var Mr=(e,n,t)=>!t.some(r=>{var o;return!((o=e.getValue(n))!=null&&o.includes(r))});Mr.autoRemove=e=>de(e)||!(e!=null&&e.length);var Fr=(e,n,t)=>t.some(r=>{var o;return(o=e.getValue(n))==null?void 0:o.includes(r)});Fr.autoRemove=e=>de(e)||!(e!=null&&e.length);var Ir=(e,n,t)=>e.getValue(n)===t;Ir.autoRemove=e=>de(e);var Tr=(e,n,t)=>e.getValue(n)==t;Tr.autoRemove=e=>de(e);var fn=(e,n,t)=>{let[r,o]=t,i=e.getValue(n);return i>=r&&i<=o};fn.resolveFilterValue=e=>{let[n,t]=e,r=typeof n!="number"?parseFloat(n):n,o=typeof t!="number"?parseFloat(t):t,i=n===null||Number.isNaN(r)?-1/0:r,s=t===null||Number.isNaN(o)?1/0:o;if(i>s){let a=i;i=s,s=a}return[i,s]};fn.autoRemove=e=>de(e)||de(e[0])&&de(e[1]);var me={includesString:Er,includesStringSensitive:Rr,equalsString:br,arrIncludes:xr,arrIncludesAll:Mr,arrIncludesSome:Fr,equals:Ir,weakEquals:Tr,inNumberRange:fn};function de(e){return e==null||e===""}var Vi={getDefaultColumnDef:()=>({filterFn:"auto"}),getInitialState:e=>({columnFilters:[],...e}),getDefaultOptions:e=>({onColumnFiltersChange:Q("columnFilters",e),filterFromLeafRows:!1,maxLeafRowFilterDepth:100}),createColumn:(e,n)=>{e.getAutoFilterFn=()=>{let t=n.getCoreRowModel().flatRows[0],r=t?.getValue(e.id);return typeof r=="string"?me.includesString:typeof r=="number"?me.inNumberRange:typeof r=="boolean"||r!==null&&typeof r=="object"?me.equals:Array.isArray(r)?me.arrIncludes:me.weakEquals},e.getFilterFn=()=>{var t,r;return ct(e.columnDef.filterFn)?e.columnDef.filterFn:e.columnDef.filterFn==="auto"?e.getAutoFilterFn():(t=(r=n.options.filterFns)==null?void 0:r[e.columnDef.filterFn])!=null?t:me[e.columnDef.filterFn]},e.getCanFilter=()=>{var t,r,o;return((t=e.columnDef.enableColumnFilter)!=null?t:!0)&&((r=n.options.enableColumnFilters)!=null?r:!0)&&((o=n.options.enableFilters)!=null?o:!0)&&!!e.accessorFn},e.getIsFiltered=()=>e.getFilterIndex()>-1,e.getFilterValue=()=>{var t;return(t=n.getState().columnFilters)==null||(t=t.find(r=>r.id===e.id))==null?void 0:t.value},e.getFilterIndex=()=>{var t,r;return(t=(r=n.getState().columnFilters)==null?void 0:r.findIndex(o=>o.id===e.id))!=null?t:-1},e.setFilterValue=t=>{n.setColumnFilters(r=>{let o=e.getFilterFn(),i=r?.find(f=>f.id===e.id),s=Se(t,i?i.value:void 0);if(Cr(o,s,e)){var a;return(a=r?.filter(f=>f.id!==e.id))!=null?a:[]}let l={id:e.id,value:s};if(i){var u;return(u=r?.map(f=>f.id===e.id?l:f))!=null?u:[]}return r!=null&&r.length?[...r,l]:[l]})}},createRow:(e,n)=>{e.columnFilters={},e.columnFiltersMeta={}},createTable:e=>{e.setColumnFilters=n=>{let t=e.getAllLeafColumns(),r=o=>{var i;return(i=Se(n,o))==null?void 0:i.filter(s=>{let a=t.find(l=>l.id===s.id);if(a){let l=a.getFilterFn();if(Cr(l,s.value,a))return!1}return!0})};e.options.onColumnFiltersChange==null||e.options.onColumnFiltersChange(r)},e.resetColumnFilters=n=>{var t,r;e.setColumnFilters(n?[]:(t=(r=e.initialState)==null?void 0:r.columnFilters)!=null?t:[])},e.getPreFilteredRowModel=()=>e.getCoreRowModel(),e.getFilteredRowModel=()=>(!e._getFilteredRowModel&&e.options.getFilteredRowModel&&(e._getFilteredRowModel=e.options.getFilteredRowModel(e)),e.options.manualFiltering||!e._getFilteredRowModel?e.getPreFilteredRowModel():e._getFilteredRowModel())}};function Cr(e,n,t){return(e&&e.autoRemove?e.autoRemove(n,t):!1)||typeof n>"u"||typeof n=="string"&&!n}var Di=(e,n,t)=>t.reduce((r,o)=>{let i=o.getValue(e);return r+(typeof i=="number"?i:0)},0),$i=(e,n,t)=>{let r;return t.forEach(o=>{let i=o.getValue(e);i!=null&&(r>i||r===void 0&&i>=i)&&(r=i)}),r},Oi=(e,n,t)=>{let r;return t.forEach(o=>{let i=o.getValue(e);i!=null&&(r=i)&&(r=i)}),r},Li=(e,n,t)=>{let r,o;return t.forEach(i=>{let s=i.getValue(e);s!=null&&(r===void 0?s>=s&&(r=o=s):(r>s&&(r=s),o{let t=0,r=0;if(n.forEach(o=>{let i=o.getValue(e);i!=null&&(i=+i)>=i&&(++t,r+=i)}),t)return r/t},Hi=(e,n)=>{if(!n.length)return;let t=n.map(i=>i.getValue(e));if(!xi(t))return;if(t.length===1)return t[0];let r=Math.floor(t.length/2),o=t.sort((i,s)=>i-s);return t.length%2!==0?o[r]:(o[r-1]+o[r])/2},Ai=(e,n)=>Array.from(new Set(n.map(t=>t.getValue(e))).values()),Ni=(e,n)=>new Set(n.map(t=>t.getValue(e))).size,zi=(e,n)=>n.length,Qt={sum:Di,min:$i,max:Oi,extent:Li,mean:ki,median:Hi,unique:Ai,uniqueCount:Ni,count:zi},Gi={getDefaultColumnDef:()=>({aggregatedCell:e=>{var n,t;return(n=(t=e.getValue())==null||t.toString==null?void 0:t.toString())!=null?n:null},aggregationFn:"auto"}),getInitialState:e=>({grouping:[],...e}),getDefaultOptions:e=>({onGroupingChange:Q("grouping",e),groupedColumnMode:"reorder"}),createColumn:(e,n)=>{e.toggleGrouping=()=>{n.setGrouping(t=>t!=null&&t.includes(e.id)?t.filter(r=>r!==e.id):[...t??[],e.id])},e.getCanGroup=()=>{var t,r;return((t=e.columnDef.enableGrouping)!=null?t:!0)&&((r=n.options.enableGrouping)!=null?r:!0)&&(!!e.accessorFn||!!e.columnDef.getGroupingValue)},e.getIsGrouped=()=>{var t;return(t=n.getState().grouping)==null?void 0:t.includes(e.id)},e.getGroupedIndex=()=>{var t;return(t=n.getState().grouping)==null?void 0:t.indexOf(e.id)},e.getToggleGroupingHandler=()=>{let t=e.getCanGroup();return()=>{t&&e.toggleGrouping()}},e.getAutoAggregationFn=()=>{let t=n.getCoreRowModel().flatRows[0],r=t?.getValue(e.id);if(typeof r=="number")return Qt.sum;if(Object.prototype.toString.call(r)==="[object Date]")return Qt.extent},e.getAggregationFn=()=>{var t,r;if(!e)throw new Error;return ct(e.columnDef.aggregationFn)?e.columnDef.aggregationFn:e.columnDef.aggregationFn==="auto"?e.getAutoAggregationFn():(t=(r=n.options.aggregationFns)==null?void 0:r[e.columnDef.aggregationFn])!=null?t:Qt[e.columnDef.aggregationFn]}},createTable:e=>{e.setGrouping=n=>e.options.onGroupingChange==null?void 0:e.options.onGroupingChange(n),e.resetGrouping=n=>{var t,r;e.setGrouping(n?[]:(t=(r=e.initialState)==null?void 0:r.grouping)!=null?t:[])},e.getPreGroupedRowModel=()=>e.getFilteredRowModel(),e.getGroupedRowModel=()=>(!e._getGroupedRowModel&&e.options.getGroupedRowModel&&(e._getGroupedRowModel=e.options.getGroupedRowModel(e)),e.options.manualGrouping||!e._getGroupedRowModel?e.getPreGroupedRowModel():e._getGroupedRowModel())},createRow:(e,n)=>{e.getIsGrouped=()=>!!e.groupingColumnId,e.getGroupingValue=t=>{if(e._groupingValuesCache.hasOwnProperty(t))return e._groupingValuesCache[t];let r=n.getColumn(t);return r!=null&&r.columnDef.getGroupingValue?(e._groupingValuesCache[t]=r.columnDef.getGroupingValue(e.original),e._groupingValuesCache[t]):e.getValue(t)},e._groupingValuesCache={}},createCell:(e,n,t,r)=>{e.getIsGrouped=()=>n.getIsGrouped()&&n.id===t.groupingColumnId,e.getIsPlaceholder=()=>!e.getIsGrouped()&&n.getIsGrouped(),e.getIsAggregated=()=>{var o;return!e.getIsGrouped()&&!e.getIsPlaceholder()&&!!((o=t.subRows)!=null&&o.length)}}};function Bi(e,n,t){if(!(n!=null&&n.length)||!t)return e;let r=e.filter(i=>!n.includes(i.id));return t==="remove"?r:[...n.map(i=>e.find(s=>s.id===i)).filter(Boolean),...r]}var Ui={getInitialState:e=>({columnOrder:[],...e}),getDefaultOptions:e=>({onColumnOrderChange:Q("columnOrder",e)}),createColumn:(e,n)=>{e.getIndex=w(t=>[Xe(n,t)],t=>t.findIndex(r=>r.id===e.id),C(n.options,"debugColumns","getIndex")),e.getIsFirstColumn=t=>{var r;return((r=Xe(n,t)[0])==null?void 0:r.id)===e.id},e.getIsLastColumn=t=>{var r;let o=Xe(n,t);return((r=o[o.length-1])==null?void 0:r.id)===e.id}},createTable:e=>{e.setColumnOrder=n=>e.options.onColumnOrderChange==null?void 0:e.options.onColumnOrderChange(n),e.resetColumnOrder=n=>{var t;e.setColumnOrder(n?[]:(t=e.initialState.columnOrder)!=null?t:[])},e._getOrderColumnsFn=w(()=>[e.getState().columnOrder,e.getState().grouping,e.options.groupedColumnMode],(n,t,r)=>o=>{let i=[];if(!(n!=null&&n.length))i=o;else{let s=[...n],a=[...o];for(;a.length&&s.length;){let l=s.shift(),u=a.findIndex(f=>f.id===l);u>-1&&i.push(a.splice(u,1)[0])}i=[...i,...a]}return Bi(i,t,r)},C(e.options,"debugTable","_getOrderColumnsFn"))}},Zt=()=>({left:[],right:[]}),Ki={getInitialState:e=>({columnPinning:Zt(),...e}),getDefaultOptions:e=>({onColumnPinningChange:Q("columnPinning",e)}),createColumn:(e,n)=>{e.pin=t=>{let r=e.getLeafColumns().map(o=>o.id).filter(Boolean);n.setColumnPinning(o=>{var i,s;if(t==="right"){var a,l;return{left:((a=o?.left)!=null?a:[]).filter(c=>!(r!=null&&r.includes(c))),right:[...((l=o?.right)!=null?l:[]).filter(c=>!(r!=null&&r.includes(c))),...r]}}if(t==="left"){var u,f;return{left:[...((u=o?.left)!=null?u:[]).filter(c=>!(r!=null&&r.includes(c))),...r],right:((f=o?.right)!=null?f:[]).filter(c=>!(r!=null&&r.includes(c)))}}return{left:((i=o?.left)!=null?i:[]).filter(c=>!(r!=null&&r.includes(c))),right:((s=o?.right)!=null?s:[]).filter(c=>!(r!=null&&r.includes(c)))}})},e.getCanPin=()=>e.getLeafColumns().some(r=>{var o,i,s;return((o=r.columnDef.enablePinning)!=null?o:!0)&&((i=(s=n.options.enableColumnPinning)!=null?s:n.options.enablePinning)!=null?i:!0)}),e.getIsPinned=()=>{let t=e.getLeafColumns().map(a=>a.id),{left:r,right:o}=n.getState().columnPinning,i=t.some(a=>r?.includes(a)),s=t.some(a=>o?.includes(a));return i?"left":s?"right":!1},e.getPinnedIndex=()=>{var t,r;let o=e.getIsPinned();return o?(t=(r=n.getState().columnPinning)==null||(r=r[o])==null?void 0:r.indexOf(e.id))!=null?t:-1:0}},createRow:(e,n)=>{e.getCenterVisibleCells=w(()=>[e._getAllVisibleCells(),n.getState().columnPinning.left,n.getState().columnPinning.right],(t,r,o)=>{let i=[...r??[],...o??[]];return t.filter(s=>!i.includes(s.column.id))},C(n.options,"debugRows","getCenterVisibleCells")),e.getLeftVisibleCells=w(()=>[e._getAllVisibleCells(),n.getState().columnPinning.left],(t,r)=>(r??[]).map(i=>t.find(s=>s.column.id===i)).filter(Boolean).map(i=>({...i,position:"left"})),C(n.options,"debugRows","getLeftVisibleCells")),e.getRightVisibleCells=w(()=>[e._getAllVisibleCells(),n.getState().columnPinning.right],(t,r)=>(r??[]).map(i=>t.find(s=>s.column.id===i)).filter(Boolean).map(i=>({...i,position:"right"})),C(n.options,"debugRows","getRightVisibleCells"))},createTable:e=>{e.setColumnPinning=n=>e.options.onColumnPinningChange==null?void 0:e.options.onColumnPinningChange(n),e.resetColumnPinning=n=>{var t,r;return e.setColumnPinning(n?Zt():(t=(r=e.initialState)==null?void 0:r.columnPinning)!=null?t:Zt())},e.getIsSomeColumnsPinned=n=>{var t;let r=e.getState().columnPinning;if(!n){var o,i;return!!((o=r.left)!=null&&o.length||(i=r.right)!=null&&i.length)}return!!((t=r[n])!=null&&t.length)},e.getLeftLeafColumns=w(()=>[e.getAllLeafColumns(),e.getState().columnPinning.left],(n,t)=>(t??[]).map(r=>n.find(o=>o.id===r)).filter(Boolean),C(e.options,"debugColumns","getLeftLeafColumns")),e.getRightLeafColumns=w(()=>[e.getAllLeafColumns(),e.getState().columnPinning.right],(n,t)=>(t??[]).map(r=>n.find(o=>o.id===r)).filter(Boolean),C(e.options,"debugColumns","getRightLeafColumns")),e.getCenterLeafColumns=w(()=>[e.getAllLeafColumns(),e.getState().columnPinning.left,e.getState().columnPinning.right],(n,t,r)=>{let o=[...t??[],...r??[]];return n.filter(i=>!o.includes(i.id))},C(e.options,"debugColumns","getCenterLeafColumns"))}},ut={size:150,minSize:20,maxSize:Number.MAX_SAFE_INTEGER},en=()=>({startOffset:null,startSize:null,deltaOffset:null,deltaPercentage:null,isResizingColumn:!1,columnSizingStart:[]}),ji={getDefaultColumnDef:()=>ut,getInitialState:e=>({columnSizing:{},columnSizingInfo:en(),...e}),getDefaultOptions:e=>({columnResizeMode:"onEnd",columnResizeDirection:"ltr",onColumnSizingChange:Q("columnSizing",e),onColumnSizingInfoChange:Q("columnSizingInfo",e)}),createColumn:(e,n)=>{e.getSize=()=>{var t,r,o;let i=n.getState().columnSizing[e.id];return Math.min(Math.max((t=e.columnDef.minSize)!=null?t:ut.minSize,(r=i??e.columnDef.size)!=null?r:ut.size),(o=e.columnDef.maxSize)!=null?o:ut.maxSize)},e.getStart=w(t=>[t,Xe(n,t),n.getState().columnSizing],(t,r)=>r.slice(0,e.getIndex(t)).reduce((o,i)=>o+i.getSize(),0),C(n.options,"debugColumns","getStart")),e.getAfter=w(t=>[t,Xe(n,t),n.getState().columnSizing],(t,r)=>r.slice(e.getIndex(t)+1).reduce((o,i)=>o+i.getSize(),0),C(n.options,"debugColumns","getAfter")),e.resetSize=()=>{n.setColumnSizing(t=>{let{[e.id]:r,...o}=t;return o})},e.getCanResize=()=>{var t,r;return((t=e.columnDef.enableResizing)!=null?t:!0)&&((r=n.options.enableColumnResizing)!=null?r:!0)},e.getIsResizing=()=>n.getState().columnSizingInfo.isResizingColumn===e.id},createHeader:(e,n)=>{e.getSize=()=>{let t=0,r=o=>{if(o.subHeaders.length)o.subHeaders.forEach(r);else{var i;t+=(i=o.column.getSize())!=null?i:0}};return r(e),t},e.getStart=()=>{if(e.index>0){let t=e.headerGroup.headers[e.index-1];return t.getStart()+t.getSize()}return 0},e.getResizeHandler=t=>{let r=n.getColumn(e.column.id),o=r?.getCanResize();return i=>{if(!r||!o||(i.persist==null||i.persist(),tn(i)&&i.touches&&i.touches.length>1))return;let s=e.getSize(),a=e?e.getLeafHeaders().map(m=>[m.column.id,m.column.getSize()]):[[r.id,r.getSize()]],l=tn(i)?Math.round(i.touches[0].clientX):i.clientX,u={},f=(m,y)=>{typeof y=="number"&&(n.setColumnSizingInfo(R=>{var V,T;let D=n.options.columnResizeDirection==="rtl"?-1:1,z=(y-((V=R?.startOffset)!=null?V:0))*D,U=Math.max(z/((T=R?.startSize)!=null?T:0),-.999999);return R.columnSizingStart.forEach(G=>{let[q,te]=G;u[q]=Math.round(Math.max(te+te*U,0)*100)/100}),{...R,deltaOffset:z,deltaPercentage:U}}),(n.options.columnResizeMode==="onChange"||m==="end")&&n.setColumnSizing(R=>({...R,...u})))},c=m=>f("move",m),g=m=>{f("end",m),n.setColumnSizingInfo(y=>({...y,isResizingColumn:!1,startOffset:null,startSize:null,deltaOffset:null,deltaPercentage:null,columnSizingStart:[]}))},d=t||typeof document<"u"?document:null,p={moveHandler:m=>c(m.clientX),upHandler:m=>{d?.removeEventListener("mousemove",p.moveHandler),d?.removeEventListener("mouseup",p.upHandler),g(m.clientX)}},h={moveHandler:m=>(m.cancelable&&(m.preventDefault(),m.stopPropagation()),c(m.touches[0].clientX),!1),upHandler:m=>{var y;d?.removeEventListener("touchmove",h.moveHandler),d?.removeEventListener("touchend",h.upHandler),m.cancelable&&(m.preventDefault(),m.stopPropagation()),g((y=m.touches[0])==null?void 0:y.clientX)}},_=qi()?{passive:!1}:!1;tn(i)?(d?.addEventListener("touchmove",h.moveHandler,_),d?.addEventListener("touchend",h.upHandler,_)):(d?.addEventListener("mousemove",p.moveHandler,_),d?.addEventListener("mouseup",p.upHandler,_)),n.setColumnSizingInfo(m=>({...m,startOffset:l,startSize:s,deltaOffset:0,deltaPercentage:0,columnSizingStart:a,isResizingColumn:r.id}))}}},createTable:e=>{e.setColumnSizing=n=>e.options.onColumnSizingChange==null?void 0:e.options.onColumnSizingChange(n),e.setColumnSizingInfo=n=>e.options.onColumnSizingInfoChange==null?void 0:e.options.onColumnSizingInfoChange(n),e.resetColumnSizing=n=>{var t;e.setColumnSizing(n?{}:(t=e.initialState.columnSizing)!=null?t:{})},e.resetHeaderSizeInfo=n=>{var t;e.setColumnSizingInfo(n?en():(t=e.initialState.columnSizingInfo)!=null?t:en())},e.getTotalSize=()=>{var n,t;return(n=(t=e.getHeaderGroups()[0])==null?void 0:t.headers.reduce((r,o)=>r+o.getSize(),0))!=null?n:0},e.getLeftTotalSize=()=>{var n,t;return(n=(t=e.getLeftHeaderGroups()[0])==null?void 0:t.headers.reduce((r,o)=>r+o.getSize(),0))!=null?n:0},e.getCenterTotalSize=()=>{var n,t;return(n=(t=e.getCenterHeaderGroups()[0])==null?void 0:t.headers.reduce((r,o)=>r+o.getSize(),0))!=null?n:0},e.getRightTotalSize=()=>{var n,t;return(n=(t=e.getRightHeaderGroups()[0])==null?void 0:t.headers.reduce((r,o)=>r+o.getSize(),0))!=null?n:0}}},dt=null;function qi(){if(typeof dt=="boolean")return dt;let e=!1;try{let n={get passive(){return e=!0,!1}},t=()=>{};window.addEventListener("test",t,n),window.removeEventListener("test",t)}catch{e=!1}return dt=e,dt}function tn(e){return e.type==="touchstart"}var Wi={getInitialState:e=>({columnVisibility:{},...e}),getDefaultOptions:e=>({onColumnVisibilityChange:Q("columnVisibility",e)}),createColumn:(e,n)=>{e.toggleVisibility=t=>{e.getCanHide()&&n.setColumnVisibility(r=>({...r,[e.id]:t??!e.getIsVisible()}))},e.getIsVisible=()=>{var t,r;let o=e.columns;return(t=o.length?o.some(i=>i.getIsVisible()):(r=n.getState().columnVisibility)==null?void 0:r[e.id])!=null?t:!0},e.getCanHide=()=>{var t,r;return((t=e.columnDef.enableHiding)!=null?t:!0)&&((r=n.options.enableHiding)!=null?r:!0)},e.getToggleVisibilityHandler=()=>t=>{e.toggleVisibility==null||e.toggleVisibility(t.target.checked)}},createRow:(e,n)=>{e._getAllVisibleCells=w(()=>[e.getAllCells(),n.getState().columnVisibility],t=>t.filter(r=>r.column.getIsVisible()),C(n.options,"debugRows","_getAllVisibleCells")),e.getVisibleCells=w(()=>[e.getLeftVisibleCells(),e.getCenterVisibleCells(),e.getRightVisibleCells()],(t,r,o)=>[...t,...r,...o],C(n.options,"debugRows","getVisibleCells"))},createTable:e=>{let n=(t,r)=>w(()=>[r(),r().filter(o=>o.getIsVisible()).map(o=>o.id).join("_")],o=>o.filter(i=>i.getIsVisible==null?void 0:i.getIsVisible()),C(e.options,"debugColumns",t));e.getVisibleFlatColumns=n("getVisibleFlatColumns",()=>e.getAllFlatColumns()),e.getVisibleLeafColumns=n("getVisibleLeafColumns",()=>e.getAllLeafColumns()),e.getLeftVisibleLeafColumns=n("getLeftVisibleLeafColumns",()=>e.getLeftLeafColumns()),e.getRightVisibleLeafColumns=n("getRightVisibleLeafColumns",()=>e.getRightLeafColumns()),e.getCenterVisibleLeafColumns=n("getCenterVisibleLeafColumns",()=>e.getCenterLeafColumns()),e.setColumnVisibility=t=>e.options.onColumnVisibilityChange==null?void 0:e.options.onColumnVisibilityChange(t),e.resetColumnVisibility=t=>{var r;e.setColumnVisibility(t?{}:(r=e.initialState.columnVisibility)!=null?r:{})},e.toggleAllColumnsVisible=t=>{var r;t=(r=t)!=null?r:!e.getIsAllColumnsVisible(),e.setColumnVisibility(e.getAllLeafColumns().reduce((o,i)=>({...o,[i.id]:t||!(i.getCanHide!=null&&i.getCanHide())}),{}))},e.getIsAllColumnsVisible=()=>!e.getAllLeafColumns().some(t=>!(t.getIsVisible!=null&&t.getIsVisible())),e.getIsSomeColumnsVisible=()=>e.getAllLeafColumns().some(t=>t.getIsVisible==null?void 0:t.getIsVisible()),e.getToggleAllColumnsVisibilityHandler=()=>t=>{var r;e.toggleAllColumnsVisible((r=t.target)==null?void 0:r.checked)}}};function Xe(e,n){return n?n==="center"?e.getCenterVisibleLeafColumns():n==="left"?e.getLeftVisibleLeafColumns():e.getRightVisibleLeafColumns():e.getVisibleLeafColumns()}var Xi={createTable:e=>{e._getGlobalFacetedRowModel=e.options.getFacetedRowModel&&e.options.getFacetedRowModel(e,"__global__"),e.getGlobalFacetedRowModel=()=>e.options.manualFiltering||!e._getGlobalFacetedRowModel?e.getPreFilteredRowModel():e._getGlobalFacetedRowModel(),e._getGlobalFacetedUniqueValues=e.options.getFacetedUniqueValues&&e.options.getFacetedUniqueValues(e,"__global__"),e.getGlobalFacetedUniqueValues=()=>e._getGlobalFacetedUniqueValues?e._getGlobalFacetedUniqueValues():new Map,e._getGlobalFacetedMinMaxValues=e.options.getFacetedMinMaxValues&&e.options.getFacetedMinMaxValues(e,"__global__"),e.getGlobalFacetedMinMaxValues=()=>{if(e._getGlobalFacetedMinMaxValues)return e._getGlobalFacetedMinMaxValues()}}},Yi={getInitialState:e=>({globalFilter:void 0,...e}),getDefaultOptions:e=>({onGlobalFilterChange:Q("globalFilter",e),globalFilterFn:"auto",getColumnCanGlobalFilter:n=>{var t;let r=(t=e.getCoreRowModel().flatRows[0])==null||(t=t._getAllCellsByColumnId()[n.id])==null?void 0:t.getValue();return typeof r=="string"||typeof r=="number"}}),createColumn:(e,n)=>{e.getCanGlobalFilter=()=>{var t,r,o,i;return((t=e.columnDef.enableGlobalFilter)!=null?t:!0)&&((r=n.options.enableGlobalFilter)!=null?r:!0)&&((o=n.options.enableFilters)!=null?o:!0)&&((i=n.options.getColumnCanGlobalFilter==null?void 0:n.options.getColumnCanGlobalFilter(e))!=null?i:!0)&&!!e.accessorFn}},createTable:e=>{e.getGlobalAutoFilterFn=()=>me.includesString,e.getGlobalFilterFn=()=>{var n,t;let{globalFilterFn:r}=e.options;return ct(r)?r:r==="auto"?e.getGlobalAutoFilterFn():(n=(t=e.options.filterFns)==null?void 0:t[r])!=null?n:me[r]},e.setGlobalFilter=n=>{e.options.onGlobalFilterChange==null||e.options.onGlobalFilterChange(n)},e.resetGlobalFilter=n=>{e.setGlobalFilter(n?void 0:e.initialState.globalFilter)}}},Ji={getInitialState:e=>({expanded:{},...e}),getDefaultOptions:e=>({onExpandedChange:Q("expanded",e),paginateExpandedRows:!0}),createTable:e=>{let n=!1,t=!1;e._autoResetExpanded=()=>{var r,o;if(!n){e._queue(()=>{n=!0});return}if((r=(o=e.options.autoResetAll)!=null?o:e.options.autoResetExpanded)!=null?r:!e.options.manualExpanding){if(t)return;t=!0,e._queue(()=>{e.resetExpanded(),t=!1})}},e.setExpanded=r=>e.options.onExpandedChange==null?void 0:e.options.onExpandedChange(r),e.toggleAllRowsExpanded=r=>{r??!e.getIsAllRowsExpanded()?e.setExpanded(!0):e.setExpanded({})},e.resetExpanded=r=>{var o,i;e.setExpanded(r?{}:(o=(i=e.initialState)==null?void 0:i.expanded)!=null?o:{})},e.getCanSomeRowsExpand=()=>e.getPrePaginationRowModel().flatRows.some(r=>r.getCanExpand()),e.getToggleAllRowsExpandedHandler=()=>r=>{r.persist==null||r.persist(),e.toggleAllRowsExpanded()},e.getIsSomeRowsExpanded=()=>{let r=e.getState().expanded;return r===!0||Object.values(r).some(Boolean)},e.getIsAllRowsExpanded=()=>{let r=e.getState().expanded;return typeof r=="boolean"?r===!0:!(!Object.keys(r).length||e.getRowModel().flatRows.some(o=>!o.getIsExpanded()))},e.getExpandedDepth=()=>{let r=0;return(e.getState().expanded===!0?Object.keys(e.getRowModel().rowsById):Object.keys(e.getState().expanded)).forEach(i=>{let s=i.split(".");r=Math.max(r,s.length)}),r},e.getPreExpandedRowModel=()=>e.getSortedRowModel(),e.getExpandedRowModel=()=>(!e._getExpandedRowModel&&e.options.getExpandedRowModel&&(e._getExpandedRowModel=e.options.getExpandedRowModel(e)),e.options.manualExpanding||!e._getExpandedRowModel?e.getPreExpandedRowModel():e._getExpandedRowModel())},createRow:(e,n)=>{e.toggleExpanded=t=>{n.setExpanded(r=>{var o;let i=r===!0?!0:!!(r!=null&&r[e.id]),s={};if(r===!0?Object.keys(n.getRowModel().rowsById).forEach(a=>{s[a]=!0}):s=r,t=(o=t)!=null?o:!i,!i&&t)return{...s,[e.id]:!0};if(i&&!t){let{[e.id]:a,...l}=s;return l}return r})},e.getIsExpanded=()=>{var t;let r=n.getState().expanded;return!!((t=n.options.getIsRowExpanded==null?void 0:n.options.getIsRowExpanded(e))!=null?t:r===!0||r?.[e.id])},e.getCanExpand=()=>{var t,r,o;return(t=n.options.getRowCanExpand==null?void 0:n.options.getRowCanExpand(e))!=null?t:((r=n.options.enableExpanding)!=null?r:!0)&&!!((o=e.subRows)!=null&&o.length)},e.getIsAllParentsExpanded=()=>{let t=!0,r=e;for(;t&&r.parentId;)r=n.getRow(r.parentId,!0),t=r.getIsExpanded();return t},e.getToggleExpandedHandler=()=>{let t=e.getCanExpand();return()=>{t&&e.toggleExpanded()}}}},sn=0,ln=10,nn=()=>({pageIndex:sn,pageSize:ln}),Qi={getInitialState:e=>({...e,pagination:{...nn(),...e?.pagination}}),getDefaultOptions:e=>({onPaginationChange:Q("pagination",e)}),createTable:e=>{let n=!1,t=!1;e._autoResetPageIndex=()=>{var r,o;if(!n){e._queue(()=>{n=!0});return}if((r=(o=e.options.autoResetAll)!=null?o:e.options.autoResetPageIndex)!=null?r:!e.options.manualPagination){if(t)return;t=!0,e._queue(()=>{e.resetPageIndex(),t=!1})}},e.setPagination=r=>{let o=i=>Se(r,i);return e.options.onPaginationChange==null?void 0:e.options.onPaginationChange(o)},e.resetPagination=r=>{var o;e.setPagination(r?nn():(o=e.initialState.pagination)!=null?o:nn())},e.setPageIndex=r=>{e.setPagination(o=>{let i=Se(r,o.pageIndex),s=typeof e.options.pageCount>"u"||e.options.pageCount===-1?Number.MAX_SAFE_INTEGER:e.options.pageCount-1;return i=Math.max(0,Math.min(i,s)),{...o,pageIndex:i}})},e.resetPageIndex=r=>{var o,i;e.setPageIndex(r?sn:(o=(i=e.initialState)==null||(i=i.pagination)==null?void 0:i.pageIndex)!=null?o:sn)},e.resetPageSize=r=>{var o,i;e.setPageSize(r?ln:(o=(i=e.initialState)==null||(i=i.pagination)==null?void 0:i.pageSize)!=null?o:ln)},e.setPageSize=r=>{e.setPagination(o=>{let i=Math.max(1,Se(r,o.pageSize)),s=o.pageSize*o.pageIndex,a=Math.floor(s/i);return{...o,pageIndex:a,pageSize:i}})},e.setPageCount=r=>e.setPagination(o=>{var i;let s=Se(r,(i=e.options.pageCount)!=null?i:-1);return typeof s=="number"&&(s=Math.max(-1,s)),{...o,pageCount:s}}),e.getPageOptions=w(()=>[e.getPageCount()],r=>{let o=[];return r&&r>0&&(o=[...new Array(r)].fill(null).map((i,s)=>s)),o},C(e.options,"debugTable","getPageOptions")),e.getCanPreviousPage=()=>e.getState().pagination.pageIndex>0,e.getCanNextPage=()=>{let{pageIndex:r}=e.getState().pagination,o=e.getPageCount();return o===-1?!0:o===0?!1:re.setPageIndex(r=>r-1),e.nextPage=()=>e.setPageIndex(r=>r+1),e.firstPage=()=>e.setPageIndex(0),e.lastPage=()=>e.setPageIndex(e.getPageCount()-1),e.getPrePaginationRowModel=()=>e.getExpandedRowModel(),e.getPaginationRowModel=()=>(!e._getPaginationRowModel&&e.options.getPaginationRowModel&&(e._getPaginationRowModel=e.options.getPaginationRowModel(e)),e.options.manualPagination||!e._getPaginationRowModel?e.getPrePaginationRowModel():e._getPaginationRowModel()),e.getPageCount=()=>{var r;return(r=e.options.pageCount)!=null?r:Math.ceil(e.getRowCount()/e.getState().pagination.pageSize)},e.getRowCount=()=>{var r;return(r=e.options.rowCount)!=null?r:e.getPrePaginationRowModel().rows.length}}},rn=()=>({top:[],bottom:[]}),Zi={getInitialState:e=>({rowPinning:rn(),...e}),getDefaultOptions:e=>({onRowPinningChange:Q("rowPinning",e)}),createRow:(e,n)=>{e.pin=(t,r,o)=>{let i=r?e.getLeafRows().map(l=>{let{id:u}=l;return u}):[],s=o?e.getParentRows().map(l=>{let{id:u}=l;return u}):[],a=new Set([...s,e.id,...i]);n.setRowPinning(l=>{var u,f;if(t==="bottom"){var c,g;return{top:((c=l?.top)!=null?c:[]).filter(h=>!(a!=null&&a.has(h))),bottom:[...((g=l?.bottom)!=null?g:[]).filter(h=>!(a!=null&&a.has(h))),...Array.from(a)]}}if(t==="top"){var d,p;return{top:[...((d=l?.top)!=null?d:[]).filter(h=>!(a!=null&&a.has(h))),...Array.from(a)],bottom:((p=l?.bottom)!=null?p:[]).filter(h=>!(a!=null&&a.has(h)))}}return{top:((u=l?.top)!=null?u:[]).filter(h=>!(a!=null&&a.has(h))),bottom:((f=l?.bottom)!=null?f:[]).filter(h=>!(a!=null&&a.has(h)))}})},e.getCanPin=()=>{var t;let{enableRowPinning:r,enablePinning:o}=n.options;return typeof r=="function"?r(e):(t=r??o)!=null?t:!0},e.getIsPinned=()=>{let t=[e.id],{top:r,bottom:o}=n.getState().rowPinning,i=t.some(a=>r?.includes(a)),s=t.some(a=>o?.includes(a));return i?"top":s?"bottom":!1},e.getPinnedIndex=()=>{var t,r;let o=e.getIsPinned();if(!o)return-1;let i=(t=o==="top"?n.getTopRows():n.getBottomRows())==null?void 0:t.map(s=>{let{id:a}=s;return a});return(r=i?.indexOf(e.id))!=null?r:-1}},createTable:e=>{e.setRowPinning=n=>e.options.onRowPinningChange==null?void 0:e.options.onRowPinningChange(n),e.resetRowPinning=n=>{var t,r;return e.setRowPinning(n?rn():(t=(r=e.initialState)==null?void 0:r.rowPinning)!=null?t:rn())},e.getIsSomeRowsPinned=n=>{var t;let r=e.getState().rowPinning;if(!n){var o,i;return!!((o=r.top)!=null&&o.length||(i=r.bottom)!=null&&i.length)}return!!((t=r[n])!=null&&t.length)},e._getPinnedRows=(n,t,r)=>{var o;return((o=e.options.keepPinnedRows)==null||o?(t??[]).map(s=>{let a=e.getRow(s,!0);return a.getIsAllParentsExpanded()?a:null}):(t??[]).map(s=>n.find(a=>a.id===s))).filter(Boolean).map(s=>({...s,position:r}))},e.getTopRows=w(()=>[e.getRowModel().rows,e.getState().rowPinning.top],(n,t)=>e._getPinnedRows(n,t,"top"),C(e.options,"debugRows","getTopRows")),e.getBottomRows=w(()=>[e.getRowModel().rows,e.getState().rowPinning.bottom],(n,t)=>e._getPinnedRows(n,t,"bottom"),C(e.options,"debugRows","getBottomRows")),e.getCenterRows=w(()=>[e.getRowModel().rows,e.getState().rowPinning.top,e.getState().rowPinning.bottom],(n,t,r)=>{let o=new Set([...t??[],...r??[]]);return n.filter(i=>!o.has(i.id))},C(e.options,"debugRows","getCenterRows"))}},es={getInitialState:e=>({rowSelection:{},...e}),getDefaultOptions:e=>({onRowSelectionChange:Q("rowSelection",e),enableRowSelection:!0,enableMultiRowSelection:!0,enableSubRowSelection:!0}),createTable:e=>{e.setRowSelection=n=>e.options.onRowSelectionChange==null?void 0:e.options.onRowSelectionChange(n),e.resetRowSelection=n=>{var t;return e.setRowSelection(n?{}:(t=e.initialState.rowSelection)!=null?t:{})},e.toggleAllRowsSelected=n=>{e.setRowSelection(t=>{n=typeof n<"u"?n:!e.getIsAllRowsSelected();let r={...t},o=e.getPreGroupedRowModel().flatRows;return n?o.forEach(i=>{i.getCanSelect()&&(r[i.id]=!0)}):o.forEach(i=>{delete r[i.id]}),r})},e.toggleAllPageRowsSelected=n=>e.setRowSelection(t=>{let r=typeof n<"u"?n:!e.getIsAllPageRowsSelected(),o={...t};return e.getRowModel().rows.forEach(i=>{an(o,i.id,r,!0,e)}),o}),e.getPreSelectedRowModel=()=>e.getCoreRowModel(),e.getSelectedRowModel=w(()=>[e.getState().rowSelection,e.getCoreRowModel()],(n,t)=>Object.keys(n).length?on(e,t):{rows:[],flatRows:[],rowsById:{}},C(e.options,"debugTable","getSelectedRowModel")),e.getFilteredSelectedRowModel=w(()=>[e.getState().rowSelection,e.getFilteredRowModel()],(n,t)=>Object.keys(n).length?on(e,t):{rows:[],flatRows:[],rowsById:{}},C(e.options,"debugTable","getFilteredSelectedRowModel")),e.getGroupedSelectedRowModel=w(()=>[e.getState().rowSelection,e.getSortedRowModel()],(n,t)=>Object.keys(n).length?on(e,t):{rows:[],flatRows:[],rowsById:{}},C(e.options,"debugTable","getGroupedSelectedRowModel")),e.getIsAllRowsSelected=()=>{let n=e.getFilteredRowModel().flatRows,{rowSelection:t}=e.getState(),r=!!(n.length&&Object.keys(t).length);return r&&n.some(o=>o.getCanSelect()&&!t[o.id])&&(r=!1),r},e.getIsAllPageRowsSelected=()=>{let n=e.getPaginationRowModel().flatRows.filter(o=>o.getCanSelect()),{rowSelection:t}=e.getState(),r=!!n.length;return r&&n.some(o=>!t[o.id])&&(r=!1),r},e.getIsSomeRowsSelected=()=>{var n;let t=Object.keys((n=e.getState().rowSelection)!=null?n:{}).length;return t>0&&t{let n=e.getPaginationRowModel().flatRows;return e.getIsAllPageRowsSelected()?!1:n.filter(t=>t.getCanSelect()).some(t=>t.getIsSelected()||t.getIsSomeSelected())},e.getToggleAllRowsSelectedHandler=()=>n=>{e.toggleAllRowsSelected(n.target.checked)},e.getToggleAllPageRowsSelectedHandler=()=>n=>{e.toggleAllPageRowsSelected(n.target.checked)}},createRow:(e,n)=>{e.toggleSelected=(t,r)=>{let o=e.getIsSelected();n.setRowSelection(i=>{var s;if(t=typeof t<"u"?t:!o,e.getCanSelect()&&o===t)return i;let a={...i};return an(a,e.id,t,(s=r?.selectChildren)!=null?s:!0,n),a})},e.getIsSelected=()=>{let{rowSelection:t}=n.getState();return gn(e,t)},e.getIsSomeSelected=()=>{let{rowSelection:t}=n.getState();return un(e,t)==="some"},e.getIsAllSubRowsSelected=()=>{let{rowSelection:t}=n.getState();return un(e,t)==="all"},e.getCanSelect=()=>{var t;return typeof n.options.enableRowSelection=="function"?n.options.enableRowSelection(e):(t=n.options.enableRowSelection)!=null?t:!0},e.getCanSelectSubRows=()=>{var t;return typeof n.options.enableSubRowSelection=="function"?n.options.enableSubRowSelection(e):(t=n.options.enableSubRowSelection)!=null?t:!0},e.getCanMultiSelect=()=>{var t;return typeof n.options.enableMultiRowSelection=="function"?n.options.enableMultiRowSelection(e):(t=n.options.enableMultiRowSelection)!=null?t:!0},e.getToggleSelectedHandler=()=>{let t=e.getCanSelect();return r=>{var o;t&&e.toggleSelected((o=r.target)==null?void 0:o.checked)}}}},an=(e,n,t,r,o)=>{var i;let s=o.getRow(n,!0);t?(s.getCanMultiSelect()||Object.keys(e).forEach(a=>delete e[a]),s.getCanSelect()&&(e[n]=!0)):delete e[n],r&&(i=s.subRows)!=null&&i.length&&s.getCanSelectSubRows()&&s.subRows.forEach(a=>an(e,a.id,t,r,o))};function on(e,n){let t=e.getState().rowSelection,r=[],o={},i=function(s,a){return s.map(l=>{var u;let f=gn(l,t);if(f&&(r.push(l),o[l.id]=l),(u=l.subRows)!=null&&u.length&&(l={...l,subRows:i(l.subRows)}),f)return l}).filter(Boolean)};return{rows:i(n.rows),flatRows:r,rowsById:o}}function gn(e,n){var t;return(t=n[e.id])!=null?t:!1}function un(e,n,t){var r;if(!((r=e.subRows)!=null&&r.length))return!1;let o=!0,i=!1;return e.subRows.forEach(s=>{if(!(i&&!o)&&(s.getCanSelect()&&(gn(s,n)?i=!0:o=!1),s.subRows&&s.subRows.length)){let a=un(s,n);a==="all"?i=!0:(a==="some"&&(i=!0),o=!1)}}),o?"all":i?"some":!1}var dn=/([0-9]+)/gm,ts=(e,n,t)=>Pr(we(e.getValue(t)).toLowerCase(),we(n.getValue(t)).toLowerCase()),ns=(e,n,t)=>Pr(we(e.getValue(t)),we(n.getValue(t))),rs=(e,n,t)=>pn(we(e.getValue(t)).toLowerCase(),we(n.getValue(t)).toLowerCase()),os=(e,n,t)=>pn(we(e.getValue(t)),we(n.getValue(t))),is=(e,n,t)=>{let r=e.getValue(t),o=n.getValue(t);return r>o?1:rpn(e.getValue(t),n.getValue(t));function pn(e,n){return e===n?0:e>n?1:-1}function we(e){return typeof e=="number"?isNaN(e)||e===1/0||e===-1/0?"":String(e):typeof e=="string"?e:""}function Pr(e,n){let t=e.split(dn).filter(Boolean),r=n.split(dn).filter(Boolean);for(;t.length&&r.length;){let o=t.shift(),i=r.shift(),s=parseInt(o,10),a=parseInt(i,10),l=[s,a].sort();if(isNaN(l[0])){if(o>i)return 1;if(i>o)return-1;continue}if(isNaN(l[1]))return isNaN(s)?-1:1;if(s>a)return 1;if(a>s)return-1}return t.length-r.length}var We={alphanumeric:ts,alphanumericCaseSensitive:ns,text:rs,textCaseSensitive:os,datetime:is,basic:ss},ls={getInitialState:e=>({sorting:[],...e}),getDefaultColumnDef:()=>({sortingFn:"auto",sortUndefined:1}),getDefaultOptions:e=>({onSortingChange:Q("sorting",e),isMultiSortEvent:n=>n.shiftKey}),createColumn:(e,n)=>{e.getAutoSortingFn=()=>{let t=n.getFilteredRowModel().flatRows.slice(10),r=!1;for(let o of t){let i=o?.getValue(e.id);if(Object.prototype.toString.call(i)==="[object Date]")return We.datetime;if(typeof i=="string"&&(r=!0,i.split(dn).length>1))return We.alphanumeric}return r?We.text:We.basic},e.getAutoSortDir=()=>{let t=n.getFilteredRowModel().flatRows[0];return typeof t?.getValue(e.id)=="string"?"asc":"desc"},e.getSortingFn=()=>{var t,r;if(!e)throw new Error;return ct(e.columnDef.sortingFn)?e.columnDef.sortingFn:e.columnDef.sortingFn==="auto"?e.getAutoSortingFn():(t=(r=n.options.sortingFns)==null?void 0:r[e.columnDef.sortingFn])!=null?t:We[e.columnDef.sortingFn]},e.toggleSorting=(t,r)=>{let o=e.getNextSortingOrder(),i=typeof t<"u"&&t!==null;n.setSorting(s=>{let a=s?.find(d=>d.id===e.id),l=s?.findIndex(d=>d.id===e.id),u=[],f,c=i?t:o==="desc";if(s!=null&&s.length&&e.getCanMultiSort()&&r?a?f="toggle":f="add":s!=null&&s.length&&l!==s.length-1?f="replace":a?f="toggle":f="replace",f==="toggle"&&(i||o||(f="remove")),f==="add"){var g;u=[...s,{id:e.id,desc:c}],u.splice(0,u.length-((g=n.options.maxMultiSortColCount)!=null?g:Number.MAX_SAFE_INTEGER))}else f==="toggle"?u=s.map(d=>d.id===e.id?{...d,desc:c}:d):f==="remove"?u=s.filter(d=>d.id!==e.id):u=[{id:e.id,desc:c}];return u})},e.getFirstSortDir=()=>{var t,r;return((t=(r=e.columnDef.sortDescFirst)!=null?r:n.options.sortDescFirst)!=null?t:e.getAutoSortDir()==="desc")?"desc":"asc"},e.getNextSortingOrder=t=>{var r,o;let i=e.getFirstSortDir(),s=e.getIsSorted();return s?s!==i&&((r=n.options.enableSortingRemoval)==null||r)&&(!(t&&(o=n.options.enableMultiRemove)!=null)||o)?!1:s==="desc"?"asc":"desc":i},e.getCanSort=()=>{var t,r;return((t=e.columnDef.enableSorting)!=null?t:!0)&&((r=n.options.enableSorting)!=null?r:!0)&&!!e.accessorFn},e.getCanMultiSort=()=>{var t,r;return(t=(r=e.columnDef.enableMultiSort)!=null?r:n.options.enableMultiSort)!=null?t:!!e.accessorFn},e.getIsSorted=()=>{var t;let r=(t=n.getState().sorting)==null?void 0:t.find(o=>o.id===e.id);return r?r.desc?"desc":"asc":!1},e.getSortIndex=()=>{var t,r;return(t=(r=n.getState().sorting)==null?void 0:r.findIndex(o=>o.id===e.id))!=null?t:-1},e.clearSorting=()=>{n.setSorting(t=>t!=null&&t.length?t.filter(r=>r.id!==e.id):[])},e.getToggleSortingHandler=()=>{let t=e.getCanSort();return r=>{t&&(r.persist==null||r.persist(),e.toggleSorting==null||e.toggleSorting(void 0,e.getCanMultiSort()?n.options.isMultiSortEvent==null?void 0:n.options.isMultiSortEvent(r):!1))}}},createTable:e=>{e.setSorting=n=>e.options.onSortingChange==null?void 0:e.options.onSortingChange(n),e.resetSorting=n=>{var t,r;e.setSorting(n?[]:(t=(r=e.initialState)==null?void 0:r.sorting)!=null?t:[])},e.getPreSortedRowModel=()=>e.getGroupedRowModel(),e.getSortedRowModel=()=>(!e._getSortedRowModel&&e.options.getSortedRowModel&&(e._getSortedRowModel=e.options.getSortedRowModel(e)),e.options.manualSorting||!e._getSortedRowModel?e.getPreSortedRowModel():e._getSortedRowModel())}},as=[Ti,Wi,Ui,Ki,Pi,Vi,Xi,Yi,ls,Gi,Ji,Qi,Zi,es,ji];function Vr(e){var n,t;let r=[...as,...(n=e._features)!=null?n:[]],o={_features:r},i=o._features.reduce((g,d)=>Object.assign(g,d.getDefaultOptions==null?void 0:d.getDefaultOptions(o)),{}),s=g=>o.options.mergeOptions?o.options.mergeOptions(i,g):{...i,...g},l={...{},...(t=e.initialState)!=null?t:{}};o._features.forEach(g=>{var d;l=(d=g.getInitialState==null?void 0:g.getInitialState(l))!=null?d:l});let u=[],f=!1,c={_features:r,options:{...i,...e},initialState:l,_queue:g=>{u.push(g),f||(f=!0,Promise.resolve().then(()=>{for(;u.length;)u.shift()();f=!1}).catch(d=>setTimeout(()=>{throw d})))},reset:()=>{o.setState(o.initialState)},setOptions:g=>{let d=Se(g,o.options);o.options=s(d)},getState:()=>o.options.state,setState:g=>{o.options.onStateChange==null||o.options.onStateChange(g)},_getRowId:(g,d,p)=>{var h;return(h=o.options.getRowId==null?void 0:o.options.getRowId(g,d,p))!=null?h:`${p?[p.id,d].join("."):d}`},getCoreRowModel:()=>(o._getCoreRowModel||(o._getCoreRowModel=o.options.getCoreRowModel(o)),o._getCoreRowModel()),getRowModel:()=>o.getPaginationRowModel(),getRow:(g,d)=>{let p=(d?o.getPrePaginationRowModel():o.getRowModel()).rowsById[g];if(!p&&(p=o.getCoreRowModel().rowsById[g],!p))throw new Error;return p},_getDefaultColumnDef:w(()=>[o.options.defaultColumn],g=>{var d;return g=(d=g)!=null?d:{},{header:p=>{let h=p.header.column.columnDef;return h.accessorKey?h.accessorKey:h.accessorFn?h.id:null},cell:p=>{var h,_;return(h=(_=p.renderValue())==null||_.toString==null?void 0:_.toString())!=null?h:null},...o._features.reduce((p,h)=>Object.assign(p,h.getDefaultColumnDef==null?void 0:h.getDefaultColumnDef()),{}),...g}},C(e,"debugColumns","_getDefaultColumnDef")),_getColumnDefs:()=>o.options.columns,getAllColumns:w(()=>[o._getColumnDefs()],g=>{let d=function(p,h,_){return _===void 0&&(_=0),p.map(m=>{let y=Ii(o,m,_,h),R=m;return y.columns=R.columns?d(R.columns,y,_+1):[],y})};return d(g)},C(e,"debugColumns","getAllColumns")),getAllFlatColumns:w(()=>[o.getAllColumns()],g=>g.flatMap(d=>d.getFlatColumns()),C(e,"debugColumns","getAllFlatColumns")),_getAllFlatColumnsById:w(()=>[o.getAllFlatColumns()],g=>g.reduce((d,p)=>(d[p.id]=p,d),{}),C(e,"debugColumns","getAllFlatColumnsById")),getAllLeafColumns:w(()=>[o.getAllColumns(),o._getOrderColumnsFn()],(g,d)=>{let p=g.flatMap(h=>h.getLeafColumns());return d(p)},C(e,"debugColumns","getAllLeafColumns")),getColumn:g=>o._getAllFlatColumnsById()[g]};Object.assign(o,c);for(let g=0;gw(()=>[e.options.data],n=>{let t={rows:[],flatRows:[],rowsById:{}},r=function(o,i,s){i===void 0&&(i=0);let a=[];for(let u=0;ue._autoResetPageIndex()))}function $r(){return(e,n)=>w(()=>{var t;return[(t=e.getColumn(n))==null?void 0:t.getFacetedRowModel()]},t=>{var r;if(!t)return;let o=(r=t.flatRows[0])==null?void 0:r.getUniqueValues(n);if(typeof o>"u")return;let i=[o,o];for(let s=0;si[1]&&(i[1]=u)}}return i},C(e.options,"debugTable","getFacetedMinMaxValues"))}function Or(e,n,t){return t.options.filterFromLeafRows?us(e,n,t):ds(e,n,t)}function us(e,n,t){var r;let o=[],i={},s=(r=t.options.maxLeafRowFilterDepth)!=null?r:100,a=function(l,u){u===void 0&&(u=0);let f=[];for(let g=0;gw(()=>[e.getPreFilteredRowModel(),e.getState().columnFilters,e.getState().globalFilter,e.getFilteredRowModel()],(t,r,o)=>{if(!t.rows.length||!(r!=null&&r.length)&&!o)return t;let i=[...r.map(a=>a.id).filter(a=>a!==n),o?"__global__":void 0].filter(Boolean),s=a=>{for(let l=0;lw(()=>{var t;return[(t=e.getColumn(n))==null?void 0:t.getFacetedRowModel()]},t=>{if(!t)return new Map;let r=new Map;for(let i=0;iw(()=>[e.getPreFilteredRowModel(),e.getState().columnFilters,e.getState().globalFilter],(n,t,r)=>{if(!n.rows.length||!(t!=null&&t.length)&&!r){for(let g=0;g{var d;let p=e.getColumn(g.id);if(!p)return;let h=p.getFilterFn();h&&o.push({id:g.id,filterFn:h,resolvedValue:(d=h.resolveFilterValue==null?void 0:h.resolveFilterValue(g.value))!=null?d:g.value})});let s=(t??[]).map(g=>g.id),a=e.getGlobalFilterFn(),l=e.getAllLeafColumns().filter(g=>g.getCanGlobalFilter());r&&a&&l.length&&(s.push("__global__"),l.forEach(g=>{var d;i.push({id:g.id,filterFn:a,resolvedValue:(d=a.resolveFilterValue==null?void 0:a.resolveFilterValue(r))!=null?d:r})}));let u,f;for(let g=0;g{d.columnFiltersMeta[h]=_})}if(i.length){for(let p=0;p{d.columnFiltersMeta[h]=_})){d.columnFilters.__global__=!0;break}}d.columnFilters.__global__!==!0&&(d.columnFilters.__global__=!1)}}let c=g=>{for(let d=0;de._autoResetPageIndex()))}function Ar(){return e=>w(()=>[e.getState().sorting,e.getPreSortedRowModel()],(n,t)=>{if(!t.rows.length||!(n!=null&&n.length))return t;let r=e.getState().sorting,o=[],i=r.filter(l=>{var u;return(u=e.getColumn(l.id))==null?void 0:u.getCanSort()}),s={};i.forEach(l=>{let u=e.getColumn(l.id);u&&(s[l.id]={sortUndefined:u.columnDef.sortUndefined,invertSorting:u.columnDef.invertSorting,sortingFn:u.getSortingFn()})});let a=l=>{let u=l.map(f=>({...f}));return u.sort((f,c)=>{for(let d=0;d{var c;o.push(f),(c=f.subRows)!=null&&c.length&&(f.subRows=a(f.subRows))}),u};return{rows:a(t.rows),flatRows:o,rowsById:t.rowsById}},C(e.options,"debugTable","getSortedRowModel",()=>e._autoResetPageIndex()))}function ft(e,n){return e?cs(e)?J(e,n):e:null}function cs(e){return fs(e)||typeof e=="function"||gs(e)}function fs(e){return typeof e=="function"&&(()=>{let n=Object.getPrototypeOf(e);return n.prototype&&n.prototype.isReactComponent})()}function gs(e){return typeof e=="object"&&typeof e.$$typeof=="symbol"&&["react.memo","react.forward_ref"].includes(e.$$typeof.description)}function Nr(e){let n={state:{},onStateChange:()=>{},renderFallbackValue:null,...e},[t]=H(()=>({current:Vr(n)})),[r,o]=H(()=>t.current.initialState);return t.current.setOptions(i=>({...i,...e,state:{...r,...e.state},onStateChange:s=>{o(s),e.onStateChange==null||e.onStateChange(s)}})),t.current}function Ve(e,n,t){let r=t.initialDeps??[],o;return()=>{var i,s,a,l;let u;t.key&&((i=t.debug)!=null&&i.call(t))&&(u=Date.now());let f=e();if(!(f.length!==r.length||f.some((d,p)=>r[p]!==d)))return o;r=f;let g;if(t.key&&((s=t.debug)!=null&&s.call(t))&&(g=Date.now()),o=n(...f),t.key&&((a=t.debug)!=null&&a.call(t))){let d=Math.round((Date.now()-u)*100)/100,p=Math.round((Date.now()-g)*100)/100,h=p/16,_=(m,y)=>{for(m=String(m);m.length{var o;return(o=e?.debugAll)!=null?o:e[n]},key:!1,onChange:r}}function Fi(e,n,t,r){let o=()=>{var s;return(s=i.getValue())!=null?s:e.options.renderFallbackValue},i={id:`${n.id}_${t.id}`,row:n,column:t,getValue:()=>n.getValue(r),renderValue:o,getContext:w(()=>[e,t,n,i],(s,a,l,u)=>({table:s,column:a,row:l,cell:u,getValue:u.getValue,renderValue:u.renderValue}),C(e.options,"debugCells","cell.getContext"))};return e._features.forEach(s=>{s.createCell==null||s.createCell(i,t,n,e)},{}),i}function Ii(e,n,t,r){var o,i;let a={...e._getDefaultColumnDef(),...n},l=a.accessorKey,u=(o=(i=a.id)!=null?i:l?l.replace(".","_"):void 0)!=null?o:typeof a.header=="string"?a.header:void 0,f;if(a.accessorFn?f=a.accessorFn:l&&(l.includes(".")?f=g=>{let d=g;for(let m of l.split(".")){var p;d=(p=d)==null?void 0:p[m]}return d}:f=g=>g[a.accessorKey]),!u)throw new Error;let c={id:`${String(u)}`,accessorFn:f,parent:r,depth:t,columnDef:a,columns:[],getFlatColumns:w(()=>[!0],()=>{var g;return[c,...(g=c.columns)==null?void 0:g.flatMap(d=>d.getFlatColumns())]},C(e.options,"debugColumns","column.getFlatColumns")),getLeafColumns:w(()=>[e._getOrderColumnsFn()],g=>{var d;if((d=c.columns)!=null&&d.length){let p=c.columns.flatMap(m=>m.getLeafColumns());return g(p)}return[c]},C(e.options,"debugColumns","column.getLeafColumns"))};for(let g of e._features)g.createColumn==null||g.createColumn(c,e);return c}var j="debugHeaders";function Cr(e,n,t){var r;let i={id:(r=t.id)!=null?r:n.id,column:n,index:t.index,isPlaceholder:!!t.isPlaceholder,placeholderId:t.placeholderId,depth:t.depth,subHeaders:[],colSpan:0,rowSpan:0,headerGroup:null,getLeafHeaders:()=>{let s=[],a=l=>{l.subHeaders&&l.subHeaders.length&&l.subHeaders.map(a),s.push(l)};return a(i),s},getContext:()=>({table:e,header:i,column:n})};return e._features.forEach(s=>{s.createHeader==null||s.createHeader(i,e)}),i}var Ti={createTable:e=>{e.getHeaderGroups=w(()=>[e.getAllColumns(),e.getVisibleLeafColumns(),e.getState().columnPinning.left,e.getState().columnPinning.right],(n,t,r,o)=>{var i,s;let a=(i=r?.map(c=>t.find(g=>g.id===c)).filter(Boolean))!=null?i:[],l=(s=o?.map(c=>t.find(g=>g.id===c)).filter(Boolean))!=null?s:[],u=t.filter(c=>!(r!=null&&r.includes(c.id))&&!(o!=null&&o.includes(c.id)));return ut(n,[...a,...u,...l],e)},C(e.options,j,"getHeaderGroups")),e.getCenterHeaderGroups=w(()=>[e.getAllColumns(),e.getVisibleLeafColumns(),e.getState().columnPinning.left,e.getState().columnPinning.right],(n,t,r,o)=>(t=t.filter(i=>!(r!=null&&r.includes(i.id))&&!(o!=null&&o.includes(i.id))),ut(n,t,e,"center")),C(e.options,j,"getCenterHeaderGroups")),e.getLeftHeaderGroups=w(()=>[e.getAllColumns(),e.getVisibleLeafColumns(),e.getState().columnPinning.left],(n,t,r)=>{var o;let i=(o=r?.map(s=>t.find(a=>a.id===s)).filter(Boolean))!=null?o:[];return ut(n,i,e,"left")},C(e.options,j,"getLeftHeaderGroups")),e.getRightHeaderGroups=w(()=>[e.getAllColumns(),e.getVisibleLeafColumns(),e.getState().columnPinning.right],(n,t,r)=>{var o;let i=(o=r?.map(s=>t.find(a=>a.id===s)).filter(Boolean))!=null?o:[];return ut(n,i,e,"right")},C(e.options,j,"getRightHeaderGroups")),e.getFooterGroups=w(()=>[e.getHeaderGroups()],n=>[...n].reverse(),C(e.options,j,"getFooterGroups")),e.getLeftFooterGroups=w(()=>[e.getLeftHeaderGroups()],n=>[...n].reverse(),C(e.options,j,"getLeftFooterGroups")),e.getCenterFooterGroups=w(()=>[e.getCenterHeaderGroups()],n=>[...n].reverse(),C(e.options,j,"getCenterFooterGroups")),e.getRightFooterGroups=w(()=>[e.getRightHeaderGroups()],n=>[...n].reverse(),C(e.options,j,"getRightFooterGroups")),e.getFlatHeaders=w(()=>[e.getHeaderGroups()],n=>n.map(t=>t.headers).flat(),C(e.options,j,"getFlatHeaders")),e.getLeftFlatHeaders=w(()=>[e.getLeftHeaderGroups()],n=>n.map(t=>t.headers).flat(),C(e.options,j,"getLeftFlatHeaders")),e.getCenterFlatHeaders=w(()=>[e.getCenterHeaderGroups()],n=>n.map(t=>t.headers).flat(),C(e.options,j,"getCenterFlatHeaders")),e.getRightFlatHeaders=w(()=>[e.getRightHeaderGroups()],n=>n.map(t=>t.headers).flat(),C(e.options,j,"getRightFlatHeaders")),e.getCenterLeafHeaders=w(()=>[e.getCenterFlatHeaders()],n=>n.filter(t=>{var r;return!((r=t.subHeaders)!=null&&r.length)}),C(e.options,j,"getCenterLeafHeaders")),e.getLeftLeafHeaders=w(()=>[e.getLeftFlatHeaders()],n=>n.filter(t=>{var r;return!((r=t.subHeaders)!=null&&r.length)}),C(e.options,j,"getLeftLeafHeaders")),e.getRightLeafHeaders=w(()=>[e.getRightFlatHeaders()],n=>n.filter(t=>{var r;return!((r=t.subHeaders)!=null&&r.length)}),C(e.options,j,"getRightLeafHeaders")),e.getLeafHeaders=w(()=>[e.getLeftHeaderGroups(),e.getCenterHeaderGroups(),e.getRightHeaderGroups()],(n,t,r)=>{var o,i,s,a,l,u;return[...(o=(i=n[0])==null?void 0:i.headers)!=null?o:[],...(s=(a=t[0])==null?void 0:a.headers)!=null?s:[],...(l=(u=r[0])==null?void 0:u.headers)!=null?l:[]].map(f=>f.getLeafHeaders()).flat()},C(e.options,j,"getLeafHeaders"))}};function ut(e,n,t,r){var o,i;let s=0,a=function(g,d){d===void 0&&(d=1),s=Math.max(s,d),g.filter(p=>p.getIsVisible()).forEach(p=>{var m;(m=p.columns)!=null&&m.length&&a(p.columns,d+1)},0)};a(e);let l=[],u=(g,d)=>{let p={depth:d,id:[r,`${d}`].filter(Boolean).join("_"),headers:[]},m=[];g.forEach(_=>{let h=[...m].reverse()[0],y=_.column.depth===p.depth,R,V=!1;if(y&&_.column.parent?R=_.column.parent:(R=_.column,V=!0),h&&h?.column===R)h.subHeaders.push(_);else{let T=Cr(t,R,{id:[r,d,R.id,_?.id].filter(Boolean).join("_"),isPlaceholder:V,placeholderId:V?`${m.filter(D=>D.column===R).length}`:void 0,depth:d,index:m.length});T.subHeaders.push(_),m.push(T)}p.headers.push(_),_.headerGroup=p}),l.push(p),d>0&&u(m,d-1)},f=n.map((g,d)=>Cr(t,g,{depth:s,index:d}));u(f,s-1),l.reverse();let c=g=>g.filter(p=>p.column.getIsVisible()).map(p=>{let m=0,_=0,h=[0];p.subHeaders&&p.subHeaders.length?(h=[],c(p.subHeaders).forEach(R=>{let{colSpan:V,rowSpan:T}=R;m+=V,h.push(T)})):m=1;let y=Math.min(...h);return _=_+y,p.colSpan=m,p.rowSpan=_,{colSpan:m,rowSpan:_}});return c((o=(i=l[0])==null?void 0:i.headers)!=null?o:[]),l}var fn=(e,n,t,r,o,i,s)=>{let a={id:n,index:r,original:t,depth:o,parentId:s,_valuesCache:{},_uniqueValuesCache:{},getValue:l=>{if(a._valuesCache.hasOwnProperty(l))return a._valuesCache[l];let u=e.getColumn(l);if(u!=null&&u.accessorFn)return a._valuesCache[l]=u.accessorFn(a.original,r),a._valuesCache[l]},getUniqueValues:l=>{if(a._uniqueValuesCache.hasOwnProperty(l))return a._uniqueValuesCache[l];let u=e.getColumn(l);if(u!=null&&u.accessorFn)return u.columnDef.getUniqueValues?(a._uniqueValuesCache[l]=u.columnDef.getUniqueValues(a.original,r),a._uniqueValuesCache[l]):(a._uniqueValuesCache[l]=[a.getValue(l)],a._uniqueValuesCache[l])},renderValue:l=>{var u;return(u=a.getValue(l))!=null?u:e.options.renderFallbackValue},subRows:i??[],getLeafRows:()=>Mi(a.subRows,l=>l.subRows),getParentRow:()=>a.parentId?e.getRow(a.parentId,!0):void 0,getParentRows:()=>{let l=[],u=a;for(;;){let f=u.getParentRow();if(!f)break;l.push(f),u=f}return l.reverse()},getAllCells:w(()=>[e.getAllLeafColumns()],l=>l.map(u=>Fi(e,a,u,u.id)),C(e.options,"debugRows","getAllCells")),_getAllCellsByColumnId:w(()=>[a.getAllCells()],l=>l.reduce((u,f)=>(u[f.column.id]=f,u),{}),C(e.options,"debugRows","getAllCellsByColumnId"))};for(let l=0;l{e._getFacetedRowModel=n.options.getFacetedRowModel&&n.options.getFacetedRowModel(n,e.id),e.getFacetedRowModel=()=>e._getFacetedRowModel?e._getFacetedRowModel():n.getPreFilteredRowModel(),e._getFacetedUniqueValues=n.options.getFacetedUniqueValues&&n.options.getFacetedUniqueValues(n,e.id),e.getFacetedUniqueValues=()=>e._getFacetedUniqueValues?e._getFacetedUniqueValues():new Map,e._getFacetedMinMaxValues=n.options.getFacetedMinMaxValues&&n.options.getFacetedMinMaxValues(n,e.id),e.getFacetedMinMaxValues=()=>{if(e._getFacetedMinMaxValues)return e._getFacetedMinMaxValues()}}},Rr=(e,n,t)=>{var r;let o=t.toLowerCase();return!!(!((r=e.getValue(n))==null||(r=r.toString())==null||(r=r.toLowerCase())==null)&&r.includes(o))};Rr.autoRemove=e=>de(e);var br=(e,n,t)=>{var r;return!!(!((r=e.getValue(n))==null||(r=r.toString())==null)&&r.includes(t))};br.autoRemove=e=>de(e);var xr=(e,n,t)=>{var r;return((r=e.getValue(n))==null||(r=r.toString())==null?void 0:r.toLowerCase())===t?.toLowerCase()};xr.autoRemove=e=>de(e);var Mr=(e,n,t)=>{var r;return(r=e.getValue(n))==null?void 0:r.includes(t)};Mr.autoRemove=e=>de(e)||!(e!=null&&e.length);var Fr=(e,n,t)=>!t.some(r=>{var o;return!((o=e.getValue(n))!=null&&o.includes(r))});Fr.autoRemove=e=>de(e)||!(e!=null&&e.length);var Ir=(e,n,t)=>t.some(r=>{var o;return(o=e.getValue(n))==null?void 0:o.includes(r)});Ir.autoRemove=e=>de(e)||!(e!=null&&e.length);var Tr=(e,n,t)=>e.getValue(n)===t;Tr.autoRemove=e=>de(e);var Pr=(e,n,t)=>e.getValue(n)==t;Pr.autoRemove=e=>de(e);var gn=(e,n,t)=>{let[r,o]=t,i=e.getValue(n);return i>=r&&i<=o};gn.resolveFilterValue=e=>{let[n,t]=e,r=typeof n!="number"?parseFloat(n):n,o=typeof t!="number"?parseFloat(t):t,i=n===null||Number.isNaN(r)?-1/0:r,s=t===null||Number.isNaN(o)?1/0:o;if(i>s){let a=i;i=s,s=a}return[i,s]};gn.autoRemove=e=>de(e)||de(e[0])&&de(e[1]);var he={includesString:Rr,includesStringSensitive:br,equalsString:xr,arrIncludes:Mr,arrIncludesAll:Fr,arrIncludesSome:Ir,equals:Tr,weakEquals:Pr,inNumberRange:gn};function de(e){return e==null||e===""}var Vi={getDefaultColumnDef:()=>({filterFn:"auto"}),getInitialState:e=>({columnFilters:[],...e}),getDefaultOptions:e=>({onColumnFiltersChange:Q("columnFilters",e),filterFromLeafRows:!1,maxLeafRowFilterDepth:100}),createColumn:(e,n)=>{e.getAutoFilterFn=()=>{let t=n.getCoreRowModel().flatRows[0],r=t?.getValue(e.id);return typeof r=="string"?he.includesString:typeof r=="number"?he.inNumberRange:typeof r=="boolean"||r!==null&&typeof r=="object"?he.equals:Array.isArray(r)?he.arrIncludes:he.weakEquals},e.getFilterFn=()=>{var t,r;return ft(e.columnDef.filterFn)?e.columnDef.filterFn:e.columnDef.filterFn==="auto"?e.getAutoFilterFn():(t=(r=n.options.filterFns)==null?void 0:r[e.columnDef.filterFn])!=null?t:he[e.columnDef.filterFn]},e.getCanFilter=()=>{var t,r,o;return((t=e.columnDef.enableColumnFilter)!=null?t:!0)&&((r=n.options.enableColumnFilters)!=null?r:!0)&&((o=n.options.enableFilters)!=null?o:!0)&&!!e.accessorFn},e.getIsFiltered=()=>e.getFilterIndex()>-1,e.getFilterValue=()=>{var t;return(t=n.getState().columnFilters)==null||(t=t.find(r=>r.id===e.id))==null?void 0:t.value},e.getFilterIndex=()=>{var t,r;return(t=(r=n.getState().columnFilters)==null?void 0:r.findIndex(o=>o.id===e.id))!=null?t:-1},e.setFilterValue=t=>{n.setColumnFilters(r=>{let o=e.getFilterFn(),i=r?.find(f=>f.id===e.id),s=we(t,i?i.value:void 0);if(Er(o,s,e)){var a;return(a=r?.filter(f=>f.id!==e.id))!=null?a:[]}let l={id:e.id,value:s};if(i){var u;return(u=r?.map(f=>f.id===e.id?l:f))!=null?u:[]}return r!=null&&r.length?[...r,l]:[l]})}},createRow:(e,n)=>{e.columnFilters={},e.columnFiltersMeta={}},createTable:e=>{e.setColumnFilters=n=>{let t=e.getAllLeafColumns(),r=o=>{var i;return(i=we(n,o))==null?void 0:i.filter(s=>{let a=t.find(l=>l.id===s.id);if(a){let l=a.getFilterFn();if(Er(l,s.value,a))return!1}return!0})};e.options.onColumnFiltersChange==null||e.options.onColumnFiltersChange(r)},e.resetColumnFilters=n=>{var t,r;e.setColumnFilters(n?[]:(t=(r=e.initialState)==null?void 0:r.columnFilters)!=null?t:[])},e.getPreFilteredRowModel=()=>e.getCoreRowModel(),e.getFilteredRowModel=()=>(!e._getFilteredRowModel&&e.options.getFilteredRowModel&&(e._getFilteredRowModel=e.options.getFilteredRowModel(e)),e.options.manualFiltering||!e._getFilteredRowModel?e.getPreFilteredRowModel():e._getFilteredRowModel())}};function Er(e,n,t){return(e&&e.autoRemove?e.autoRemove(n,t):!1)||typeof n>"u"||typeof n=="string"&&!n}var Di=(e,n,t)=>t.reduce((r,o)=>{let i=o.getValue(e);return r+(typeof i=="number"?i:0)},0),$i=(e,n,t)=>{let r;return t.forEach(o=>{let i=o.getValue(e);i!=null&&(r>i||r===void 0&&i>=i)&&(r=i)}),r},Oi=(e,n,t)=>{let r;return t.forEach(o=>{let i=o.getValue(e);i!=null&&(r=i)&&(r=i)}),r},Li=(e,n,t)=>{let r,o;return t.forEach(i=>{let s=i.getValue(e);s!=null&&(r===void 0?s>=s&&(r=o=s):(r>s&&(r=s),o{let t=0,r=0;if(n.forEach(o=>{let i=o.getValue(e);i!=null&&(i=+i)>=i&&(++t,r+=i)}),t)return r/t},Hi=(e,n)=>{if(!n.length)return;let t=n.map(i=>i.getValue(e));if(!xi(t))return;if(t.length===1)return t[0];let r=Math.floor(t.length/2),o=t.sort((i,s)=>i-s);return t.length%2!==0?o[r]:(o[r-1]+o[r])/2},Ai=(e,n)=>Array.from(new Set(n.map(t=>t.getValue(e))).values()),Ni=(e,n)=>new Set(n.map(t=>t.getValue(e))).size,zi=(e,n)=>n.length,Zt={sum:Di,min:$i,max:Oi,extent:Li,mean:ki,median:Hi,unique:Ai,uniqueCount:Ni,count:zi},Gi={getDefaultColumnDef:()=>({aggregatedCell:e=>{var n,t;return(n=(t=e.getValue())==null||t.toString==null?void 0:t.toString())!=null?n:null},aggregationFn:"auto"}),getInitialState:e=>({grouping:[],...e}),getDefaultOptions:e=>({onGroupingChange:Q("grouping",e),groupedColumnMode:"reorder"}),createColumn:(e,n)=>{e.toggleGrouping=()=>{n.setGrouping(t=>t!=null&&t.includes(e.id)?t.filter(r=>r!==e.id):[...t??[],e.id])},e.getCanGroup=()=>{var t,r;return((t=e.columnDef.enableGrouping)!=null?t:!0)&&((r=n.options.enableGrouping)!=null?r:!0)&&(!!e.accessorFn||!!e.columnDef.getGroupingValue)},e.getIsGrouped=()=>{var t;return(t=n.getState().grouping)==null?void 0:t.includes(e.id)},e.getGroupedIndex=()=>{var t;return(t=n.getState().grouping)==null?void 0:t.indexOf(e.id)},e.getToggleGroupingHandler=()=>{let t=e.getCanGroup();return()=>{t&&e.toggleGrouping()}},e.getAutoAggregationFn=()=>{let t=n.getCoreRowModel().flatRows[0],r=t?.getValue(e.id);if(typeof r=="number")return Zt.sum;if(Object.prototype.toString.call(r)==="[object Date]")return Zt.extent},e.getAggregationFn=()=>{var t,r;if(!e)throw new Error;return ft(e.columnDef.aggregationFn)?e.columnDef.aggregationFn:e.columnDef.aggregationFn==="auto"?e.getAutoAggregationFn():(t=(r=n.options.aggregationFns)==null?void 0:r[e.columnDef.aggregationFn])!=null?t:Zt[e.columnDef.aggregationFn]}},createTable:e=>{e.setGrouping=n=>e.options.onGroupingChange==null?void 0:e.options.onGroupingChange(n),e.resetGrouping=n=>{var t,r;e.setGrouping(n?[]:(t=(r=e.initialState)==null?void 0:r.grouping)!=null?t:[])},e.getPreGroupedRowModel=()=>e.getFilteredRowModel(),e.getGroupedRowModel=()=>(!e._getGroupedRowModel&&e.options.getGroupedRowModel&&(e._getGroupedRowModel=e.options.getGroupedRowModel(e)),e.options.manualGrouping||!e._getGroupedRowModel?e.getPreGroupedRowModel():e._getGroupedRowModel())},createRow:(e,n)=>{e.getIsGrouped=()=>!!e.groupingColumnId,e.getGroupingValue=t=>{if(e._groupingValuesCache.hasOwnProperty(t))return e._groupingValuesCache[t];let r=n.getColumn(t);return r!=null&&r.columnDef.getGroupingValue?(e._groupingValuesCache[t]=r.columnDef.getGroupingValue(e.original),e._groupingValuesCache[t]):e.getValue(t)},e._groupingValuesCache={}},createCell:(e,n,t,r)=>{e.getIsGrouped=()=>n.getIsGrouped()&&n.id===t.groupingColumnId,e.getIsPlaceholder=()=>!e.getIsGrouped()&&n.getIsGrouped(),e.getIsAggregated=()=>{var o;return!e.getIsGrouped()&&!e.getIsPlaceholder()&&!!((o=t.subRows)!=null&&o.length)}}};function Bi(e,n,t){if(!(n!=null&&n.length)||!t)return e;let r=e.filter(i=>!n.includes(i.id));return t==="remove"?r:[...n.map(i=>e.find(s=>s.id===i)).filter(Boolean),...r]}var Ui={getInitialState:e=>({columnOrder:[],...e}),getDefaultOptions:e=>({onColumnOrderChange:Q("columnOrder",e)}),createColumn:(e,n)=>{e.getIndex=w(t=>[Ye(n,t)],t=>t.findIndex(r=>r.id===e.id),C(n.options,"debugColumns","getIndex")),e.getIsFirstColumn=t=>{var r;return((r=Ye(n,t)[0])==null?void 0:r.id)===e.id},e.getIsLastColumn=t=>{var r;let o=Ye(n,t);return((r=o[o.length-1])==null?void 0:r.id)===e.id}},createTable:e=>{e.setColumnOrder=n=>e.options.onColumnOrderChange==null?void 0:e.options.onColumnOrderChange(n),e.resetColumnOrder=n=>{var t;e.setColumnOrder(n?[]:(t=e.initialState.columnOrder)!=null?t:[])},e._getOrderColumnsFn=w(()=>[e.getState().columnOrder,e.getState().grouping,e.options.groupedColumnMode],(n,t,r)=>o=>{let i=[];if(!(n!=null&&n.length))i=o;else{let s=[...n],a=[...o];for(;a.length&&s.length;){let l=s.shift(),u=a.findIndex(f=>f.id===l);u>-1&&i.push(a.splice(u,1)[0])}i=[...i,...a]}return Bi(i,t,r)},C(e.options,"debugTable","_getOrderColumnsFn"))}},en=()=>({left:[],right:[]}),Ki={getInitialState:e=>({columnPinning:en(),...e}),getDefaultOptions:e=>({onColumnPinningChange:Q("columnPinning",e)}),createColumn:(e,n)=>{e.pin=t=>{let r=e.getLeafColumns().map(o=>o.id).filter(Boolean);n.setColumnPinning(o=>{var i,s;if(t==="right"){var a,l;return{left:((a=o?.left)!=null?a:[]).filter(c=>!(r!=null&&r.includes(c))),right:[...((l=o?.right)!=null?l:[]).filter(c=>!(r!=null&&r.includes(c))),...r]}}if(t==="left"){var u,f;return{left:[...((u=o?.left)!=null?u:[]).filter(c=>!(r!=null&&r.includes(c))),...r],right:((f=o?.right)!=null?f:[]).filter(c=>!(r!=null&&r.includes(c)))}}return{left:((i=o?.left)!=null?i:[]).filter(c=>!(r!=null&&r.includes(c))),right:((s=o?.right)!=null?s:[]).filter(c=>!(r!=null&&r.includes(c)))}})},e.getCanPin=()=>e.getLeafColumns().some(r=>{var o,i,s;return((o=r.columnDef.enablePinning)!=null?o:!0)&&((i=(s=n.options.enableColumnPinning)!=null?s:n.options.enablePinning)!=null?i:!0)}),e.getIsPinned=()=>{let t=e.getLeafColumns().map(a=>a.id),{left:r,right:o}=n.getState().columnPinning,i=t.some(a=>r?.includes(a)),s=t.some(a=>o?.includes(a));return i?"left":s?"right":!1},e.getPinnedIndex=()=>{var t,r;let o=e.getIsPinned();return o?(t=(r=n.getState().columnPinning)==null||(r=r[o])==null?void 0:r.indexOf(e.id))!=null?t:-1:0}},createRow:(e,n)=>{e.getCenterVisibleCells=w(()=>[e._getAllVisibleCells(),n.getState().columnPinning.left,n.getState().columnPinning.right],(t,r,o)=>{let i=[...r??[],...o??[]];return t.filter(s=>!i.includes(s.column.id))},C(n.options,"debugRows","getCenterVisibleCells")),e.getLeftVisibleCells=w(()=>[e._getAllVisibleCells(),n.getState().columnPinning.left],(t,r)=>(r??[]).map(i=>t.find(s=>s.column.id===i)).filter(Boolean).map(i=>({...i,position:"left"})),C(n.options,"debugRows","getLeftVisibleCells")),e.getRightVisibleCells=w(()=>[e._getAllVisibleCells(),n.getState().columnPinning.right],(t,r)=>(r??[]).map(i=>t.find(s=>s.column.id===i)).filter(Boolean).map(i=>({...i,position:"right"})),C(n.options,"debugRows","getRightVisibleCells"))},createTable:e=>{e.setColumnPinning=n=>e.options.onColumnPinningChange==null?void 0:e.options.onColumnPinningChange(n),e.resetColumnPinning=n=>{var t,r;return e.setColumnPinning(n?en():(t=(r=e.initialState)==null?void 0:r.columnPinning)!=null?t:en())},e.getIsSomeColumnsPinned=n=>{var t;let r=e.getState().columnPinning;if(!n){var o,i;return!!((o=r.left)!=null&&o.length||(i=r.right)!=null&&i.length)}return!!((t=r[n])!=null&&t.length)},e.getLeftLeafColumns=w(()=>[e.getAllLeafColumns(),e.getState().columnPinning.left],(n,t)=>(t??[]).map(r=>n.find(o=>o.id===r)).filter(Boolean),C(e.options,"debugColumns","getLeftLeafColumns")),e.getRightLeafColumns=w(()=>[e.getAllLeafColumns(),e.getState().columnPinning.right],(n,t)=>(t??[]).map(r=>n.find(o=>o.id===r)).filter(Boolean),C(e.options,"debugColumns","getRightLeafColumns")),e.getCenterLeafColumns=w(()=>[e.getAllLeafColumns(),e.getState().columnPinning.left,e.getState().columnPinning.right],(n,t,r)=>{let o=[...t??[],...r??[]];return n.filter(i=>!o.includes(i.id))},C(e.options,"debugColumns","getCenterLeafColumns"))}},dt={size:150,minSize:20,maxSize:Number.MAX_SAFE_INTEGER},tn=()=>({startOffset:null,startSize:null,deltaOffset:null,deltaPercentage:null,isResizingColumn:!1,columnSizingStart:[]}),ji={getDefaultColumnDef:()=>dt,getInitialState:e=>({columnSizing:{},columnSizingInfo:tn(),...e}),getDefaultOptions:e=>({columnResizeMode:"onEnd",columnResizeDirection:"ltr",onColumnSizingChange:Q("columnSizing",e),onColumnSizingInfoChange:Q("columnSizingInfo",e)}),createColumn:(e,n)=>{e.getSize=()=>{var t,r,o;let i=n.getState().columnSizing[e.id];return Math.min(Math.max((t=e.columnDef.minSize)!=null?t:dt.minSize,(r=i??e.columnDef.size)!=null?r:dt.size),(o=e.columnDef.maxSize)!=null?o:dt.maxSize)},e.getStart=w(t=>[t,Ye(n,t),n.getState().columnSizing],(t,r)=>r.slice(0,e.getIndex(t)).reduce((o,i)=>o+i.getSize(),0),C(n.options,"debugColumns","getStart")),e.getAfter=w(t=>[t,Ye(n,t),n.getState().columnSizing],(t,r)=>r.slice(e.getIndex(t)+1).reduce((o,i)=>o+i.getSize(),0),C(n.options,"debugColumns","getAfter")),e.resetSize=()=>{n.setColumnSizing(t=>{let{[e.id]:r,...o}=t;return o})},e.getCanResize=()=>{var t,r;return((t=e.columnDef.enableResizing)!=null?t:!0)&&((r=n.options.enableColumnResizing)!=null?r:!0)},e.getIsResizing=()=>n.getState().columnSizingInfo.isResizingColumn===e.id},createHeader:(e,n)=>{e.getSize=()=>{let t=0,r=o=>{if(o.subHeaders.length)o.subHeaders.forEach(r);else{var i;t+=(i=o.column.getSize())!=null?i:0}};return r(e),t},e.getStart=()=>{if(e.index>0){let t=e.headerGroup.headers[e.index-1];return t.getStart()+t.getSize()}return 0},e.getResizeHandler=t=>{let r=n.getColumn(e.column.id),o=r?.getCanResize();return i=>{if(!r||!o||(i.persist==null||i.persist(),nn(i)&&i.touches&&i.touches.length>1))return;let s=e.getSize(),a=e?e.getLeafHeaders().map(h=>[h.column.id,h.column.getSize()]):[[r.id,r.getSize()]],l=nn(i)?Math.round(i.touches[0].clientX):i.clientX,u={},f=(h,y)=>{typeof y=="number"&&(n.setColumnSizingInfo(R=>{var V,T;let D=n.options.columnResizeDirection==="rtl"?-1:1,z=(y-((V=R?.startOffset)!=null?V:0))*D,U=Math.max(z/((T=R?.startSize)!=null?T:0),-.999999);return R.columnSizingStart.forEach(G=>{let[q,te]=G;u[q]=Math.round(Math.max(te+te*U,0)*100)/100}),{...R,deltaOffset:z,deltaPercentage:U}}),(n.options.columnResizeMode==="onChange"||h==="end")&&n.setColumnSizing(R=>({...R,...u})))},c=h=>f("move",h),g=h=>{f("end",h),n.setColumnSizingInfo(y=>({...y,isResizingColumn:!1,startOffset:null,startSize:null,deltaOffset:null,deltaPercentage:null,columnSizingStart:[]}))},d=t||typeof document<"u"?document:null,p={moveHandler:h=>c(h.clientX),upHandler:h=>{d?.removeEventListener("mousemove",p.moveHandler),d?.removeEventListener("mouseup",p.upHandler),g(h.clientX)}},m={moveHandler:h=>(h.cancelable&&(h.preventDefault(),h.stopPropagation()),c(h.touches[0].clientX),!1),upHandler:h=>{var y;d?.removeEventListener("touchmove",m.moveHandler),d?.removeEventListener("touchend",m.upHandler),h.cancelable&&(h.preventDefault(),h.stopPropagation()),g((y=h.touches[0])==null?void 0:y.clientX)}},_=qi()?{passive:!1}:!1;nn(i)?(d?.addEventListener("touchmove",m.moveHandler,_),d?.addEventListener("touchend",m.upHandler,_)):(d?.addEventListener("mousemove",p.moveHandler,_),d?.addEventListener("mouseup",p.upHandler,_)),n.setColumnSizingInfo(h=>({...h,startOffset:l,startSize:s,deltaOffset:0,deltaPercentage:0,columnSizingStart:a,isResizingColumn:r.id}))}}},createTable:e=>{e.setColumnSizing=n=>e.options.onColumnSizingChange==null?void 0:e.options.onColumnSizingChange(n),e.setColumnSizingInfo=n=>e.options.onColumnSizingInfoChange==null?void 0:e.options.onColumnSizingInfoChange(n),e.resetColumnSizing=n=>{var t;e.setColumnSizing(n?{}:(t=e.initialState.columnSizing)!=null?t:{})},e.resetHeaderSizeInfo=n=>{var t;e.setColumnSizingInfo(n?tn():(t=e.initialState.columnSizingInfo)!=null?t:tn())},e.getTotalSize=()=>{var n,t;return(n=(t=e.getHeaderGroups()[0])==null?void 0:t.headers.reduce((r,o)=>r+o.getSize(),0))!=null?n:0},e.getLeftTotalSize=()=>{var n,t;return(n=(t=e.getLeftHeaderGroups()[0])==null?void 0:t.headers.reduce((r,o)=>r+o.getSize(),0))!=null?n:0},e.getCenterTotalSize=()=>{var n,t;return(n=(t=e.getCenterHeaderGroups()[0])==null?void 0:t.headers.reduce((r,o)=>r+o.getSize(),0))!=null?n:0},e.getRightTotalSize=()=>{var n,t;return(n=(t=e.getRightHeaderGroups()[0])==null?void 0:t.headers.reduce((r,o)=>r+o.getSize(),0))!=null?n:0}}},ct=null;function qi(){if(typeof ct=="boolean")return ct;let e=!1;try{let n={get passive(){return e=!0,!1}},t=()=>{};window.addEventListener("test",t,n),window.removeEventListener("test",t)}catch{e=!1}return ct=e,ct}function nn(e){return e.type==="touchstart"}var Wi={getInitialState:e=>({columnVisibility:{},...e}),getDefaultOptions:e=>({onColumnVisibilityChange:Q("columnVisibility",e)}),createColumn:(e,n)=>{e.toggleVisibility=t=>{e.getCanHide()&&n.setColumnVisibility(r=>({...r,[e.id]:t??!e.getIsVisible()}))},e.getIsVisible=()=>{var t,r;let o=e.columns;return(t=o.length?o.some(i=>i.getIsVisible()):(r=n.getState().columnVisibility)==null?void 0:r[e.id])!=null?t:!0},e.getCanHide=()=>{var t,r;return((t=e.columnDef.enableHiding)!=null?t:!0)&&((r=n.options.enableHiding)!=null?r:!0)},e.getToggleVisibilityHandler=()=>t=>{e.toggleVisibility==null||e.toggleVisibility(t.target.checked)}},createRow:(e,n)=>{e._getAllVisibleCells=w(()=>[e.getAllCells(),n.getState().columnVisibility],t=>t.filter(r=>r.column.getIsVisible()),C(n.options,"debugRows","_getAllVisibleCells")),e.getVisibleCells=w(()=>[e.getLeftVisibleCells(),e.getCenterVisibleCells(),e.getRightVisibleCells()],(t,r,o)=>[...t,...r,...o],C(n.options,"debugRows","getVisibleCells"))},createTable:e=>{let n=(t,r)=>w(()=>[r(),r().filter(o=>o.getIsVisible()).map(o=>o.id).join("_")],o=>o.filter(i=>i.getIsVisible==null?void 0:i.getIsVisible()),C(e.options,"debugColumns",t));e.getVisibleFlatColumns=n("getVisibleFlatColumns",()=>e.getAllFlatColumns()),e.getVisibleLeafColumns=n("getVisibleLeafColumns",()=>e.getAllLeafColumns()),e.getLeftVisibleLeafColumns=n("getLeftVisibleLeafColumns",()=>e.getLeftLeafColumns()),e.getRightVisibleLeafColumns=n("getRightVisibleLeafColumns",()=>e.getRightLeafColumns()),e.getCenterVisibleLeafColumns=n("getCenterVisibleLeafColumns",()=>e.getCenterLeafColumns()),e.setColumnVisibility=t=>e.options.onColumnVisibilityChange==null?void 0:e.options.onColumnVisibilityChange(t),e.resetColumnVisibility=t=>{var r;e.setColumnVisibility(t?{}:(r=e.initialState.columnVisibility)!=null?r:{})},e.toggleAllColumnsVisible=t=>{var r;t=(r=t)!=null?r:!e.getIsAllColumnsVisible(),e.setColumnVisibility(e.getAllLeafColumns().reduce((o,i)=>({...o,[i.id]:t||!(i.getCanHide!=null&&i.getCanHide())}),{}))},e.getIsAllColumnsVisible=()=>!e.getAllLeafColumns().some(t=>!(t.getIsVisible!=null&&t.getIsVisible())),e.getIsSomeColumnsVisible=()=>e.getAllLeafColumns().some(t=>t.getIsVisible==null?void 0:t.getIsVisible()),e.getToggleAllColumnsVisibilityHandler=()=>t=>{var r;e.toggleAllColumnsVisible((r=t.target)==null?void 0:r.checked)}}};function Ye(e,n){return n?n==="center"?e.getCenterVisibleLeafColumns():n==="left"?e.getLeftVisibleLeafColumns():e.getRightVisibleLeafColumns():e.getVisibleLeafColumns()}var Xi={createTable:e=>{e._getGlobalFacetedRowModel=e.options.getFacetedRowModel&&e.options.getFacetedRowModel(e,"__global__"),e.getGlobalFacetedRowModel=()=>e.options.manualFiltering||!e._getGlobalFacetedRowModel?e.getPreFilteredRowModel():e._getGlobalFacetedRowModel(),e._getGlobalFacetedUniqueValues=e.options.getFacetedUniqueValues&&e.options.getFacetedUniqueValues(e,"__global__"),e.getGlobalFacetedUniqueValues=()=>e._getGlobalFacetedUniqueValues?e._getGlobalFacetedUniqueValues():new Map,e._getGlobalFacetedMinMaxValues=e.options.getFacetedMinMaxValues&&e.options.getFacetedMinMaxValues(e,"__global__"),e.getGlobalFacetedMinMaxValues=()=>{if(e._getGlobalFacetedMinMaxValues)return e._getGlobalFacetedMinMaxValues()}}},Yi={getInitialState:e=>({globalFilter:void 0,...e}),getDefaultOptions:e=>({onGlobalFilterChange:Q("globalFilter",e),globalFilterFn:"auto",getColumnCanGlobalFilter:n=>{var t;let r=(t=e.getCoreRowModel().flatRows[0])==null||(t=t._getAllCellsByColumnId()[n.id])==null?void 0:t.getValue();return typeof r=="string"||typeof r=="number"}}),createColumn:(e,n)=>{e.getCanGlobalFilter=()=>{var t,r,o,i;return((t=e.columnDef.enableGlobalFilter)!=null?t:!0)&&((r=n.options.enableGlobalFilter)!=null?r:!0)&&((o=n.options.enableFilters)!=null?o:!0)&&((i=n.options.getColumnCanGlobalFilter==null?void 0:n.options.getColumnCanGlobalFilter(e))!=null?i:!0)&&!!e.accessorFn}},createTable:e=>{e.getGlobalAutoFilterFn=()=>he.includesString,e.getGlobalFilterFn=()=>{var n,t;let{globalFilterFn:r}=e.options;return ft(r)?r:r==="auto"?e.getGlobalAutoFilterFn():(n=(t=e.options.filterFns)==null?void 0:t[r])!=null?n:he[r]},e.setGlobalFilter=n=>{e.options.onGlobalFilterChange==null||e.options.onGlobalFilterChange(n)},e.resetGlobalFilter=n=>{e.setGlobalFilter(n?void 0:e.initialState.globalFilter)}}},Ji={getInitialState:e=>({expanded:{},...e}),getDefaultOptions:e=>({onExpandedChange:Q("expanded",e),paginateExpandedRows:!0}),createTable:e=>{let n=!1,t=!1;e._autoResetExpanded=()=>{var r,o;if(!n){e._queue(()=>{n=!0});return}if((r=(o=e.options.autoResetAll)!=null?o:e.options.autoResetExpanded)!=null?r:!e.options.manualExpanding){if(t)return;t=!0,e._queue(()=>{e.resetExpanded(),t=!1})}},e.setExpanded=r=>e.options.onExpandedChange==null?void 0:e.options.onExpandedChange(r),e.toggleAllRowsExpanded=r=>{r??!e.getIsAllRowsExpanded()?e.setExpanded(!0):e.setExpanded({})},e.resetExpanded=r=>{var o,i;e.setExpanded(r?{}:(o=(i=e.initialState)==null?void 0:i.expanded)!=null?o:{})},e.getCanSomeRowsExpand=()=>e.getPrePaginationRowModel().flatRows.some(r=>r.getCanExpand()),e.getToggleAllRowsExpandedHandler=()=>r=>{r.persist==null||r.persist(),e.toggleAllRowsExpanded()},e.getIsSomeRowsExpanded=()=>{let r=e.getState().expanded;return r===!0||Object.values(r).some(Boolean)},e.getIsAllRowsExpanded=()=>{let r=e.getState().expanded;return typeof r=="boolean"?r===!0:!(!Object.keys(r).length||e.getRowModel().flatRows.some(o=>!o.getIsExpanded()))},e.getExpandedDepth=()=>{let r=0;return(e.getState().expanded===!0?Object.keys(e.getRowModel().rowsById):Object.keys(e.getState().expanded)).forEach(i=>{let s=i.split(".");r=Math.max(r,s.length)}),r},e.getPreExpandedRowModel=()=>e.getSortedRowModel(),e.getExpandedRowModel=()=>(!e._getExpandedRowModel&&e.options.getExpandedRowModel&&(e._getExpandedRowModel=e.options.getExpandedRowModel(e)),e.options.manualExpanding||!e._getExpandedRowModel?e.getPreExpandedRowModel():e._getExpandedRowModel())},createRow:(e,n)=>{e.toggleExpanded=t=>{n.setExpanded(r=>{var o;let i=r===!0?!0:!!(r!=null&&r[e.id]),s={};if(r===!0?Object.keys(n.getRowModel().rowsById).forEach(a=>{s[a]=!0}):s=r,t=(o=t)!=null?o:!i,!i&&t)return{...s,[e.id]:!0};if(i&&!t){let{[e.id]:a,...l}=s;return l}return r})},e.getIsExpanded=()=>{var t;let r=n.getState().expanded;return!!((t=n.options.getIsRowExpanded==null?void 0:n.options.getIsRowExpanded(e))!=null?t:r===!0||r?.[e.id])},e.getCanExpand=()=>{var t,r,o;return(t=n.options.getRowCanExpand==null?void 0:n.options.getRowCanExpand(e))!=null?t:((r=n.options.enableExpanding)!=null?r:!0)&&!!((o=e.subRows)!=null&&o.length)},e.getIsAllParentsExpanded=()=>{let t=!0,r=e;for(;t&&r.parentId;)r=n.getRow(r.parentId,!0),t=r.getIsExpanded();return t},e.getToggleExpandedHandler=()=>{let t=e.getCanExpand();return()=>{t&&e.toggleExpanded()}}}},ln=0,an=10,rn=()=>({pageIndex:ln,pageSize:an}),Qi={getInitialState:e=>({...e,pagination:{...rn(),...e?.pagination}}),getDefaultOptions:e=>({onPaginationChange:Q("pagination",e)}),createTable:e=>{let n=!1,t=!1;e._autoResetPageIndex=()=>{var r,o;if(!n){e._queue(()=>{n=!0});return}if((r=(o=e.options.autoResetAll)!=null?o:e.options.autoResetPageIndex)!=null?r:!e.options.manualPagination){if(t)return;t=!0,e._queue(()=>{e.resetPageIndex(),t=!1})}},e.setPagination=r=>{let o=i=>we(r,i);return e.options.onPaginationChange==null?void 0:e.options.onPaginationChange(o)},e.resetPagination=r=>{var o;e.setPagination(r?rn():(o=e.initialState.pagination)!=null?o:rn())},e.setPageIndex=r=>{e.setPagination(o=>{let i=we(r,o.pageIndex),s=typeof e.options.pageCount>"u"||e.options.pageCount===-1?Number.MAX_SAFE_INTEGER:e.options.pageCount-1;return i=Math.max(0,Math.min(i,s)),{...o,pageIndex:i}})},e.resetPageIndex=r=>{var o,i;e.setPageIndex(r?ln:(o=(i=e.initialState)==null||(i=i.pagination)==null?void 0:i.pageIndex)!=null?o:ln)},e.resetPageSize=r=>{var o,i;e.setPageSize(r?an:(o=(i=e.initialState)==null||(i=i.pagination)==null?void 0:i.pageSize)!=null?o:an)},e.setPageSize=r=>{e.setPagination(o=>{let i=Math.max(1,we(r,o.pageSize)),s=o.pageSize*o.pageIndex,a=Math.floor(s/i);return{...o,pageIndex:a,pageSize:i}})},e.setPageCount=r=>e.setPagination(o=>{var i;let s=we(r,(i=e.options.pageCount)!=null?i:-1);return typeof s=="number"&&(s=Math.max(-1,s)),{...o,pageCount:s}}),e.getPageOptions=w(()=>[e.getPageCount()],r=>{let o=[];return r&&r>0&&(o=[...new Array(r)].fill(null).map((i,s)=>s)),o},C(e.options,"debugTable","getPageOptions")),e.getCanPreviousPage=()=>e.getState().pagination.pageIndex>0,e.getCanNextPage=()=>{let{pageIndex:r}=e.getState().pagination,o=e.getPageCount();return o===-1?!0:o===0?!1:re.setPageIndex(r=>r-1),e.nextPage=()=>e.setPageIndex(r=>r+1),e.firstPage=()=>e.setPageIndex(0),e.lastPage=()=>e.setPageIndex(e.getPageCount()-1),e.getPrePaginationRowModel=()=>e.getExpandedRowModel(),e.getPaginationRowModel=()=>(!e._getPaginationRowModel&&e.options.getPaginationRowModel&&(e._getPaginationRowModel=e.options.getPaginationRowModel(e)),e.options.manualPagination||!e._getPaginationRowModel?e.getPrePaginationRowModel():e._getPaginationRowModel()),e.getPageCount=()=>{var r;return(r=e.options.pageCount)!=null?r:Math.ceil(e.getRowCount()/e.getState().pagination.pageSize)},e.getRowCount=()=>{var r;return(r=e.options.rowCount)!=null?r:e.getPrePaginationRowModel().rows.length}}},on=()=>({top:[],bottom:[]}),Zi={getInitialState:e=>({rowPinning:on(),...e}),getDefaultOptions:e=>({onRowPinningChange:Q("rowPinning",e)}),createRow:(e,n)=>{e.pin=(t,r,o)=>{let i=r?e.getLeafRows().map(l=>{let{id:u}=l;return u}):[],s=o?e.getParentRows().map(l=>{let{id:u}=l;return u}):[],a=new Set([...s,e.id,...i]);n.setRowPinning(l=>{var u,f;if(t==="bottom"){var c,g;return{top:((c=l?.top)!=null?c:[]).filter(m=>!(a!=null&&a.has(m))),bottom:[...((g=l?.bottom)!=null?g:[]).filter(m=>!(a!=null&&a.has(m))),...Array.from(a)]}}if(t==="top"){var d,p;return{top:[...((d=l?.top)!=null?d:[]).filter(m=>!(a!=null&&a.has(m))),...Array.from(a)],bottom:((p=l?.bottom)!=null?p:[]).filter(m=>!(a!=null&&a.has(m)))}}return{top:((u=l?.top)!=null?u:[]).filter(m=>!(a!=null&&a.has(m))),bottom:((f=l?.bottom)!=null?f:[]).filter(m=>!(a!=null&&a.has(m)))}})},e.getCanPin=()=>{var t;let{enableRowPinning:r,enablePinning:o}=n.options;return typeof r=="function"?r(e):(t=r??o)!=null?t:!0},e.getIsPinned=()=>{let t=[e.id],{top:r,bottom:o}=n.getState().rowPinning,i=t.some(a=>r?.includes(a)),s=t.some(a=>o?.includes(a));return i?"top":s?"bottom":!1},e.getPinnedIndex=()=>{var t,r;let o=e.getIsPinned();if(!o)return-1;let i=(t=o==="top"?n.getTopRows():n.getBottomRows())==null?void 0:t.map(s=>{let{id:a}=s;return a});return(r=i?.indexOf(e.id))!=null?r:-1}},createTable:e=>{e.setRowPinning=n=>e.options.onRowPinningChange==null?void 0:e.options.onRowPinningChange(n),e.resetRowPinning=n=>{var t,r;return e.setRowPinning(n?on():(t=(r=e.initialState)==null?void 0:r.rowPinning)!=null?t:on())},e.getIsSomeRowsPinned=n=>{var t;let r=e.getState().rowPinning;if(!n){var o,i;return!!((o=r.top)!=null&&o.length||(i=r.bottom)!=null&&i.length)}return!!((t=r[n])!=null&&t.length)},e._getPinnedRows=(n,t,r)=>{var o;return((o=e.options.keepPinnedRows)==null||o?(t??[]).map(s=>{let a=e.getRow(s,!0);return a.getIsAllParentsExpanded()?a:null}):(t??[]).map(s=>n.find(a=>a.id===s))).filter(Boolean).map(s=>({...s,position:r}))},e.getTopRows=w(()=>[e.getRowModel().rows,e.getState().rowPinning.top],(n,t)=>e._getPinnedRows(n,t,"top"),C(e.options,"debugRows","getTopRows")),e.getBottomRows=w(()=>[e.getRowModel().rows,e.getState().rowPinning.bottom],(n,t)=>e._getPinnedRows(n,t,"bottom"),C(e.options,"debugRows","getBottomRows")),e.getCenterRows=w(()=>[e.getRowModel().rows,e.getState().rowPinning.top,e.getState().rowPinning.bottom],(n,t,r)=>{let o=new Set([...t??[],...r??[]]);return n.filter(i=>!o.has(i.id))},C(e.options,"debugRows","getCenterRows"))}},es={getInitialState:e=>({rowSelection:{},...e}),getDefaultOptions:e=>({onRowSelectionChange:Q("rowSelection",e),enableRowSelection:!0,enableMultiRowSelection:!0,enableSubRowSelection:!0}),createTable:e=>{e.setRowSelection=n=>e.options.onRowSelectionChange==null?void 0:e.options.onRowSelectionChange(n),e.resetRowSelection=n=>{var t;return e.setRowSelection(n?{}:(t=e.initialState.rowSelection)!=null?t:{})},e.toggleAllRowsSelected=n=>{e.setRowSelection(t=>{n=typeof n<"u"?n:!e.getIsAllRowsSelected();let r={...t},o=e.getPreGroupedRowModel().flatRows;return n?o.forEach(i=>{i.getCanSelect()&&(r[i.id]=!0)}):o.forEach(i=>{delete r[i.id]}),r})},e.toggleAllPageRowsSelected=n=>e.setRowSelection(t=>{let r=typeof n<"u"?n:!e.getIsAllPageRowsSelected(),o={...t};return e.getRowModel().rows.forEach(i=>{un(o,i.id,r,!0,e)}),o}),e.getPreSelectedRowModel=()=>e.getCoreRowModel(),e.getSelectedRowModel=w(()=>[e.getState().rowSelection,e.getCoreRowModel()],(n,t)=>Object.keys(n).length?sn(e,t):{rows:[],flatRows:[],rowsById:{}},C(e.options,"debugTable","getSelectedRowModel")),e.getFilteredSelectedRowModel=w(()=>[e.getState().rowSelection,e.getFilteredRowModel()],(n,t)=>Object.keys(n).length?sn(e,t):{rows:[],flatRows:[],rowsById:{}},C(e.options,"debugTable","getFilteredSelectedRowModel")),e.getGroupedSelectedRowModel=w(()=>[e.getState().rowSelection,e.getSortedRowModel()],(n,t)=>Object.keys(n).length?sn(e,t):{rows:[],flatRows:[],rowsById:{}},C(e.options,"debugTable","getGroupedSelectedRowModel")),e.getIsAllRowsSelected=()=>{let n=e.getFilteredRowModel().flatRows,{rowSelection:t}=e.getState(),r=!!(n.length&&Object.keys(t).length);return r&&n.some(o=>o.getCanSelect()&&!t[o.id])&&(r=!1),r},e.getIsAllPageRowsSelected=()=>{let n=e.getPaginationRowModel().flatRows.filter(o=>o.getCanSelect()),{rowSelection:t}=e.getState(),r=!!n.length;return r&&n.some(o=>!t[o.id])&&(r=!1),r},e.getIsSomeRowsSelected=()=>{var n;let t=Object.keys((n=e.getState().rowSelection)!=null?n:{}).length;return t>0&&t{let n=e.getPaginationRowModel().flatRows;return e.getIsAllPageRowsSelected()?!1:n.filter(t=>t.getCanSelect()).some(t=>t.getIsSelected()||t.getIsSomeSelected())},e.getToggleAllRowsSelectedHandler=()=>n=>{e.toggleAllRowsSelected(n.target.checked)},e.getToggleAllPageRowsSelectedHandler=()=>n=>{e.toggleAllPageRowsSelected(n.target.checked)}},createRow:(e,n)=>{e.toggleSelected=(t,r)=>{let o=e.getIsSelected();n.setRowSelection(i=>{var s;if(t=typeof t<"u"?t:!o,e.getCanSelect()&&o===t)return i;let a={...i};return un(a,e.id,t,(s=r?.selectChildren)!=null?s:!0,n),a})},e.getIsSelected=()=>{let{rowSelection:t}=n.getState();return pn(e,t)},e.getIsSomeSelected=()=>{let{rowSelection:t}=n.getState();return dn(e,t)==="some"},e.getIsAllSubRowsSelected=()=>{let{rowSelection:t}=n.getState();return dn(e,t)==="all"},e.getCanSelect=()=>{var t;return typeof n.options.enableRowSelection=="function"?n.options.enableRowSelection(e):(t=n.options.enableRowSelection)!=null?t:!0},e.getCanSelectSubRows=()=>{var t;return typeof n.options.enableSubRowSelection=="function"?n.options.enableSubRowSelection(e):(t=n.options.enableSubRowSelection)!=null?t:!0},e.getCanMultiSelect=()=>{var t;return typeof n.options.enableMultiRowSelection=="function"?n.options.enableMultiRowSelection(e):(t=n.options.enableMultiRowSelection)!=null?t:!0},e.getToggleSelectedHandler=()=>{let t=e.getCanSelect();return r=>{var o;t&&e.toggleSelected((o=r.target)==null?void 0:o.checked)}}}},un=(e,n,t,r,o)=>{var i;let s=o.getRow(n,!0);t?(s.getCanMultiSelect()||Object.keys(e).forEach(a=>delete e[a]),s.getCanSelect()&&(e[n]=!0)):delete e[n],r&&(i=s.subRows)!=null&&i.length&&s.getCanSelectSubRows()&&s.subRows.forEach(a=>un(e,a.id,t,r,o))};function sn(e,n){let t=e.getState().rowSelection,r=[],o={},i=function(s,a){return s.map(l=>{var u;let f=pn(l,t);if(f&&(r.push(l),o[l.id]=l),(u=l.subRows)!=null&&u.length&&(l={...l,subRows:i(l.subRows)}),f)return l}).filter(Boolean)};return{rows:i(n.rows),flatRows:r,rowsById:o}}function pn(e,n){var t;return(t=n[e.id])!=null?t:!1}function dn(e,n,t){var r;if(!((r=e.subRows)!=null&&r.length))return!1;let o=!0,i=!1;return e.subRows.forEach(s=>{if(!(i&&!o)&&(s.getCanSelect()&&(pn(s,n)?i=!0:o=!1),s.subRows&&s.subRows.length)){let a=dn(s,n);a==="all"?i=!0:(a==="some"&&(i=!0),o=!1)}}),o?"all":i?"some":!1}var cn=/([0-9]+)/gm,ts=(e,n,t)=>Vr(Ce(e.getValue(t)).toLowerCase(),Ce(n.getValue(t)).toLowerCase()),ns=(e,n,t)=>Vr(Ce(e.getValue(t)),Ce(n.getValue(t))),rs=(e,n,t)=>mn(Ce(e.getValue(t)).toLowerCase(),Ce(n.getValue(t)).toLowerCase()),os=(e,n,t)=>mn(Ce(e.getValue(t)),Ce(n.getValue(t))),is=(e,n,t)=>{let r=e.getValue(t),o=n.getValue(t);return r>o?1:rmn(e.getValue(t),n.getValue(t));function mn(e,n){return e===n?0:e>n?1:-1}function Ce(e){return typeof e=="number"?isNaN(e)||e===1/0||e===-1/0?"":String(e):typeof e=="string"?e:""}function Vr(e,n){let t=e.split(cn).filter(Boolean),r=n.split(cn).filter(Boolean);for(;t.length&&r.length;){let o=t.shift(),i=r.shift(),s=parseInt(o,10),a=parseInt(i,10),l=[s,a].sort();if(isNaN(l[0])){if(o>i)return 1;if(i>o)return-1;continue}if(isNaN(l[1]))return isNaN(s)?-1:1;if(s>a)return 1;if(a>s)return-1}return t.length-r.length}var Xe={alphanumeric:ts,alphanumericCaseSensitive:ns,text:rs,textCaseSensitive:os,datetime:is,basic:ss},ls={getInitialState:e=>({sorting:[],...e}),getDefaultColumnDef:()=>({sortingFn:"auto",sortUndefined:1}),getDefaultOptions:e=>({onSortingChange:Q("sorting",e),isMultiSortEvent:n=>n.shiftKey}),createColumn:(e,n)=>{e.getAutoSortingFn=()=>{let t=n.getFilteredRowModel().flatRows.slice(10),r=!1;for(let o of t){let i=o?.getValue(e.id);if(Object.prototype.toString.call(i)==="[object Date]")return Xe.datetime;if(typeof i=="string"&&(r=!0,i.split(cn).length>1))return Xe.alphanumeric}return r?Xe.text:Xe.basic},e.getAutoSortDir=()=>{let t=n.getFilteredRowModel().flatRows[0];return typeof t?.getValue(e.id)=="string"?"asc":"desc"},e.getSortingFn=()=>{var t,r;if(!e)throw new Error;return ft(e.columnDef.sortingFn)?e.columnDef.sortingFn:e.columnDef.sortingFn==="auto"?e.getAutoSortingFn():(t=(r=n.options.sortingFns)==null?void 0:r[e.columnDef.sortingFn])!=null?t:Xe[e.columnDef.sortingFn]},e.toggleSorting=(t,r)=>{let o=e.getNextSortingOrder(),i=typeof t<"u"&&t!==null;n.setSorting(s=>{let a=s?.find(d=>d.id===e.id),l=s?.findIndex(d=>d.id===e.id),u=[],f,c=i?t:o==="desc";if(s!=null&&s.length&&e.getCanMultiSort()&&r?a?f="toggle":f="add":s!=null&&s.length&&l!==s.length-1?f="replace":a?f="toggle":f="replace",f==="toggle"&&(i||o||(f="remove")),f==="add"){var g;u=[...s,{id:e.id,desc:c}],u.splice(0,u.length-((g=n.options.maxMultiSortColCount)!=null?g:Number.MAX_SAFE_INTEGER))}else f==="toggle"?u=s.map(d=>d.id===e.id?{...d,desc:c}:d):f==="remove"?u=s.filter(d=>d.id!==e.id):u=[{id:e.id,desc:c}];return u})},e.getFirstSortDir=()=>{var t,r;return((t=(r=e.columnDef.sortDescFirst)!=null?r:n.options.sortDescFirst)!=null?t:e.getAutoSortDir()==="desc")?"desc":"asc"},e.getNextSortingOrder=t=>{var r,o;let i=e.getFirstSortDir(),s=e.getIsSorted();return s?s!==i&&((r=n.options.enableSortingRemoval)==null||r)&&(!(t&&(o=n.options.enableMultiRemove)!=null)||o)?!1:s==="desc"?"asc":"desc":i},e.getCanSort=()=>{var t,r;return((t=e.columnDef.enableSorting)!=null?t:!0)&&((r=n.options.enableSorting)!=null?r:!0)&&!!e.accessorFn},e.getCanMultiSort=()=>{var t,r;return(t=(r=e.columnDef.enableMultiSort)!=null?r:n.options.enableMultiSort)!=null?t:!!e.accessorFn},e.getIsSorted=()=>{var t;let r=(t=n.getState().sorting)==null?void 0:t.find(o=>o.id===e.id);return r?r.desc?"desc":"asc":!1},e.getSortIndex=()=>{var t,r;return(t=(r=n.getState().sorting)==null?void 0:r.findIndex(o=>o.id===e.id))!=null?t:-1},e.clearSorting=()=>{n.setSorting(t=>t!=null&&t.length?t.filter(r=>r.id!==e.id):[])},e.getToggleSortingHandler=()=>{let t=e.getCanSort();return r=>{t&&(r.persist==null||r.persist(),e.toggleSorting==null||e.toggleSorting(void 0,e.getCanMultiSort()?n.options.isMultiSortEvent==null?void 0:n.options.isMultiSortEvent(r):!1))}}},createTable:e=>{e.setSorting=n=>e.options.onSortingChange==null?void 0:e.options.onSortingChange(n),e.resetSorting=n=>{var t,r;e.setSorting(n?[]:(t=(r=e.initialState)==null?void 0:r.sorting)!=null?t:[])},e.getPreSortedRowModel=()=>e.getGroupedRowModel(),e.getSortedRowModel=()=>(!e._getSortedRowModel&&e.options.getSortedRowModel&&(e._getSortedRowModel=e.options.getSortedRowModel(e)),e.options.manualSorting||!e._getSortedRowModel?e.getPreSortedRowModel():e._getSortedRowModel())}},as=[Ti,Wi,Ui,Ki,Pi,Vi,Xi,Yi,ls,Gi,Ji,Qi,Zi,es,ji];function Dr(e){var n,t;let r=[...as,...(n=e._features)!=null?n:[]],o={_features:r},i=o._features.reduce((g,d)=>Object.assign(g,d.getDefaultOptions==null?void 0:d.getDefaultOptions(o)),{}),s=g=>o.options.mergeOptions?o.options.mergeOptions(i,g):{...i,...g},l={...{},...(t=e.initialState)!=null?t:{}};o._features.forEach(g=>{var d;l=(d=g.getInitialState==null?void 0:g.getInitialState(l))!=null?d:l});let u=[],f=!1,c={_features:r,options:{...i,...e},initialState:l,_queue:g=>{u.push(g),f||(f=!0,Promise.resolve().then(()=>{for(;u.length;)u.shift()();f=!1}).catch(d=>setTimeout(()=>{throw d})))},reset:()=>{o.setState(o.initialState)},setOptions:g=>{let d=we(g,o.options);o.options=s(d)},getState:()=>o.options.state,setState:g=>{o.options.onStateChange==null||o.options.onStateChange(g)},_getRowId:(g,d,p)=>{var m;return(m=o.options.getRowId==null?void 0:o.options.getRowId(g,d,p))!=null?m:`${p?[p.id,d].join("."):d}`},getCoreRowModel:()=>(o._getCoreRowModel||(o._getCoreRowModel=o.options.getCoreRowModel(o)),o._getCoreRowModel()),getRowModel:()=>o.getPaginationRowModel(),getRow:(g,d)=>{let p=(d?o.getPrePaginationRowModel():o.getRowModel()).rowsById[g];if(!p&&(p=o.getCoreRowModel().rowsById[g],!p))throw new Error;return p},_getDefaultColumnDef:w(()=>[o.options.defaultColumn],g=>{var d;return g=(d=g)!=null?d:{},{header:p=>{let m=p.header.column.columnDef;return m.accessorKey?m.accessorKey:m.accessorFn?m.id:null},cell:p=>{var m,_;return(m=(_=p.renderValue())==null||_.toString==null?void 0:_.toString())!=null?m:null},...o._features.reduce((p,m)=>Object.assign(p,m.getDefaultColumnDef==null?void 0:m.getDefaultColumnDef()),{}),...g}},C(e,"debugColumns","_getDefaultColumnDef")),_getColumnDefs:()=>o.options.columns,getAllColumns:w(()=>[o._getColumnDefs()],g=>{let d=function(p,m,_){return _===void 0&&(_=0),p.map(h=>{let y=Ii(o,h,_,m),R=h;return y.columns=R.columns?d(R.columns,y,_+1):[],y})};return d(g)},C(e,"debugColumns","getAllColumns")),getAllFlatColumns:w(()=>[o.getAllColumns()],g=>g.flatMap(d=>d.getFlatColumns()),C(e,"debugColumns","getAllFlatColumns")),_getAllFlatColumnsById:w(()=>[o.getAllFlatColumns()],g=>g.reduce((d,p)=>(d[p.id]=p,d),{}),C(e,"debugColumns","getAllFlatColumnsById")),getAllLeafColumns:w(()=>[o.getAllColumns(),o._getOrderColumnsFn()],(g,d)=>{let p=g.flatMap(m=>m.getLeafColumns());return d(p)},C(e,"debugColumns","getAllLeafColumns")),getColumn:g=>o._getAllFlatColumnsById()[g]};Object.assign(o,c);for(let g=0;gw(()=>[e.options.data],n=>{let t={rows:[],flatRows:[],rowsById:{}},r=function(o,i,s){i===void 0&&(i=0);let a=[];for(let u=0;ue._autoResetPageIndex()))}function Or(){return(e,n)=>w(()=>{var t;return[(t=e.getColumn(n))==null?void 0:t.getFacetedRowModel()]},t=>{var r;if(!t)return;let o=(r=t.flatRows[0])==null?void 0:r.getUniqueValues(n);if(typeof o>"u")return;let i=[o,o];for(let s=0;si[1]&&(i[1]=u)}}return i},C(e.options,"debugTable","getFacetedMinMaxValues"))}function Lr(e,n,t){return t.options.filterFromLeafRows?us(e,n,t):ds(e,n,t)}function us(e,n,t){var r;let o=[],i={},s=(r=t.options.maxLeafRowFilterDepth)!=null?r:100,a=function(l,u){u===void 0&&(u=0);let f=[];for(let g=0;gw(()=>[e.getPreFilteredRowModel(),e.getState().columnFilters,e.getState().globalFilter,e.getFilteredRowModel()],(t,r,o)=>{if(!t.rows.length||!(r!=null&&r.length)&&!o)return t;let i=[...r.map(a=>a.id).filter(a=>a!==n),o?"__global__":void 0].filter(Boolean),s=a=>{for(let l=0;lw(()=>{var t;return[(t=e.getColumn(n))==null?void 0:t.getFacetedRowModel()]},t=>{if(!t)return new Map;let r=new Map;for(let i=0;iw(()=>[e.getPreFilteredRowModel(),e.getState().columnFilters,e.getState().globalFilter],(n,t,r)=>{if(!n.rows.length||!(t!=null&&t.length)&&!r){for(let g=0;g{var d;let p=e.getColumn(g.id);if(!p)return;let m=p.getFilterFn();m&&o.push({id:g.id,filterFn:m,resolvedValue:(d=m.resolveFilterValue==null?void 0:m.resolveFilterValue(g.value))!=null?d:g.value})});let s=(t??[]).map(g=>g.id),a=e.getGlobalFilterFn(),l=e.getAllLeafColumns().filter(g=>g.getCanGlobalFilter());r&&a&&l.length&&(s.push("__global__"),l.forEach(g=>{var d;i.push({id:g.id,filterFn:a,resolvedValue:(d=a.resolveFilterValue==null?void 0:a.resolveFilterValue(r))!=null?d:r})}));let u,f;for(let g=0;g{d.columnFiltersMeta[m]=_})}if(i.length){for(let p=0;p{d.columnFiltersMeta[m]=_})){d.columnFilters.__global__=!0;break}}d.columnFilters.__global__!==!0&&(d.columnFilters.__global__=!1)}}let c=g=>{for(let d=0;de._autoResetPageIndex()))}function Nr(){return e=>w(()=>[e.getState().sorting,e.getPreSortedRowModel()],(n,t)=>{if(!t.rows.length||!(n!=null&&n.length))return t;let r=e.getState().sorting,o=[],i=r.filter(l=>{var u;return(u=e.getColumn(l.id))==null?void 0:u.getCanSort()}),s={};i.forEach(l=>{let u=e.getColumn(l.id);u&&(s[l.id]={sortUndefined:u.columnDef.sortUndefined,invertSorting:u.columnDef.invertSorting,sortingFn:u.getSortingFn()})});let a=l=>{let u=l.map(f=>({...f}));return u.sort((f,c)=>{for(let d=0;d{var c;o.push(f),(c=f.subRows)!=null&&c.length&&(f.subRows=a(f.subRows))}),u};return{rows:a(t.rows),flatRows:o,rowsById:t.rowsById}},C(e.options,"debugTable","getSortedRowModel",()=>e._autoResetPageIndex()))}function gt(e,n){return e?cs(e)?J(e,n):e:null}function cs(e){return fs(e)||typeof e=="function"||gs(e)}function fs(e){return typeof e=="function"&&(()=>{let n=Object.getPrototypeOf(e);return n.prototype&&n.prototype.isReactComponent})()}function gs(e){return typeof e=="object"&&typeof e.$$typeof=="symbol"&&["react.memo","react.forward_ref"].includes(e.$$typeof.description)}function zr(e){let n={state:{},onStateChange:()=>{},renderFallbackValue:null,...e},[t]=H(()=>({current:Dr(n)})),[r,o]=H(()=>t.current.initialState);return t.current.setOptions(i=>({...i,...e,state:{...r,...e.state},onStateChange:s=>{o(s),e.onStateChange==null||e.onStateChange(s)}})),t.current}function De(e,n,t){let r=t.initialDeps??[],o;return()=>{var i,s,a,l;let u;t.key&&((i=t.debug)!=null&&i.call(t))&&(u=Date.now());let f=e();if(!(f.length!==r.length||f.some((d,p)=>r[p]!==d)))return o;r=f;let g;if(t.key&&((s=t.debug)!=null&&s.call(t))&&(g=Date.now()),o=n(...f),t.key&&((a=t.debug)!=null&&a.call(t))){let d=Math.round((Date.now()-u)*100)/100,p=Math.round((Date.now()-g)*100)/100,m=p/16,_=(h,y)=>{for(h=String(h);h.lengthMath.abs(e-n)<1,Gr=(e,n,t)=>{let r;return function(...o){e.clearTimeout(r),r=e.setTimeout(()=>n.apply(this,o),t)}};var ps=e=>e,hs=e=>{let n=Math.max(e.startIndex-e.overscan,0),t=Math.min(e.endIndex+e.overscan,e.count-1),r=[];for(let o=n;o<=t;o++)r.push(o);return r},Ur=(e,n)=>{let t=e.scrollElement;if(!t)return;let r=e.targetWindow;if(!r)return;let o=s=>{let{width:a,height:l}=s;n({width:Math.round(a),height:Math.round(l)})};if(o(t.getBoundingClientRect()),!r.ResizeObserver)return()=>{};let i=new r.ResizeObserver(s=>{let a=s[0];if(a?.borderBoxSize){let l=a.borderBoxSize[0];if(l){o({width:l.inlineSize,height:l.blockSize});return}}o(t.getBoundingClientRect())});return i.observe(t,{box:"border-box"}),()=>{i.unobserve(t)}},Br={passive:!0};var ms=typeof window>"u"?!0:"onscrollend"in window,Kr=(e,n)=>{let t=e.scrollElement;if(!t)return;let r=e.targetWindow;if(!r)return;let o=0,i=ms?()=>{}:Gr(r,()=>{n(o,!1)},e.options.isScrollingResetDelay),s=u=>()=>{o=t[e.options.horizontal?"scrollLeft":"scrollTop"],i(),n(o,u)},a=s(!0),l=s(!1);return l(),t.addEventListener("scroll",a,Br),t.addEventListener("scrollend",l,Br),()=>{t.removeEventListener("scroll",a),t.removeEventListener("scrollend",l)}};var _s=(e,n,t)=>{if(n?.borderBoxSize){let r=n.borderBoxSize[0];if(r)return Math.round(r[t.options.horizontal?"inlineSize":"blockSize"])}return Math.round(e.getBoundingClientRect()[t.options.horizontal?"width":"height"])};var jr=(e,{adjustments:n=0,behavior:t},r)=>{var o,i;let s=e+n;(i=(o=r.scrollElement)==null?void 0:o.scrollTo)==null||i.call(o,{[r.options.horizontal?"left":"top"]:s,behavior:t})},pt=class{constructor(n){this.unsubs=[],this.scrollElement=null,this.targetWindow=null,this.isScrolling=!1,this.scrollToIndexTimeoutId=null,this.measurementsCache=[],this.itemSizeCache=new Map,this.pendingMeasuredCacheIndexes=[],this.scrollRect=null,this.scrollOffset=null,this.scrollDirection=null,this.scrollAdjustments=0,this.elementsCache=new Map,this.observer=(()=>{let t=null,r=()=>t||(!this.targetWindow||!this.targetWindow.ResizeObserver?null:t=new this.targetWindow.ResizeObserver(o=>{o.forEach(i=>{this._measureElement(i.target,i)})}));return{disconnect:()=>{var o;return(o=r())==null?void 0:o.disconnect()},observe:o=>{var i;return(i=r())==null?void 0:i.observe(o,{box:"border-box"})},unobserve:o=>{var i;return(i=r())==null?void 0:i.unobserve(o)}}})(),this.range=null,this.setOptions=t=>{Object.entries(t).forEach(([r,o])=>{typeof o>"u"&&delete t[r]}),this.options={debug:!1,initialOffset:0,overscan:1,paddingStart:0,paddingEnd:0,scrollPaddingStart:0,scrollPaddingEnd:0,horizontal:!1,getItemKey:ps,rangeExtractor:hs,onChange:()=>{},measureElement:_s,initialRect:{width:0,height:0},scrollMargin:0,gap:0,indexAttribute:"data-index",initialMeasurementsCache:[],lanes:1,isScrollingResetDelay:150,enabled:!0,...t}},this.notify=(t,r)=>{var o,i;let{startIndex:s,endIndex:a}=this.range??{startIndex:void 0,endIndex:void 0},l=this.calculateRange();(t||s!==l?.startIndex||a!==l?.endIndex)&&((i=(o=this.options).onChange)==null||i.call(o,this,r))},this.cleanup=()=>{this.unsubs.filter(Boolean).forEach(t=>t()),this.unsubs=[],this.scrollElement=null,this.targetWindow=null,this.observer.disconnect(),this.elementsCache.clear()},this._didMount=()=>()=>{this.cleanup()},this._willUpdate=()=>{var t;let r=this.options.enabled?this.options.getScrollElement():null;if(this.scrollElement!==r){if(this.cleanup(),!r){this.notify(!1,!1);return}this.scrollElement=r,this.scrollElement&&"ownerDocument"in this.scrollElement?this.targetWindow=this.scrollElement.ownerDocument.defaultView:this.targetWindow=((t=this.scrollElement)==null?void 0:t.window)??null,this._scrollToOffset(this.getScrollOffset(),{adjustments:void 0,behavior:void 0}),this.unsubs.push(this.options.observeElementRect(this,o=>{this.scrollRect=o,this.notify(!1,!1)})),this.unsubs.push(this.options.observeElementOffset(this,(o,i)=>{this.scrollAdjustments=0,this.scrollDirection=i?this.getScrollOffset()this.options.enabled?(this.scrollRect=this.scrollRect??this.options.initialRect,this.scrollRect[this.options.horizontal?"width":"height"]):(this.scrollRect=null,0),this.getScrollOffset=()=>this.options.enabled?(this.scrollOffset=this.scrollOffset??(typeof this.options.initialOffset=="function"?this.options.initialOffset():this.options.initialOffset),this.scrollOffset):(this.scrollOffset=null,0),this.getFurthestMeasurement=(t,r)=>{let o=new Map,i=new Map;for(let s=r-1;s>=0;s--){let a=t[s];if(o.has(a.lane))continue;let l=i.get(a.lane);if(l==null||a.end>l.end?i.set(a.lane,a):a.ends.end===a.end?s.index-a.index:s.end-a.end)[0]:void 0},this.getMeasurementOptions=Ve(()=>[this.options.count,this.options.paddingStart,this.options.scrollMargin,this.options.getItemKey,this.options.enabled],(t,r,o,i,s)=>(this.pendingMeasuredCacheIndexes=[],{count:t,paddingStart:r,scrollMargin:o,getItemKey:i,enabled:s}),{key:!1}),this.getMeasurements=Ve(()=>[this.getMeasurementOptions(),this.itemSizeCache],({count:t,paddingStart:r,scrollMargin:o,getItemKey:i,enabled:s},a)=>{var l;if(!s)return this.measurementsCache=[],this.itemSizeCache.clear(),[];this.measurementsCache.length===0&&(this.measurementsCache=this.options.initialMeasurementsCache,this.measurementsCache.forEach(c=>{this.itemSizeCache.set(c.key,c.size)}));let u=this.pendingMeasuredCacheIndexes.length>0?Math.min(...this.pendingMeasuredCacheIndexes):0;this.pendingMeasuredCacheIndexes=[];let f=this.measurementsCache.slice(0,u);for(let c=u;c{let T=i(c),D=this.elementsCache.get(T);if(!V){D&&(this.observer.unobserve(D),this.elementsCache.delete(T));return}D!==V&&(D&&this.observer.unobserve(D),this.observer.observe(V),this.elementsCache.set(T,V)),V.isConnected&&this.resizeItem(c,this.options.measureElement(V,void 0,this))});let d=i(c),p=this.options.lanes===1?f[c-1]:this.getFurthestMeasurement(f,c),h=p?p.end+this.options.gap:r+o,_=a.get(d),m=typeof _=="number"?_:this.options.estimateSize(c),y=h+m,R=p?p.lane:c%this.options.lanes;f[c]={index:c,start:h,size:m,end:y,key:d,lane:R,measureElement:g}}return this.measurementsCache=f,f},{key:!1,debug:()=>this.options.debug}),this.calculateRange=Ve(()=>[this.getMeasurements(),this.getSize(),this.getScrollOffset()],(t,r,o)=>this.range=t.length>0&&r>0?ys({measurements:t,outerSize:r,scrollOffset:o}):null,{key:!1,debug:()=>this.options.debug}),this.getIndexes=Ve(()=>[this.options.rangeExtractor,this.calculateRange(),this.options.overscan,this.options.count],(t,r,o,i)=>r===null?[]:t({startIndex:r.startIndex,endIndex:r.endIndex,overscan:o,count:i}),{key:!1,debug:()=>this.options.debug}),this.indexFromElement=t=>{let r=this.options.indexAttribute,o=t.getAttribute(r);return o?parseInt(o,10):(console.warn(`Missing attribute name '${r}={index}' on measured element.`),-1)},this._measureElement=(t,r)=>{let o=this.indexFromElement(t),i=this.getMeasurements()[o];if(!i||!t.isConnected){this.elementsCache.forEach((a,l)=>{a===t&&(this.observer.unobserve(t),this.elementsCache.delete(l))});return}let s=this.elementsCache.get(i.key);s!==t&&(s&&this.observer.unobserve(s),this.observer.observe(t),this.elementsCache.set(i.key,t)),this.resizeItem(o,this.options.measureElement(t,r,this))},this.resizeItem=(t,r)=>{let o=this.getMeasurements()[t];if(!o)return;let i=this.itemSizeCache.get(o.key)??o.size,s=r-i;s!==0&&((this.shouldAdjustScrollPositionOnItemSizeChange!==void 0?this.shouldAdjustScrollPositionOnItemSizeChange(o,s,this):o.start{t&&this._measureElement(t,void 0)},this.getVirtualItems=Ve(()=>[this.getIndexes(),this.getMeasurements()],(t,r)=>{let o=[];for(let i=0,s=t.length;ithis.options.debug}),this.getVirtualItemForOffset=t=>{let r=this.getMeasurements();if(r.length!==0)return gt(r[qr(0,r.length-1,o=>gt(r[o]).start,t)])},this.getOffsetForAlignment=(t,r)=>{let o=this.getSize(),i=this.getScrollOffset();r==="auto"&&(t<=i?r="start":t>=i+o?r="end":r="start"),r==="start"?t=t:r==="end"?t=t-o:r==="center"&&(t=t-o/2);let s=this.options.horizontal?"scrollWidth":"scrollHeight",l=(this.scrollElement?"document"in this.scrollElement?this.scrollElement.document.documentElement[s]:this.scrollElement[s]:0)-o;return Math.max(Math.min(l,t),0)},this.getOffsetForIndex=(t,r="auto")=>{t=Math.max(0,Math.min(t,this.options.count-1));let o=this.getMeasurements()[t];if(!o)return;let i=this.getSize(),s=this.getScrollOffset();if(r==="auto")if(o.end>=s+i-this.options.scrollPaddingEnd)r="end";else if(o.start<=s+this.options.scrollPaddingStart)r="start";else return[s,r];let a=r==="end"?o.end+this.options.scrollPaddingEnd:o.start-this.options.scrollPaddingStart;return[this.getOffsetForAlignment(a,r),r]},this.isDynamicMode=()=>this.elementsCache.size>0,this.cancelScrollToIndex=()=>{this.scrollToIndexTimeoutId!==null&&this.targetWindow&&(this.targetWindow.clearTimeout(this.scrollToIndexTimeoutId),this.scrollToIndexTimeoutId=null)},this.scrollToOffset=(t,{align:r="start",behavior:o}={})=>{this.cancelScrollToIndex(),o==="smooth"&&this.isDynamicMode()&&console.warn("The `smooth` scroll behavior is not fully supported with dynamic size."),this._scrollToOffset(this.getOffsetForAlignment(t,r),{adjustments:void 0,behavior:o})},this.scrollToIndex=(t,{align:r="auto",behavior:o}={})=>{t=Math.max(0,Math.min(t,this.options.count-1)),this.cancelScrollToIndex(),o==="smooth"&&this.isDynamicMode()&&console.warn("The `smooth` scroll behavior is not fully supported with dynamic size.");let i=this.getOffsetForIndex(t,r);if(!i)return;let[s,a]=i;this._scrollToOffset(s,{adjustments:void 0,behavior:o}),o!=="smooth"&&this.isDynamicMode()&&this.targetWindow&&(this.scrollToIndexTimeoutId=this.targetWindow.setTimeout(()=>{if(this.scrollToIndexTimeoutId=null,this.elementsCache.has(this.options.getItemKey(t))){let[u]=gt(this.getOffsetForIndex(t,a));zr(u,this.getScrollOffset())||this.scrollToIndex(t,{align:a,behavior:o})}else this.scrollToIndex(t,{align:a,behavior:o})}))},this.scrollBy=(t,{behavior:r}={})=>{this.cancelScrollToIndex(),r==="smooth"&&this.isDynamicMode()&&console.warn("The `smooth` scroll behavior is not fully supported with dynamic size."),this._scrollToOffset(this.getScrollOffset()+t,{adjustments:void 0,behavior:r})},this.getTotalSize=()=>{var t;let r=this.getMeasurements(),o;return r.length===0?o=this.options.paddingStart:o=this.options.lanes===1?((t=r[r.length-1])==null?void 0:t.end)??0:Math.max(...r.slice(-this.options.lanes).map(i=>i.end)),o-this.options.scrollMargin+this.options.paddingEnd},this._scrollToOffset=(t,{adjustments:r,behavior:o})=>{this.options.scrollToFn(t,{behavior:o,adjustments:r},this)},this.measure=()=>{var t,r;this.itemSizeCache=new Map,(r=(t=this.options).onChange)==null||r.call(t,this,!1)},this.setOptions(n)}},qr=(e,n,t,r)=>{for(;e<=n;){let o=(e+n)/2|0,i=t(o);if(ir)n=o-1;else return o}return e>0?e-1:0};function ys({measurements:e,outerSize:n,scrollOffset:t}){let r=e.length-1,i=qr(0,r,a=>e[a].start,t),s=i;for(;s({}),{})[1],t={...e,onChange:(o,i)=>{var s;i?Yt(n):n(),(s=e.onChange)==null||s.call(e,o,i)}},[r]=H(()=>new pt(t));return r.setOptions(t),L(()=>r._didMount(),[]),vs(()=>r._willUpdate()),r}function Wr(e){return Ss({observeElementRect:Ur,observeElementOffset:Kr,scrollToFn:jr,...e})}function Xr(e){return{render:function(n){qt(n,e)},unmount:function(){Xt(e)}}}var to=Symbol.for("immer-nothing"),Yr=Symbol.for("immer-draftable"),P=Symbol.for("immer-state");function ie(e,...n){throw new Error(`[Immer] minified error nr: ${e}. Full error at: https://bit.ly/3cXEKWf`)}var De=Object.getPrototypeOf;function $e(e){return!!e&&!!e[P]}function ye(e){return e?no(e)||Array.isArray(e)||!!e[Yr]||!!e.constructor?.[Yr]||vt(e)||St(e):!1}var ws=Object.prototype.constructor.toString();function no(e){if(!e||typeof e!="object")return!1;let n=De(e);if(n===null)return!0;let t=Object.hasOwnProperty.call(n,"constructor")&&n.constructor;return t===Object?!0:typeof t=="function"&&Function.toString.call(t)===ws}function Oe(e,n){yt(e)===0?Object.entries(e).forEach(([t,r])=>{n(t,r,e)}):e.forEach((t,r)=>n(r,t,e))}function yt(e){let n=e[P];return n?n.type_:Array.isArray(e)?1:vt(e)?2:St(e)?3:0}function _n(e,n){return yt(e)===2?e.has(n):Object.prototype.hasOwnProperty.call(e,n)}function ro(e,n,t){let r=yt(e);r===2?e.set(n,t):r===3?e.add(t):e[n]=t}function Cs(e,n){return e===n?e!==0||1/e===1/n:e!==e&&n!==n}function vt(e){return e instanceof Map}function St(e){return e instanceof Set}function N(e){return e.copy_||e.base_}function yn(e,n){if(vt(e))return new Map(e);if(St(e))return new Set(e);if(Array.isArray(e))return Array.prototype.slice.call(e);if(!n&&no(e))return De(e)?{...e}:Object.assign(Object.create(null),e);let t=Object.getOwnPropertyDescriptors(e);delete t[P];let r=Reflect.ownKeys(t);for(let o=0;o1&&(e.set=e.add=e.clear=e.delete=Es),Object.freeze(e),n&&Oe(e,(t,r)=>Le(r,!0),!0)),e}function Es(){ie(2)}function wt(e){return Object.isFrozen(e)}var vn={};function xe(e){let n=vn[e];return n||ie(0,e),n}function Rs(e,n){vn[e]||(vn[e]=n)}var Ye;function ht(){return Ye}function bs(e,n){return{drafts_:[],parent_:e,immer_:n,canAutoFreeze_:!0,unfinalizedDrafts_:0}}function Jr(e,n){n&&(xe("Patches"),e.patches_=[],e.inversePatches_=[],e.patchListener_=n)}function Sn(e){wn(e),e.drafts_.forEach(xs),e.drafts_=null}function wn(e){e===Ye&&(Ye=e.parent_)}function Qr(e){return Ye=bs(Ye,e)}function xs(e){let n=e[P];n.type_===0||n.type_===1?n.revoke_():n.revoked_=!0}function Zr(e,n){n.unfinalizedDrafts_=n.drafts_.length;let t=n.drafts_[0];return e!==void 0&&e!==t?(t[P].modified_&&(Sn(n),ie(4)),ye(e)&&(e=mt(n,e),n.parent_||_t(n,e)),n.patches_&&xe("Patches").generateReplacementPatches_(t[P].base_,e,n.patches_,n.inversePatches_)):e=mt(n,t,[]),Sn(n),n.patches_&&n.patchListener_(n.patches_,n.inversePatches_),e!==to?e:void 0}function mt(e,n,t){if(wt(n))return n;let r=n[P];if(!r)return Oe(n,(o,i)=>eo(e,r,n,o,i,t),!0),n;if(r.scope_!==e)return n;if(!r.modified_)return _t(e,r.base_,!0),r.base_;if(!r.finalized_){r.finalized_=!0,r.scope_.unfinalizedDrafts_--;let o=r.copy_,i=o,s=!1;r.type_===3&&(i=new Set(o),o.clear(),s=!0),Oe(i,(a,l)=>eo(e,r,o,a,l,t,s)),_t(e,o,!1),t&&e.patches_&&xe("Patches").generatePatches_(r,t,e.patches_,e.inversePatches_)}return r.copy_}function eo(e,n,t,r,o,i,s){if($e(o)){let a=i&&n&&n.type_!==3&&!_n(n.assigned_,r)?i.concat(r):void 0,l=mt(e,o,a);if(ro(t,r,l),$e(l))e.canAutoFreeze_=!1;else return}else s&&t.add(o);if(ye(o)&&!wt(o)){if(!e.immer_.autoFreeze_&&e.unfinalizedDrafts_<1)return;mt(e,o),(!n||!n.scope_.parent_)&&_t(e,o)}}function _t(e,n,t=!1){!e.parent_&&e.immer_.autoFreeze_&&e.canAutoFreeze_&&Le(n,t)}function Ms(e,n){let t=Array.isArray(e),r={type_:t?1:0,scope_:n?n.scope_:ht(),modified_:!1,finalized_:!1,assigned_:{},parent_:n,base_:e,draft_:null,copy_:null,revoke_:null,isManual_:!1},o=r,i=Cn;t&&(o=[r],i=Je);let{revoke:s,proxy:a}=Proxy.revocable(o,i);return r.draft_=a,r.revoke_=s,a}var Cn={get(e,n){if(n===P)return e;let t=N(e);if(!_n(t,n))return Fs(e,t,n);let r=t[n];return e.finalized_||!ye(r)?r:r===hn(e.base_,n)?(mn(e),e.copy_[n]=Qe(r,e)):r},has(e,n){return n in N(e)},ownKeys(e){return Reflect.ownKeys(N(e))},set(e,n,t){let r=oo(N(e),n);if(r?.set)return r.set.call(e.draft_,t),!0;if(!e.modified_){let o=hn(N(e),n),i=o?.[P];if(i&&i.base_===t)return e.copy_[n]=t,e.assigned_[n]=!1,!0;if(Cs(t,o)&&(t!==void 0||_n(e.base_,n)))return!0;mn(e),_e(e)}return e.copy_[n]===t&&(t!==void 0||n in e.copy_)||Number.isNaN(t)&&Number.isNaN(e.copy_[n])||(e.copy_[n]=t,e.assigned_[n]=!0),!0},deleteProperty(e,n){return hn(e.base_,n)!==void 0||n in e.base_?(e.assigned_[n]=!1,mn(e),_e(e)):delete e.assigned_[n],e.copy_&&delete e.copy_[n],!0},getOwnPropertyDescriptor(e,n){let t=N(e),r=Reflect.getOwnPropertyDescriptor(t,n);return r&&{writable:!0,configurable:e.type_!==1||n!=="length",enumerable:r.enumerable,value:t[n]}},defineProperty(){ie(11)},getPrototypeOf(e){return De(e.base_)},setPrototypeOf(){ie(12)}},Je={};Oe(Cn,(e,n)=>{Je[e]=function(){return arguments[0]=arguments[0][0],n.apply(this,arguments)}});Je.deleteProperty=function(e,n){return Je.set.call(this,e,n,void 0)};Je.set=function(e,n,t){return Cn.set.call(this,e[0],n,t,e[0])};function hn(e,n){let t=e[P];return(t?N(t):e)[n]}function Fs(e,n,t){let r=oo(n,t);return r?"value"in r?r.value:r.get?.call(e.draft_):void 0}function oo(e,n){if(!(n in e))return;let t=De(e);for(;t;){let r=Object.getOwnPropertyDescriptor(t,n);if(r)return r;t=De(t)}}function _e(e){e.modified_||(e.modified_=!0,e.parent_&&_e(e.parent_))}function mn(e){e.copy_||(e.copy_=yn(e.base_,e.scope_.immer_.useStrictShallowCopy_))}var Is=class{constructor(e){this.autoFreeze_=!0,this.useStrictShallowCopy_=!1,this.produce=(n,t,r)=>{if(typeof n=="function"&&typeof t!="function"){let i=t;t=n;let s=this;return function(l=i,...u){return s.produce(l,f=>t.call(this,f,...u))}}typeof t!="function"&&ie(6),r!==void 0&&typeof r!="function"&&ie(7);let o;if(ye(n)){let i=Qr(this),s=Qe(n,void 0),a=!0;try{o=t(s),a=!1}finally{a?Sn(i):wn(i)}return Jr(i,r),Zr(o,i)}else if(!n||typeof n!="object"){if(o=t(n),o===void 0&&(o=n),o===to&&(o=void 0),this.autoFreeze_&&Le(o,!0),r){let i=[],s=[];xe("Patches").generateReplacementPatches_(n,o,i,s),r(i,s)}return o}else ie(1,n)},this.produceWithPatches=(n,t)=>{if(typeof n=="function")return(s,...a)=>this.produceWithPatches(s,l=>n(l,...a));let r,o;return[this.produce(n,t,(s,a)=>{r=s,o=a}),r,o]},typeof e?.autoFreeze=="boolean"&&this.setAutoFreeze(e.autoFreeze),typeof e?.useStrictShallowCopy=="boolean"&&this.setUseStrictShallowCopy(e.useStrictShallowCopy)}createDraft(e){ye(e)||ie(8),$e(e)&&(e=Ts(e));let n=Qr(this),t=Qe(e,void 0);return t[P].isManual_=!0,wn(n),t}finishDraft(e,n){let t=e&&e[P];(!t||!t.isManual_)&&ie(9);let{scope_:r}=t;return Jr(r,n),Zr(void 0,r)}setAutoFreeze(e){this.autoFreeze_=e}setUseStrictShallowCopy(e){this.useStrictShallowCopy_=e}applyPatches(e,n){let t;for(t=n.length-1;t>=0;t--){let o=n[t];if(o.path.length===0&&o.op==="replace"){e=o.value;break}}t>-1&&(n=n.slice(t+1));let r=xe("Patches").applyPatches_;return $e(e)?r(e,n):this.produce(e,o=>r(o,n))}};function Qe(e,n){let t=vt(e)?xe("MapSet").proxyMap_(e,n):St(e)?xe("MapSet").proxySet_(e,n):Ms(e,n);return(n?n.scope_:ht()).drafts_.push(t),t}function Ts(e){return $e(e)||ie(10,e),io(e)}function io(e){if(!ye(e)||wt(e))return e;let n=e[P],t;if(n){if(!n.modified_)return n.base_;n.finalized_=!0,t=yn(e,n.scope_.immer_.useStrictShallowCopy_)}else t=yn(e,!0);return Oe(t,(r,o)=>{ro(t,r,io(o))}),n&&(n.finalized_=!1),t}function Ct(){class e extends Map{constructor(l,u){super(),this[P]={type_:2,parent_:u,scope_:u?u.scope_:ht(),modified_:!1,finalized_:!1,copy_:void 0,assigned_:void 0,base_:l,draft_:this,isManual_:!1,revoked_:!1}}get size(){return N(this[P]).size}has(l){return N(this[P]).has(l)}set(l,u){let f=this[P];return s(f),(!N(f).has(l)||N(f).get(l)!==u)&&(t(f),_e(f),f.assigned_.set(l,!0),f.copy_.set(l,u),f.assigned_.set(l,!0)),this}delete(l){if(!this.has(l))return!1;let u=this[P];return s(u),t(u),_e(u),u.base_.has(l)?u.assigned_.set(l,!1):u.assigned_.delete(l),u.copy_.delete(l),!0}clear(){let l=this[P];s(l),N(l).size&&(t(l),_e(l),l.assigned_=new Map,Oe(l.base_,u=>{l.assigned_.set(u,!1)}),l.copy_.clear())}forEach(l,u){let f=this[P];N(f).forEach((c,g,d)=>{l.call(u,this.get(g),g,this)})}get(l){let u=this[P];s(u);let f=N(u).get(l);if(u.finalized_||!ye(f)||f!==u.base_.get(l))return f;let c=Qe(f,u);return t(u),u.copy_.set(l,c),c}keys(){return N(this[P]).keys()}values(){let l=this.keys();return{[Symbol.iterator]:()=>this.values(),next:()=>{let u=l.next();return u.done?u:{done:!1,value:this.get(u.value)}}}}entries(){let l=this.keys();return{[Symbol.iterator]:()=>this.entries(),next:()=>{let u=l.next();if(u.done)return u;let f=this.get(u.value);return{done:!1,value:[u.value,f]}}}}[Symbol.iterator](){return this.entries()}}function n(a,l){return new e(a,l)}function t(a){a.copy_||(a.assigned_=new Map,a.copy_=new Map(a.base_))}class r extends Set{constructor(l,u){super(),this[P]={type_:3,parent_:u,scope_:u?u.scope_:ht(),modified_:!1,finalized_:!1,copy_:void 0,base_:l,draft_:this,drafts_:new Map,revoked_:!1,isManual_:!1}}get size(){return N(this[P]).size}has(l){let u=this[P];return s(u),u.copy_?!!(u.copy_.has(l)||u.drafts_.has(l)&&u.copy_.has(u.drafts_.get(l))):u.base_.has(l)}add(l){let u=this[P];return s(u),this.has(l)||(i(u),_e(u),u.copy_.add(l)),this}delete(l){if(!this.has(l))return!1;let u=this[P];return s(u),i(u),_e(u),u.copy_.delete(l)||(u.drafts_.has(l)?u.copy_.delete(u.drafts_.get(l)):!1)}clear(){let l=this[P];s(l),N(l).size&&(i(l),_e(l),l.copy_.clear())}values(){let l=this[P];return s(l),i(l),l.copy_.values()}entries(){let l=this[P];return s(l),i(l),l.copy_.entries()}keys(){return this.values()}[Symbol.iterator](){return this.values()}forEach(l,u){let f=this.values(),c=f.next();for(;!c.done;)l.call(u,c.value,c.value,this),c=f.next()}}function o(a,l){return new r(a,l)}function i(a){a.copy_||(a.copy_=new Set,a.base_.forEach(l=>{if(ye(l)){let u=Qe(l,a);a.drafts_.set(l,u),a.copy_.add(u)}else a.copy_.add(l)}))}function s(a){a.revoked_&&ie(3,JSON.stringify(N(a)))}Rs("MapSet",{proxyMap_:n,proxySet_:o})}var Z=new Is,so=Z.produce,wl=Z.produceWithPatches.bind(Z),Cl=Z.setAutoFreeze.bind(Z),El=Z.setUseStrictShallowCopy.bind(Z),Rl=Z.applyPatches.bind(Z),bl=Z.createDraft.bind(Z),xl=Z.finishDraft.bind(Z);function ke(e){var n=H(function(){return Le(typeof e=="function"?e():e,!0)}),t=n[1];return[n[0],Y(function(r){t(typeof r=="function"?so(r):Le(r))},[])]}function Ps(e,n,t,r,o){window.Shiny.shinyapp.makeRequest(e,n,t,r,o)}function lo({method:e,args:n,blobs:t}){return new Promise((r,o)=>{Ps(e,n,i=>{r(i)},i=>{o(i)},t)})}function ao({patchInfo:e,patches:n,onSuccess:t,onError:r,columns:o,setData:i,setCellEditMapAtLoc:s}){let a=n.map(l=>({row_index:l.rowIndex,column_index:l.columnIndex,value:l.value}));lo({method:e.key,args:[a]}).then(l=>{if(!Array.isArray(l))throw new Error("Expected a response of a list of patches");for(let f of l)if(!("row_index"in f&&"column_index"in f&&"value"in f))throw new Error("Expected list of patches containing `row_index`, `column_index`, and `value`");l=l;let u=l.map(f=>({rowIndex:f.row_index,columnIndex:f.column_index,value:f.value}));i(f=>{u.forEach(({rowIndex:c,columnIndex:g,value:d})=>{f[c][g]=d})}),n.forEach(({rowIndex:f,columnIndex:c,value:g})=>{s(f,c,d=>{d.state===ce.EditSaving&&(d.state=ce.Ready,d.value=g,d.errorTitle=void 0)})}),u.forEach(({rowIndex:f,columnIndex:c,value:g})=>{s(f,c,d=>{d.value=g,d.state=ce.EditSuccess,d.errorTitle=void 0})}),t(u)}).catch(l=>{n.forEach(({rowIndex:u,columnIndex:f,value:c})=>{s(u,f,g=>{g.value=String(c),g.state=ce.EditFailure,g.errorTitle=String(l)})}),r(l)})}var ce={EditSaving:"EditSaving",EditSuccess:"EditSuccess",EditFailure:"EditFailure",Editing:"Editing",Ready:"Ready"},bn={EditSaving:"cell-edit-saving",EditSuccess:"cell-edit-success",EditFailure:"cell-edit-failure",Editing:"cell-edit-editing",Ready:void 0},Rn=e=>e!==null&&typeof e=="object"&&Object.prototype.hasOwnProperty.call(e,"isShinyHtml")&&e.isShinyHtml===!0,En=e=>Rn(e)?e.obj.html:e===null?"":e,uo=({containerRef:e,rowId:n,cell:t,patchInfo:r,columns:o,coldefs:i,rowIndex:s,columnIndex:a,editCellsIsAllowed:l,getSortedRowModel:u,cellEditInfo:f,cellStyle:c,cellClassName:g,setData:d,setCellEditMapAtLoc:p,selection:h})=>{let _=t.getValue(),m=t.column.columnDef.meta.isHtmlColumn,y=f?.value??_,R=f?.state??ce.Ready,V=f?.errorTitle,T=f?.isEditing??!1,D=f?.editValue??En(y),z=X(null),U=X(null),G=Y(({resetIsEditing:x=!1,resetEditValue:I=!1}={resetIsEditing:!0,resetEditValue:!0})=>{p(s,a,A=>{x&&(A.isEditing=!1),I&&(A.editValue=void 0)})},[s,a,p]),q=x=>{x.key==="Escape"&&(x.preventDefault(),x.stopPropagation(),G(),h.focusOffset(n,0))},te=x=>{if(x.key!=="Tab")return;x.preventDefault(),x.stopPropagation();let I=x.shiftKey,A=a;for(;;){let K=A+(I?-1:1);if(K<0||K>=i.length)return;if(A=K,i[K].meta.isHtmlColumn!==!0)break}He(),p(s,A,K=>{K.isEditing=!0})},Ce=x=>{if(x.key!=="Enter")return;x.preventDefault(),x.stopPropagation();let I=x.shiftKey,A=u(),K=A.rows.findIndex(Fe=>Fe.id===n);if(K<0)return;let le=K+(I?-1:1);if(le<0||le>=A.rows.length)return;He();let tt=A.rows[le].index;p(tt,a,Fe=>{Fe.isEditing=!0})},Rt=x=>{[q,Ce,te].forEach(I=>I(x))},He=Y(()=>{if(p(s,a,x=>{x.errorTitle=void 0}),`${En(y)}`==`${D}`){G(),p(s,a,x=>{x.state=R});return}G({resetIsEditing:!0}),p(s,a,x=>{x.state=ce.EditSaving}),ao({patchInfo:r,patches:[{rowIndex:s,columnIndex:a,value:D}],onSuccess:x=>{G({resetEditValue:!0})},onError:x=>{},columns:o,setData:d,setCellEditMapAtLoc:p})},[p,s,a,y,D,G,r,o,d,R]);L(()=>{T&&U.current&&(U.current.focus(),U.current.select())},[T]),L(()=>{if(!T||!z.current||!U.current)return;let x=K=>{z.current?.contains(K.target)&&K.stopPropagation()},I=z.current;I.addEventListener("mousedown",x);let A=K=>{K.target!==U.current&&(He(),G())};return document.body.addEventListener("mousedown",A),()=>{I.removeEventListener("mousedown",x),document.body.removeEventListener("mousedown",A)}},[R,He,s,a,T,G]);function Me(x){T&&x.target.select()}function Ae(x){p(s,a,I=>{I.editValue=x.target.value})}let Ze,Ne,et=V,ge=g,ze=x=>{x&&(ge?(ge+=" ",ge+=x):ge=x)};ze(bn[T?ce.Editing:R]);let Ge=!1,Be=null;return R===ce.EditSaving?Ne=D:(T?Be=b.createElement("textarea",{value:String(D),onChange:Ae,onFocus:Me,onKeyDown:Rt,ref:U}):m?ze("cell-html"):l&&(ze("cell-editable"),Ze=x=>{p(s,a,I=>{I.isEditing=!0,I.editValue=En(y)})}),Rn(y)?Ge=!0:Ne=ft(t.column.columnDef.cell,t.getContext())),L(()=>{if(!z.current||!Ge||!Rn(y))return;let x=JSON.parse(JSON.stringify(y.obj));window.Shiny.renderContentAsync(z.current,x);let I=z.current;return()=>{window.Shiny.unbindAll(I),I.replaceChildren("")}},[z,y,s,a,Ge]),b.createElement("td",{ref:z,onDoubleClick:Ze,title:et,className:ge,style:{...c}},Be,Ne)};var co=()=>{let[e,n]=ke(new Map);return Ct(),{cellEditMap:e,setCellEditMapAtLoc:(r,o,i)=>{n(s=>{let a=fo(r,o),l=s.get(a)??{};i(l),s.set(a,l)})}}},fo=(e,n)=>`[${e}, ${n}]`;var go=(e,n,t)=>{let r=fo(n,t);return[e.get(r)??{},r]};function Et(e,n,t){let r=Object.assign({top:0,right:0,bottom:0,left:0},t),o=e,i=o.scrollTop+r.top,s=o.scrollLeft+r.left,a=i+o.clientHeight-r.top-r.bottom,l=s+o.clientWidth-r.left-r.right;for(let u=0;u=i&&c<=a&&g>=s&&g<=l)return f}return null}function xn(e,n){return document?.defaultView?.getComputedStyle(e,null)?.getPropertyValue(n)}var mo=e=>{let[n,t]=H(!1),{range:r,from:o,to:i,onRangeChange:s}=e;return b.createElement(Vs,{range:r,value:[o,i],editing:n,onValueChange:a=>s(...a),onFocus:()=>t(!0),onBlur:()=>t(!1)})};var Vs=e=>{let[n,t]=e.value,{editing:r,onFocus:o}=e,[i,s]=e.range(),a=X(null),l=X(null);return b.createElement("div",{onBlur:u=>{if(!u.currentTarget.contains(u.relatedTarget))return e.onBlur()},onFocus:()=>o(),style:{display:"flex",gap:"0.5rem"}},b.createElement("input",{ref:a,className:`form-control form-control-sm ${a.current?.checkValidity()?"":"is-invalid"}`,style:{flex:"1 1 0",width:"0"},type:"number",placeholder:po(r,"Min",i),defaultValue:n,step:"any",onChange:u=>{let f=ho(u.target.value);a.current&&(a.current.classList.toggle("is-invalid",!u.target.checkValidity()),e.onValueChange([f,t]))}}),b.createElement("input",{ref:l,className:`form-control form-control-sm ${l.current?.checkValidity()?"":"is-invalid"}`,style:{flex:"1 1 0",width:"0"},type:"number",placeholder:po(r,"Max",s),defaultValue:t,step:"any",onChange:u=>{let f=ho(u.target.value);l.current&&(l.current.classList.toggle("is-invalid",!u.target.checkValidity()),e.onValueChange([n,f]))}}))};function po(e,n,t){if(e)return typeof t>"u"?n:`${n} (${t})`}function ho(e){if(e!=="")return+e}function _o(e){let[n,t]=H([]),r=e?{getFilteredRowModel:Hr(),getFacetedRowModel:Lr(),getFacetedUniqueValues:kr(),getFacetedMinMaxValues:$r(),filterFns:{substring:(o,i,s,a)=>o.getValue(i)?.toString().includes(s)??!1},onColumnFiltersChange:t}:{};return{columnFilters:n,columnFiltersState:{columnFilters:n},filtersTableOptions:r,setColumnFilters:t}}var yo=({header:e,className:n,...t})=>{let r=e.column.columnDef.meta?.typeHint;if(!r||r.type==="html")return null;if(r.type==="numeric"){let[o,i]=e.column.getFilterValue()??[void 0,void 0];return mo({from:o,to:i,range:()=>e.column.getFacetedMinMaxValues()??[void 0,void 0],onRangeChange:(a,l)=>e.column.setFilterValue([a,l])})}return b.createElement("input",{...t,value:e.column.getFilterValue()||"",className:`form-control form-control-sm ${n}`,type:"text",onChange:o=>e.column.setFilterValue(o.target.value)})};var ee=class e{static{this._empty=new e(new Set)}constructor(n){this._set=n}static empty(){return this._empty}static just(...n){return this.empty().add(...n)}has(n){return this._set.has(n)}add(...n){let t=new Set(this._set.keys());for(let r of n)t.add(r);return new e(t)}toggle(n){return this.has(n)?this.delete(n):this.add(n)}delete(n){let t=new Set(this._set.keys());return t.delete(n),new e(t)}clear(){return e.empty()}[Symbol.iterator](){return this._set[Symbol.iterator]()}toList(){return[...this._set.keys()]}};var se=class e{static{this._NONE="none"}static{this._ROW_SINGLE="single"}static{this._ROW_MULTIPLE="multiple"}static{this._COL_SINGLE="single"}static{this._col_multiple="multiple"}static{this._RECT_CELL="cell"}static{this._RECT_REGION="region"}static{this._rowEnum={NONE:e._NONE,SINGLE:e._ROW_SINGLE,MULTIPLE:e._ROW_MULTIPLE}}static{this._colEnum={NONE:e._NONE,SINGLE:e._COL_SINGLE,MULTIPLE:e._col_multiple}}static{this._rectEnum={NONE:e._NONE,REGION:e._RECT_REGION,CELL:e._RECT_CELL}}constructor({row:n,col:t,rect:r}){if(!Object.values(e._rowEnum).includes(n))throw new Error(`Invalid row selection mode: ${n}`);if(!Object.values(e._colEnum).includes(t))throw new Error(`Invalid col selection mode: ${t}`);if(!Object.values(e._rectEnum).includes(r))throw new Error(`Invalid rect selection mode: ${r}`);this.row=n,this.col=t,this.rect=r}isNone(){return this.row===e._rowEnum.NONE&&this.col===e._colEnum.NONE&&this.rect===e._rectEnum.NONE}};function So(e){return e||(e={row:"multiple",col:"none",rect:"none"}),new se({row:e.row,col:e.col,rect:e.rect})}function wo({isEditingCell:e,editCellsIsAllowed:n,selectionModes:t,keyAccessor:r,focusOffset:o,focusEscape:i,onKeyDownEnter:s,between:a}){let[l,u]=H(ee.empty()),[f,c]=H(null),g=h=>{if(t.isNone())return;let _=h.currentTarget,m=r(_);if(e&&_.classList.contains(bn[ce.Editing]))return;let y=Ds(t,a,l,h,m,f);y&&(u(y.selection),y.anchor&&(c(m),_.focus()),h.preventDefault())},d=h=>{if(e||t.isNone())return;let _=h.currentTarget,m=r(_),y=l.has(m);if(h.key==="Escape"){i(_),h.preventDefault();return}if(t.row===se._rowEnum.SINGLE){if(h.key===" "||h.key==="Enter")h.preventDefault(),n&&h.key==="Enter"?s(_):l.has(m)?u(ee.empty()):u(ee.just(m));else if(h.key==="ArrowUp"||h.key==="ArrowDown"){let R=o(m,h.key==="ArrowUp"?-1:1);R&&(h.preventDefault(),y&&u(ee.just(R)))}}else t.row===se._rowEnum.MULTIPLE&&(h.key===" "||h.key==="Enter"?(h.preventDefault(),n&&h.key==="Enter"?s(_):u(l.toggle(m))):(h.key==="ArrowUp"||h.key==="ArrowDown")&&o(m,h.key==="ArrowUp"?-1:1)&&h.preventDefault())};return{has(h){return l.has(h)},set(h,_){u(_?l.add(h):l.delete(h))},setMultiple(h){u(ee.just(...h))},clear(){u(l.clear())},keys(){return l},itemHandlers(){return{onMouseDown:g,onKeyDown:d}},focusOffset:o}}var vo=/^mac/i.test(window.navigator.userAgentData?.platform??window.navigator.platform);function Ds(e,n,t,r,o,i){let{shiftKey:s,altKey:a}=r,l=vo?r.metaKey:r.ctrlKey;if((vo?r.ctrlKey:r.metaKey)||a||e.row===se._rowEnum.NONE)return null;if(e.row===se._rowEnum.SINGLE)return l&&!s?t.has(o)?{selection:ee.empty(),anchor:!0}:{selection:ee.just(o),anchor:!0}:{selection:ee.just(o),anchor:!0};if(e.row===se._rowEnum.MULTIPLE)if(s&&l){if(i!==null&&n){let f=n(i,o);return{selection:t.add(...f)}}}else{if(l)return{selection:t.toggle(o),anchor:!0};if(s){if(i!==null&&n){let f=n(i,o);return{selection:ee.just(...f)}}}else return{selection:ee.just(o),anchor:!0}}else throw new Error(`Unsupported row selection mode: ${e.row}`);return null}function Co({getColDefs:e}){let[n,t]=H([]);return{sorting:n,sortTableStateOptions:{sorting:n},sortTableOptions:{onSortingChange:r=>{let o=typeof r=="function"?r(n):r,i=e(),s=new Set(i.filter(l=>l.meta.isHtmlColumn).map(l=>l.header)),a=s.size==0?o:o.filter(l=>!s.has(l.id));t(a)},getSortedRowModel:Ar()},setSorting:t}}var Eo="sort-arrow",Ro={viewBox:[-1,-1,2,2].map(e=>e*1.4).join(" "),width:"100%",height:"100%",style:{paddingLeft:"3px"}},bo={stroke:"#333333",strokeWidth:"0.6",fill:"transparent"},$s=b.createElement("svg",{xmlns:"http://www.w3.org/2000/svg",...Ro,className:`${Eo} sort-arrow-up`},b.createElement("path",{d:"M -1 0.5 L 0 -0.5 L 1 0.5",...bo,strokeLinecap:"round"})),Os=b.createElement("svg",{xmlns:"http://www.w3.org/2000/svg",...Ro,className:`${Eo} sort-arrow-down`},b.createElement("path",{d:"M -1 -0.5 L 0 0.5 L 1 -0.5",...bo,strokeLinecap:"round"})),xo=({direction:e})=>{if(!e)return null;if(e==="asc")return $s;if(e==="desc")return Os;throw new Error(`Unexpected sort direction: '${e}'`)};Ct();var Mo=({location:e,rowIndex:n,columnIndex:t})=>`[${e}, ${n}, ${t}]`,Fo=({initStyleInfos:e,nrow:n,ncol:t})=>{let[r,o]=ke(new Map),i=Y(l=>{let{location:u,rows:f,cols:c}=l;o(g=>{let d=f??Array.from({length:n},(h,_)=>_),p=c??Array.from({length:t},(h,_)=>_);for(let h of d)for(let _ of p){let m=Mo({location:u,rowIndex:h,columnIndex:_}),y=g.get(m)??{style:{},class:void 0},R;y.class?l.class?R=`${y.class} ${l.class}`:R=y.class:l.class?R=l.class:R=void 0,g.set(m,{location:u,rowIndex:h,columnIndex:_,style:{...y.style,...l.style},class:R})}})},[t,n,o]),s=Y(()=>{o(l=>{l.clear()})},[o]),a=Y(l=>{s();for(let u of l)i(u)},[i,s]);return L(()=>{a(e)},[e,a]),{styleInfoMap:r,setStyleInfo:i,setStyleInfos:a,resetStyleInfos:s}};var Io=(e,n,t,r)=>{let o=Mo({location:n,rowIndex:t,columnIndex:r}),i=e.get(o);return{cellStyle:i?.style,cellClassName:i?.class}},Da=document.createElement("cssStringToObj");var To=` + color: hsl(${Math.max(0,Math.min(120-120*m,120))}deg 100% 31%);`,t?.key)}return(l=t?.onChange)==null||l.call(t,o),o}}function pt(e,n){if(e===void 0)throw new Error(`Unexpected undefined${n?`: ${n}`:""}`);return e}var Gr=(e,n)=>Math.abs(e-n)<1,Br=(e,n,t)=>{let r;return function(...o){e.clearTimeout(r),r=e.setTimeout(()=>n.apply(this,o),t)}};var ps=e=>e,ms=e=>{let n=Math.max(e.startIndex-e.overscan,0),t=Math.min(e.endIndex+e.overscan,e.count-1),r=[];for(let o=n;o<=t;o++)r.push(o);return r},Kr=(e,n)=>{let t=e.scrollElement;if(!t)return;let r=e.targetWindow;if(!r)return;let o=s=>{let{width:a,height:l}=s;n({width:Math.round(a),height:Math.round(l)})};if(o(t.getBoundingClientRect()),!r.ResizeObserver)return()=>{};let i=new r.ResizeObserver(s=>{let a=s[0];if(a?.borderBoxSize){let l=a.borderBoxSize[0];if(l){o({width:l.inlineSize,height:l.blockSize});return}}o(t.getBoundingClientRect())});return i.observe(t,{box:"border-box"}),()=>{i.unobserve(t)}},Ur={passive:!0};var hs=typeof window>"u"?!0:"onscrollend"in window,jr=(e,n)=>{let t=e.scrollElement;if(!t)return;let r=e.targetWindow;if(!r)return;let o=0,i=hs?()=>{}:Br(r,()=>{n(o,!1)},e.options.isScrollingResetDelay),s=u=>()=>{o=t[e.options.horizontal?"scrollLeft":"scrollTop"],i(),n(o,u)},a=s(!0),l=s(!1);return l(),t.addEventListener("scroll",a,Ur),t.addEventListener("scrollend",l,Ur),()=>{t.removeEventListener("scroll",a),t.removeEventListener("scrollend",l)}};var _s=(e,n,t)=>{if(n?.borderBoxSize){let r=n.borderBoxSize[0];if(r)return Math.round(r[t.options.horizontal?"inlineSize":"blockSize"])}return Math.round(e.getBoundingClientRect()[t.options.horizontal?"width":"height"])};var qr=(e,{adjustments:n=0,behavior:t},r)=>{var o,i;let s=e+n;(i=(o=r.scrollElement)==null?void 0:o.scrollTo)==null||i.call(o,{[r.options.horizontal?"left":"top"]:s,behavior:t})},mt=class{constructor(n){this.unsubs=[],this.scrollElement=null,this.targetWindow=null,this.isScrolling=!1,this.scrollToIndexTimeoutId=null,this.measurementsCache=[],this.itemSizeCache=new Map,this.pendingMeasuredCacheIndexes=[],this.scrollRect=null,this.scrollOffset=null,this.scrollDirection=null,this.scrollAdjustments=0,this.elementsCache=new Map,this.observer=(()=>{let t=null,r=()=>t||(!this.targetWindow||!this.targetWindow.ResizeObserver?null:t=new this.targetWindow.ResizeObserver(o=>{o.forEach(i=>{this._measureElement(i.target,i)})}));return{disconnect:()=>{var o;return(o=r())==null?void 0:o.disconnect()},observe:o=>{var i;return(i=r())==null?void 0:i.observe(o,{box:"border-box"})},unobserve:o=>{var i;return(i=r())==null?void 0:i.unobserve(o)}}})(),this.range=null,this.setOptions=t=>{Object.entries(t).forEach(([r,o])=>{typeof o>"u"&&delete t[r]}),this.options={debug:!1,initialOffset:0,overscan:1,paddingStart:0,paddingEnd:0,scrollPaddingStart:0,scrollPaddingEnd:0,horizontal:!1,getItemKey:ps,rangeExtractor:ms,onChange:()=>{},measureElement:_s,initialRect:{width:0,height:0},scrollMargin:0,gap:0,indexAttribute:"data-index",initialMeasurementsCache:[],lanes:1,isScrollingResetDelay:150,enabled:!0,...t}},this.notify=(t,r)=>{var o,i;let{startIndex:s,endIndex:a}=this.range??{startIndex:void 0,endIndex:void 0},l=this.calculateRange();(t||s!==l?.startIndex||a!==l?.endIndex)&&((i=(o=this.options).onChange)==null||i.call(o,this,r))},this.cleanup=()=>{this.unsubs.filter(Boolean).forEach(t=>t()),this.unsubs=[],this.scrollElement=null,this.targetWindow=null,this.observer.disconnect(),this.elementsCache.clear()},this._didMount=()=>()=>{this.cleanup()},this._willUpdate=()=>{var t;let r=this.options.enabled?this.options.getScrollElement():null;if(this.scrollElement!==r){if(this.cleanup(),!r){this.notify(!1,!1);return}this.scrollElement=r,this.scrollElement&&"ownerDocument"in this.scrollElement?this.targetWindow=this.scrollElement.ownerDocument.defaultView:this.targetWindow=((t=this.scrollElement)==null?void 0:t.window)??null,this._scrollToOffset(this.getScrollOffset(),{adjustments:void 0,behavior:void 0}),this.unsubs.push(this.options.observeElementRect(this,o=>{this.scrollRect=o,this.notify(!1,!1)})),this.unsubs.push(this.options.observeElementOffset(this,(o,i)=>{this.scrollAdjustments=0,this.scrollDirection=i?this.getScrollOffset()this.options.enabled?(this.scrollRect=this.scrollRect??this.options.initialRect,this.scrollRect[this.options.horizontal?"width":"height"]):(this.scrollRect=null,0),this.getScrollOffset=()=>this.options.enabled?(this.scrollOffset=this.scrollOffset??(typeof this.options.initialOffset=="function"?this.options.initialOffset():this.options.initialOffset),this.scrollOffset):(this.scrollOffset=null,0),this.getFurthestMeasurement=(t,r)=>{let o=new Map,i=new Map;for(let s=r-1;s>=0;s--){let a=t[s];if(o.has(a.lane))continue;let l=i.get(a.lane);if(l==null||a.end>l.end?i.set(a.lane,a):a.ends.end===a.end?s.index-a.index:s.end-a.end)[0]:void 0},this.getMeasurementOptions=De(()=>[this.options.count,this.options.paddingStart,this.options.scrollMargin,this.options.getItemKey,this.options.enabled],(t,r,o,i,s)=>(this.pendingMeasuredCacheIndexes=[],{count:t,paddingStart:r,scrollMargin:o,getItemKey:i,enabled:s}),{key:!1}),this.getMeasurements=De(()=>[this.getMeasurementOptions(),this.itemSizeCache],({count:t,paddingStart:r,scrollMargin:o,getItemKey:i,enabled:s},a)=>{var l;if(!s)return this.measurementsCache=[],this.itemSizeCache.clear(),[];this.measurementsCache.length===0&&(this.measurementsCache=this.options.initialMeasurementsCache,this.measurementsCache.forEach(c=>{this.itemSizeCache.set(c.key,c.size)}));let u=this.pendingMeasuredCacheIndexes.length>0?Math.min(...this.pendingMeasuredCacheIndexes):0;this.pendingMeasuredCacheIndexes=[];let f=this.measurementsCache.slice(0,u);for(let c=u;c{let T=i(c),D=this.elementsCache.get(T);if(!V){D&&(this.observer.unobserve(D),this.elementsCache.delete(T));return}D!==V&&(D&&this.observer.unobserve(D),this.observer.observe(V),this.elementsCache.set(T,V)),V.isConnected&&this.resizeItem(c,this.options.measureElement(V,void 0,this))});let d=i(c),p=this.options.lanes===1?f[c-1]:this.getFurthestMeasurement(f,c),m=p?p.end+this.options.gap:r+o,_=a.get(d),h=typeof _=="number"?_:this.options.estimateSize(c),y=m+h,R=p?p.lane:c%this.options.lanes;f[c]={index:c,start:m,size:h,end:y,key:d,lane:R,measureElement:g}}return this.measurementsCache=f,f},{key:!1,debug:()=>this.options.debug}),this.calculateRange=De(()=>[this.getMeasurements(),this.getSize(),this.getScrollOffset()],(t,r,o)=>this.range=t.length>0&&r>0?ys({measurements:t,outerSize:r,scrollOffset:o}):null,{key:!1,debug:()=>this.options.debug}),this.getIndexes=De(()=>[this.options.rangeExtractor,this.calculateRange(),this.options.overscan,this.options.count],(t,r,o,i)=>r===null?[]:t({startIndex:r.startIndex,endIndex:r.endIndex,overscan:o,count:i}),{key:!1,debug:()=>this.options.debug}),this.indexFromElement=t=>{let r=this.options.indexAttribute,o=t.getAttribute(r);return o?parseInt(o,10):(console.warn(`Missing attribute name '${r}={index}' on measured element.`),-1)},this._measureElement=(t,r)=>{let o=this.indexFromElement(t),i=this.getMeasurements()[o];if(!i||!t.isConnected){this.elementsCache.forEach((a,l)=>{a===t&&(this.observer.unobserve(t),this.elementsCache.delete(l))});return}let s=this.elementsCache.get(i.key);s!==t&&(s&&this.observer.unobserve(s),this.observer.observe(t),this.elementsCache.set(i.key,t)),this.resizeItem(o,this.options.measureElement(t,r,this))},this.resizeItem=(t,r)=>{let o=this.getMeasurements()[t];if(!o)return;let i=this.itemSizeCache.get(o.key)??o.size,s=r-i;s!==0&&((this.shouldAdjustScrollPositionOnItemSizeChange!==void 0?this.shouldAdjustScrollPositionOnItemSizeChange(o,s,this):o.start{t&&this._measureElement(t,void 0)},this.getVirtualItems=De(()=>[this.getIndexes(),this.getMeasurements()],(t,r)=>{let o=[];for(let i=0,s=t.length;ithis.options.debug}),this.getVirtualItemForOffset=t=>{let r=this.getMeasurements();if(r.length!==0)return pt(r[Wr(0,r.length-1,o=>pt(r[o]).start,t)])},this.getOffsetForAlignment=(t,r)=>{let o=this.getSize(),i=this.getScrollOffset();r==="auto"&&(t<=i?r="start":t>=i+o?r="end":r="start"),r==="start"?t=t:r==="end"?t=t-o:r==="center"&&(t=t-o/2);let s=this.options.horizontal?"scrollWidth":"scrollHeight",l=(this.scrollElement?"document"in this.scrollElement?this.scrollElement.document.documentElement[s]:this.scrollElement[s]:0)-o;return Math.max(Math.min(l,t),0)},this.getOffsetForIndex=(t,r="auto")=>{t=Math.max(0,Math.min(t,this.options.count-1));let o=this.getMeasurements()[t];if(!o)return;let i=this.getSize(),s=this.getScrollOffset();if(r==="auto")if(o.end>=s+i-this.options.scrollPaddingEnd)r="end";else if(o.start<=s+this.options.scrollPaddingStart)r="start";else return[s,r];let a=r==="end"?o.end+this.options.scrollPaddingEnd:o.start-this.options.scrollPaddingStart;return[this.getOffsetForAlignment(a,r),r]},this.isDynamicMode=()=>this.elementsCache.size>0,this.cancelScrollToIndex=()=>{this.scrollToIndexTimeoutId!==null&&this.targetWindow&&(this.targetWindow.clearTimeout(this.scrollToIndexTimeoutId),this.scrollToIndexTimeoutId=null)},this.scrollToOffset=(t,{align:r="start",behavior:o}={})=>{this.cancelScrollToIndex(),o==="smooth"&&this.isDynamicMode()&&console.warn("The `smooth` scroll behavior is not fully supported with dynamic size."),this._scrollToOffset(this.getOffsetForAlignment(t,r),{adjustments:void 0,behavior:o})},this.scrollToIndex=(t,{align:r="auto",behavior:o}={})=>{t=Math.max(0,Math.min(t,this.options.count-1)),this.cancelScrollToIndex(),o==="smooth"&&this.isDynamicMode()&&console.warn("The `smooth` scroll behavior is not fully supported with dynamic size.");let i=this.getOffsetForIndex(t,r);if(!i)return;let[s,a]=i;this._scrollToOffset(s,{adjustments:void 0,behavior:o}),o!=="smooth"&&this.isDynamicMode()&&this.targetWindow&&(this.scrollToIndexTimeoutId=this.targetWindow.setTimeout(()=>{if(this.scrollToIndexTimeoutId=null,this.elementsCache.has(this.options.getItemKey(t))){let[u]=pt(this.getOffsetForIndex(t,a));Gr(u,this.getScrollOffset())||this.scrollToIndex(t,{align:a,behavior:o})}else this.scrollToIndex(t,{align:a,behavior:o})}))},this.scrollBy=(t,{behavior:r}={})=>{this.cancelScrollToIndex(),r==="smooth"&&this.isDynamicMode()&&console.warn("The `smooth` scroll behavior is not fully supported with dynamic size."),this._scrollToOffset(this.getScrollOffset()+t,{adjustments:void 0,behavior:r})},this.getTotalSize=()=>{var t;let r=this.getMeasurements(),o;return r.length===0?o=this.options.paddingStart:o=this.options.lanes===1?((t=r[r.length-1])==null?void 0:t.end)??0:Math.max(...r.slice(-this.options.lanes).map(i=>i.end)),o-this.options.scrollMargin+this.options.paddingEnd},this._scrollToOffset=(t,{adjustments:r,behavior:o})=>{this.options.scrollToFn(t,{behavior:o,adjustments:r},this)},this.measure=()=>{var t,r;this.itemSizeCache=new Map,(r=(t=this.options).onChange)==null||r.call(t,this,!1)},this.setOptions(n)}},Wr=(e,n,t,r)=>{for(;e<=n;){let o=(e+n)/2|0,i=t(o);if(ir)n=o-1;else return o}return e>0?e-1:0};function ys({measurements:e,outerSize:n,scrollOffset:t}){let r=e.length-1,i=Wr(0,r,a=>e[a].start,t),s=i;for(;s({}),{})[1],t={...e,onChange:(o,i)=>{var s;i?Jt(n):n(),(s=e.onChange)==null||s.call(e,o,i)}},[r]=H(()=>new mt(t));return r.setOptions(t),L(()=>r._didMount(),[]),vs(()=>r._willUpdate()),r}function Xr(e){return Ss({observeElementRect:Kr,observeElementOffset:jr,scrollToFn:qr,...e})}function Yr(e){return{render:function(n){Wt(n,e)},unmount:function(){Yt(e)}}}var no=Symbol.for("immer-nothing"),Jr=Symbol.for("immer-draftable"),P=Symbol.for("immer-state");function ie(e,...n){throw new Error(`[Immer] minified error nr: ${e}. Full error at: https://bit.ly/3cXEKWf`)}var $e=Object.getPrototypeOf;function Oe(e){return!!e&&!!e[P]}function ye(e){return e?ro(e)||Array.isArray(e)||!!e[Jr]||!!e.constructor?.[Jr]||St(e)||wt(e):!1}var ws=Object.prototype.constructor.toString();function ro(e){if(!e||typeof e!="object")return!1;let n=$e(e);if(n===null)return!0;let t=Object.hasOwnProperty.call(n,"constructor")&&n.constructor;return t===Object?!0:typeof t=="function"&&Function.toString.call(t)===ws}function Le(e,n){vt(e)===0?Object.entries(e).forEach(([t,r])=>{n(t,r,e)}):e.forEach((t,r)=>n(r,t,e))}function vt(e){let n=e[P];return n?n.type_:Array.isArray(e)?1:St(e)?2:wt(e)?3:0}function yn(e,n){return vt(e)===2?e.has(n):Object.prototype.hasOwnProperty.call(e,n)}function oo(e,n,t){let r=vt(e);r===2?e.set(n,t):r===3?e.add(t):e[n]=t}function Cs(e,n){return e===n?e!==0||1/e===1/n:e!==e&&n!==n}function St(e){return e instanceof Map}function wt(e){return e instanceof Set}function N(e){return e.copy_||e.base_}function vn(e,n){if(St(e))return new Map(e);if(wt(e))return new Set(e);if(Array.isArray(e))return Array.prototype.slice.call(e);if(!n&&ro(e))return $e(e)?{...e}:Object.assign(Object.create(null),e);let t=Object.getOwnPropertyDescriptors(e);delete t[P];let r=Reflect.ownKeys(t);for(let o=0;o1&&(e.set=e.add=e.clear=e.delete=Es),Object.freeze(e),n&&Le(e,(t,r)=>ke(r,!0),!0)),e}function Es(){ie(2)}function Ct(e){return Object.isFrozen(e)}var Sn={};function Me(e){let n=Sn[e];return n||ie(0,e),n}function Rs(e,n){Sn[e]||(Sn[e]=n)}var Je;function ht(){return Je}function bs(e,n){return{drafts_:[],parent_:e,immer_:n,canAutoFreeze_:!0,unfinalizedDrafts_:0}}function Qr(e,n){n&&(Me("Patches"),e.patches_=[],e.inversePatches_=[],e.patchListener_=n)}function wn(e){Cn(e),e.drafts_.forEach(xs),e.drafts_=null}function Cn(e){e===Je&&(Je=e.parent_)}function Zr(e){return Je=bs(Je,e)}function xs(e){let n=e[P];n.type_===0||n.type_===1?n.revoke_():n.revoked_=!0}function eo(e,n){n.unfinalizedDrafts_=n.drafts_.length;let t=n.drafts_[0];return e!==void 0&&e!==t?(t[P].modified_&&(wn(n),ie(4)),ye(e)&&(e=_t(n,e),n.parent_||yt(n,e)),n.patches_&&Me("Patches").generateReplacementPatches_(t[P].base_,e,n.patches_,n.inversePatches_)):e=_t(n,t,[]),wn(n),n.patches_&&n.patchListener_(n.patches_,n.inversePatches_),e!==no?e:void 0}function _t(e,n,t){if(Ct(n))return n;let r=n[P];if(!r)return Le(n,(o,i)=>to(e,r,n,o,i,t),!0),n;if(r.scope_!==e)return n;if(!r.modified_)return yt(e,r.base_,!0),r.base_;if(!r.finalized_){r.finalized_=!0,r.scope_.unfinalizedDrafts_--;let o=r.copy_,i=o,s=!1;r.type_===3&&(i=new Set(o),o.clear(),s=!0),Le(i,(a,l)=>to(e,r,o,a,l,t,s)),yt(e,o,!1),t&&e.patches_&&Me("Patches").generatePatches_(r,t,e.patches_,e.inversePatches_)}return r.copy_}function to(e,n,t,r,o,i,s){if(Oe(o)){let a=i&&n&&n.type_!==3&&!yn(n.assigned_,r)?i.concat(r):void 0,l=_t(e,o,a);if(oo(t,r,l),Oe(l))e.canAutoFreeze_=!1;else return}else s&&t.add(o);if(ye(o)&&!Ct(o)){if(!e.immer_.autoFreeze_&&e.unfinalizedDrafts_<1)return;_t(e,o),(!n||!n.scope_.parent_)&&yt(e,o)}}function yt(e,n,t=!1){!e.parent_&&e.immer_.autoFreeze_&&e.canAutoFreeze_&&ke(n,t)}function Ms(e,n){let t=Array.isArray(e),r={type_:t?1:0,scope_:n?n.scope_:ht(),modified_:!1,finalized_:!1,assigned_:{},parent_:n,base_:e,draft_:null,copy_:null,revoke_:null,isManual_:!1},o=r,i=En;t&&(o=[r],i=Qe);let{revoke:s,proxy:a}=Proxy.revocable(o,i);return r.draft_=a,r.revoke_=s,a}var En={get(e,n){if(n===P)return e;let t=N(e);if(!yn(t,n))return Fs(e,t,n);let r=t[n];return e.finalized_||!ye(r)?r:r===hn(e.base_,n)?(_n(e),e.copy_[n]=Ze(r,e)):r},has(e,n){return n in N(e)},ownKeys(e){return Reflect.ownKeys(N(e))},set(e,n,t){let r=io(N(e),n);if(r?.set)return r.set.call(e.draft_,t),!0;if(!e.modified_){let o=hn(N(e),n),i=o?.[P];if(i&&i.base_===t)return e.copy_[n]=t,e.assigned_[n]=!1,!0;if(Cs(t,o)&&(t!==void 0||yn(e.base_,n)))return!0;_n(e),_e(e)}return e.copy_[n]===t&&(t!==void 0||n in e.copy_)||Number.isNaN(t)&&Number.isNaN(e.copy_[n])||(e.copy_[n]=t,e.assigned_[n]=!0),!0},deleteProperty(e,n){return hn(e.base_,n)!==void 0||n in e.base_?(e.assigned_[n]=!1,_n(e),_e(e)):delete e.assigned_[n],e.copy_&&delete e.copy_[n],!0},getOwnPropertyDescriptor(e,n){let t=N(e),r=Reflect.getOwnPropertyDescriptor(t,n);return r&&{writable:!0,configurable:e.type_!==1||n!=="length",enumerable:r.enumerable,value:t[n]}},defineProperty(){ie(11)},getPrototypeOf(e){return $e(e.base_)},setPrototypeOf(){ie(12)}},Qe={};Le(En,(e,n)=>{Qe[e]=function(){return arguments[0]=arguments[0][0],n.apply(this,arguments)}});Qe.deleteProperty=function(e,n){return Qe.set.call(this,e,n,void 0)};Qe.set=function(e,n,t){return En.set.call(this,e[0],n,t,e[0])};function hn(e,n){let t=e[P];return(t?N(t):e)[n]}function Fs(e,n,t){let r=io(n,t);return r?"value"in r?r.value:r.get?.call(e.draft_):void 0}function io(e,n){if(!(n in e))return;let t=$e(e);for(;t;){let r=Object.getOwnPropertyDescriptor(t,n);if(r)return r;t=$e(t)}}function _e(e){e.modified_||(e.modified_=!0,e.parent_&&_e(e.parent_))}function _n(e){e.copy_||(e.copy_=vn(e.base_,e.scope_.immer_.useStrictShallowCopy_))}var Is=class{constructor(e){this.autoFreeze_=!0,this.useStrictShallowCopy_=!1,this.produce=(n,t,r)=>{if(typeof n=="function"&&typeof t!="function"){let i=t;t=n;let s=this;return function(l=i,...u){return s.produce(l,f=>t.call(this,f,...u))}}typeof t!="function"&&ie(6),r!==void 0&&typeof r!="function"&&ie(7);let o;if(ye(n)){let i=Zr(this),s=Ze(n,void 0),a=!0;try{o=t(s),a=!1}finally{a?wn(i):Cn(i)}return Qr(i,r),eo(o,i)}else if(!n||typeof n!="object"){if(o=t(n),o===void 0&&(o=n),o===no&&(o=void 0),this.autoFreeze_&&ke(o,!0),r){let i=[],s=[];Me("Patches").generateReplacementPatches_(n,o,i,s),r(i,s)}return o}else ie(1,n)},this.produceWithPatches=(n,t)=>{if(typeof n=="function")return(s,...a)=>this.produceWithPatches(s,l=>n(l,...a));let r,o;return[this.produce(n,t,(s,a)=>{r=s,o=a}),r,o]},typeof e?.autoFreeze=="boolean"&&this.setAutoFreeze(e.autoFreeze),typeof e?.useStrictShallowCopy=="boolean"&&this.setUseStrictShallowCopy(e.useStrictShallowCopy)}createDraft(e){ye(e)||ie(8),Oe(e)&&(e=Ts(e));let n=Zr(this),t=Ze(e,void 0);return t[P].isManual_=!0,Cn(n),t}finishDraft(e,n){let t=e&&e[P];(!t||!t.isManual_)&&ie(9);let{scope_:r}=t;return Qr(r,n),eo(void 0,r)}setAutoFreeze(e){this.autoFreeze_=e}setUseStrictShallowCopy(e){this.useStrictShallowCopy_=e}applyPatches(e,n){let t;for(t=n.length-1;t>=0;t--){let o=n[t];if(o.path.length===0&&o.op==="replace"){e=o.value;break}}t>-1&&(n=n.slice(t+1));let r=Me("Patches").applyPatches_;return Oe(e)?r(e,n):this.produce(e,o=>r(o,n))}};function Ze(e,n){let t=St(e)?Me("MapSet").proxyMap_(e,n):wt(e)?Me("MapSet").proxySet_(e,n):Ms(e,n);return(n?n.scope_:ht()).drafts_.push(t),t}function Ts(e){return Oe(e)||ie(10,e),so(e)}function so(e){if(!ye(e)||Ct(e))return e;let n=e[P],t;if(n){if(!n.modified_)return n.base_;n.finalized_=!0,t=vn(e,n.scope_.immer_.useStrictShallowCopy_)}else t=vn(e,!0);return Le(t,(r,o)=>{oo(t,r,so(o))}),n&&(n.finalized_=!1),t}function Et(){class e extends Map{constructor(l,u){super(),this[P]={type_:2,parent_:u,scope_:u?u.scope_:ht(),modified_:!1,finalized_:!1,copy_:void 0,assigned_:void 0,base_:l,draft_:this,isManual_:!1,revoked_:!1}}get size(){return N(this[P]).size}has(l){return N(this[P]).has(l)}set(l,u){let f=this[P];return s(f),(!N(f).has(l)||N(f).get(l)!==u)&&(t(f),_e(f),f.assigned_.set(l,!0),f.copy_.set(l,u),f.assigned_.set(l,!0)),this}delete(l){if(!this.has(l))return!1;let u=this[P];return s(u),t(u),_e(u),u.base_.has(l)?u.assigned_.set(l,!1):u.assigned_.delete(l),u.copy_.delete(l),!0}clear(){let l=this[P];s(l),N(l).size&&(t(l),_e(l),l.assigned_=new Map,Le(l.base_,u=>{l.assigned_.set(u,!1)}),l.copy_.clear())}forEach(l,u){let f=this[P];N(f).forEach((c,g,d)=>{l.call(u,this.get(g),g,this)})}get(l){let u=this[P];s(u);let f=N(u).get(l);if(u.finalized_||!ye(f)||f!==u.base_.get(l))return f;let c=Ze(f,u);return t(u),u.copy_.set(l,c),c}keys(){return N(this[P]).keys()}values(){let l=this.keys();return{[Symbol.iterator]:()=>this.values(),next:()=>{let u=l.next();return u.done?u:{done:!1,value:this.get(u.value)}}}}entries(){let l=this.keys();return{[Symbol.iterator]:()=>this.entries(),next:()=>{let u=l.next();if(u.done)return u;let f=this.get(u.value);return{done:!1,value:[u.value,f]}}}}[Symbol.iterator](){return this.entries()}}function n(a,l){return new e(a,l)}function t(a){a.copy_||(a.assigned_=new Map,a.copy_=new Map(a.base_))}class r extends Set{constructor(l,u){super(),this[P]={type_:3,parent_:u,scope_:u?u.scope_:ht(),modified_:!1,finalized_:!1,copy_:void 0,base_:l,draft_:this,drafts_:new Map,revoked_:!1,isManual_:!1}}get size(){return N(this[P]).size}has(l){let u=this[P];return s(u),u.copy_?!!(u.copy_.has(l)||u.drafts_.has(l)&&u.copy_.has(u.drafts_.get(l))):u.base_.has(l)}add(l){let u=this[P];return s(u),this.has(l)||(i(u),_e(u),u.copy_.add(l)),this}delete(l){if(!this.has(l))return!1;let u=this[P];return s(u),i(u),_e(u),u.copy_.delete(l)||(u.drafts_.has(l)?u.copy_.delete(u.drafts_.get(l)):!1)}clear(){let l=this[P];s(l),N(l).size&&(i(l),_e(l),l.copy_.clear())}values(){let l=this[P];return s(l),i(l),l.copy_.values()}entries(){let l=this[P];return s(l),i(l),l.copy_.entries()}keys(){return this.values()}[Symbol.iterator](){return this.values()}forEach(l,u){let f=this.values(),c=f.next();for(;!c.done;)l.call(u,c.value,c.value,this),c=f.next()}}function o(a,l){return new r(a,l)}function i(a){a.copy_||(a.copy_=new Set,a.base_.forEach(l=>{if(ye(l)){let u=Ze(l,a);a.drafts_.set(l,u),a.copy_.add(u)}else a.copy_.add(l)}))}function s(a){a.revoked_&&ie(3,JSON.stringify(N(a)))}Rs("MapSet",{proxyMap_:n,proxySet_:o})}var Z=new Is,lo=Z.produce,wl=Z.produceWithPatches.bind(Z),Cl=Z.setAutoFreeze.bind(Z),El=Z.setUseStrictShallowCopy.bind(Z),Rl=Z.applyPatches.bind(Z),bl=Z.createDraft.bind(Z),xl=Z.finishDraft.bind(Z);function He(e){var n=H(function(){return ke(typeof e=="function"?e():e,!0)}),t=n[1];return[n[0],Y(function(r){t(typeof r=="function"?lo(r):ke(r))},[])]}function Ps(e,n,t,r,o){window.Shiny.shinyapp.makeRequest(e,n,t,r,o)}function ao({method:e,args:n,blobs:t}){return new Promise((r,o)=>{Ps(e,n,i=>{r(i)},i=>{o(i)},t)})}function uo({patchInfo:e,patches:n,onSuccess:t,onError:r,columns:o,setData:i,setCellEditMapAtLoc:s}){let a=n.map(l=>({row_index:l.rowIndex,column_index:l.columnIndex,value:l.value}));ao({method:e.key,args:[a]}).then(l=>{if(!Array.isArray(l))throw new Error("Expected a response of a list of patches");for(let f of l)if(!("row_index"in f&&"column_index"in f&&"value"in f))throw new Error("Expected list of patches containing `row_index`, `column_index`, and `value`");l=l;let u=l.map(f=>({rowIndex:f.row_index,columnIndex:f.column_index,value:f.value}));i(f=>{u.forEach(({rowIndex:c,columnIndex:g,value:d})=>{f[c][g]=d})}),n.forEach(({rowIndex:f,columnIndex:c,value:g})=>{s(f,c,d=>{d.state===ce.EditSaving&&(d.state=ce.Ready,d.value=g,d.errorTitle=void 0)})}),u.forEach(({rowIndex:f,columnIndex:c,value:g})=>{s(f,c,d=>{d.value=g,d.state=ce.EditSuccess,d.errorTitle=void 0})}),t(u)}).catch(l=>{n.forEach(({rowIndex:u,columnIndex:f,value:c})=>{s(u,f,g=>{g.value=String(c),g.state=ce.EditFailure,g.errorTitle=String(l)})}),r(l)})}var ce={EditSaving:"EditSaving",EditSuccess:"EditSuccess",EditFailure:"EditFailure",Editing:"Editing",Ready:"Ready"},xn={EditSaving:"cell-edit-saving",EditSuccess:"cell-edit-success",EditFailure:"cell-edit-failure",Editing:"cell-edit-editing",Ready:void 0},bn=e=>e!==null&&typeof e=="object"&&Object.prototype.hasOwnProperty.call(e,"isShinyHtml")&&e.isShinyHtml===!0,Rn=e=>bn(e)?e.obj.html:e===null?"":e,co=({containerRef:e,rowId:n,cell:t,patchInfo:r,columns:o,coldefs:i,rowIndex:s,columnIndex:a,editCellsIsAllowed:l,getSortedRowModel:u,cellEditInfo:f,cellStyle:c,cellClassName:g,setData:d,setCellEditMapAtLoc:p,selection:m})=>{let _=t.getValue(),h=t.column.columnDef.meta.isHtmlColumn,y=f?.value??_,R=f?.state??ce.Ready,V=f?.errorTitle,T=f?.isEditing??!1,D=f?.editValue??Rn(y),z=X(null),U=X(null),G=Y(({resetIsEditing:x=!1,resetEditValue:I=!1}={resetIsEditing:!0,resetEditValue:!0})=>{p(s,a,A=>{x&&(A.isEditing=!1),I&&(A.editValue=void 0)})},[s,a,p]),q=x=>{x.key==="Escape"&&(x.preventDefault(),x.stopPropagation(),G(),m.focusOffset(n,0))},te=x=>{if(x.key!=="Tab")return;x.preventDefault(),x.stopPropagation();let I=x.shiftKey,A=a;for(;;){let K=A+(I?-1:1);if(K<0||K>=i.length)return;if(A=K,i[K].meta.isHtmlColumn!==!0)break}Ae(),p(s,A,K=>{K.isEditing=!0})},Ee=x=>{if(x.key!=="Enter")return;x.preventDefault(),x.stopPropagation();let I=x.shiftKey,A=u(),K=A.rows.findIndex(Ie=>Ie.id===n);if(K<0)return;let le=K+(I?-1:1);if(le<0||le>=A.rows.length)return;Ae();let nt=A.rows[le].index;p(nt,a,Ie=>{Ie.isEditing=!0})},bt=x=>{[q,Ee,te].forEach(I=>I(x))},Ae=Y(()=>{if(p(s,a,x=>{x.errorTitle=void 0}),`${Rn(y)}`==`${D}`){G(),p(s,a,x=>{x.state=R});return}G({resetIsEditing:!0}),p(s,a,x=>{x.state=ce.EditSaving}),uo({patchInfo:r,patches:[{rowIndex:s,columnIndex:a,value:D}],onSuccess:x=>{G({resetEditValue:!0})},onError:x=>{},columns:o,setData:d,setCellEditMapAtLoc:p})},[p,s,a,y,D,G,r,o,d,R]);L(()=>{T&&U.current&&(U.current.focus(),U.current.select())},[T]),L(()=>{if(!T||!z.current||!U.current)return;let x=K=>{z.current?.contains(K.target)&&K.stopPropagation()},I=z.current;I.addEventListener("mousedown",x);let A=K=>{K.target!==U.current&&(Ae(),G())};return document.body.addEventListener("mousedown",A),()=>{I.removeEventListener("mousedown",x),document.body.removeEventListener("mousedown",A)}},[R,Ae,s,a,T,G]);function Fe(x){T&&x.target.select()}function Ne(x){p(s,a,I=>{I.editValue=x.target.value})}let et,ze,tt=V,ge=g,Ge=x=>{x&&(ge?(ge+=" ",ge+=x):ge=x)};Ge(xn[T?ce.Editing:R]);let Be=!1,Ue=null;return R===ce.EditSaving?ze=D:(T?Ue=b.createElement("textarea",{value:String(D),onChange:Ne,onFocus:Fe,onKeyDown:bt,ref:U}):h?Ge("cell-html"):l&&(Ge("cell-editable"),et=x=>{p(s,a,I=>{I.isEditing=!0,I.editValue=Rn(y)})}),bn(y)?Be=!0:ze=gt(t.column.columnDef.cell,t.getContext())),L(()=>{if(!z.current||!Be||!bn(y))return;let x=JSON.parse(JSON.stringify(y.obj));window.Shiny.renderContentAsync(z.current,x);let I=z.current;return()=>{window.Shiny.unbindAll(I),I.replaceChildren("")}},[z,y,s,a,Be]),b.createElement("td",{ref:z,onDoubleClick:et,title:tt,className:ge,style:{...c}},Ue,ze)};var fo=()=>{let[e,n]=He(new Map);return Et(),{cellEditMap:e,setCellEditMapAtLoc:(r,o,i)=>{n(s=>{let a=go(r,o),l=s.get(a)??{};i(l),s.set(a,l)})}}},go=(e,n)=>`[${e}, ${n}]`;var po=(e,n,t)=>{let r=go(n,t);return[e.get(r)??{},r]};function Rt(e,n,t){let r=Object.assign({top:0,right:0,bottom:0,left:0},t),o=e,i=o.scrollTop+r.top,s=o.scrollLeft+r.left,a=i+o.clientHeight-r.top-r.bottom,l=s+o.clientWidth-r.left-r.right;for(let u=0;u=i&&c<=a&&g>=s&&g<=l)return f}return null}function Mn(e,n){return document?.defaultView?.getComputedStyle(e,null)?.getPropertyValue(n)}var _o=e=>{let[n,t]=H(!1),{range:r,from:o,to:i,onRangeChange:s}=e;return b.createElement(Vs,{range:r,value:[o,i],editing:n,onValueChange:a=>s(...a),onFocus:()=>t(!0),onBlur:()=>t(!1)})};var Vs=e=>{let[n,t]=e.value,{editing:r,onFocus:o}=e,[i,s]=e.range(),a=X(null),l=X(null);return b.createElement("div",{onBlur:u=>{if(!u.currentTarget.contains(u.relatedTarget))return e.onBlur()},onFocus:()=>o(),style:{display:"flex",gap:"0.5rem"}},b.createElement("input",{ref:a,className:`form-control form-control-sm ${a.current?.checkValidity()?"":"is-invalid"}`,style:{flex:"1 1 0",width:"0"},type:"number",placeholder:mo(r,"Min",i),defaultValue:n,step:"any",onChange:u=>{let f=ho(u.target.value);a.current&&(a.current.classList.toggle("is-invalid",!u.target.checkValidity()),e.onValueChange([f,t]))}}),b.createElement("input",{ref:l,className:`form-control form-control-sm ${l.current?.checkValidity()?"":"is-invalid"}`,style:{flex:"1 1 0",width:"0"},type:"number",placeholder:mo(r,"Max",s),defaultValue:t,step:"any",onChange:u=>{let f=ho(u.target.value);l.current&&(l.current.classList.toggle("is-invalid",!u.target.checkValidity()),e.onValueChange([n,f]))}}))};function mo(e,n,t){if(e)return typeof t>"u"?n:`${n} (${t})`}function ho(e){if(e!=="")return+e}function yo(e){let[n,t]=H([]),r=e?{getFilteredRowModel:Ar(),getFacetedRowModel:kr(),getFacetedUniqueValues:Hr(),getFacetedMinMaxValues:Or(),filterFns:{substring:(o,i,s,a)=>o.getValue(i)?.toString().includes(s)??!1},onColumnFiltersChange:t}:{};return{columnFilters:n,columnFiltersState:{columnFilters:n},filtersTableOptions:r,setColumnFilters:t}}var vo=({header:e,className:n,...t})=>{let r=e.column.columnDef.meta?.typeHint;if(!r||r.type==="html")return null;if(r.type==="numeric"){let[o,i]=e.column.getFilterValue()??[void 0,void 0];return _o({from:o,to:i,range:()=>e.column.getFacetedMinMaxValues()??[void 0,void 0],onRangeChange:(a,l)=>e.column.setFilterValue([a,l])})}return b.createElement("input",{...t,value:e.column.getFilterValue()||"",className:`form-control form-control-sm ${n}`,type:"text",onChange:o=>e.column.setFilterValue(o.target.value)})};var ee=class e{static{this._empty=new e(new Set)}constructor(n){this._set=n}static empty(){return this._empty}static just(...n){return this.empty().add(...n)}has(n){return this._set.has(n)}add(...n){let t=new Set(this._set.keys());for(let r of n)t.add(r);return new e(t)}toggle(n){return this.has(n)?this.delete(n):this.add(n)}delete(n){let t=new Set(this._set.keys());return t.delete(n),new e(t)}clear(){return e.empty()}[Symbol.iterator](){return this._set[Symbol.iterator]()}toList(){return[...this._set.keys()]}};var se=class e{static{this._NONE="none"}static{this._ROW_SINGLE="single"}static{this._ROW_MULTIPLE="multiple"}static{this._COL_SINGLE="single"}static{this._col_multiple="multiple"}static{this._RECT_CELL="cell"}static{this._RECT_REGION="region"}static{this._rowEnum={NONE:e._NONE,SINGLE:e._ROW_SINGLE,MULTIPLE:e._ROW_MULTIPLE}}static{this._colEnum={NONE:e._NONE,SINGLE:e._COL_SINGLE,MULTIPLE:e._col_multiple}}static{this._rectEnum={NONE:e._NONE,REGION:e._RECT_REGION,CELL:e._RECT_CELL}}constructor({row:n,col:t,rect:r}){if(!Object.values(e._rowEnum).includes(n))throw new Error(`Invalid row selection mode: ${n}`);if(!Object.values(e._colEnum).includes(t))throw new Error(`Invalid col selection mode: ${t}`);if(!Object.values(e._rectEnum).includes(r))throw new Error(`Invalid rect selection mode: ${r}`);this.row=n,this.col=t,this.rect=r}isNone(){return this.row===e._rowEnum.NONE&&this.col===e._colEnum.NONE&&this.rect===e._rectEnum.NONE}};function wo(e){return e||(e={row:"multiple",col:"none",rect:"none"}),new se({row:e.row,col:e.col,rect:e.rect})}function Co({isEditingCell:e,editCellsIsAllowed:n,selectionModes:t,keyAccessor:r,focusOffset:o,focusEscape:i,onKeyDownEnter:s,between:a}){let[l,u]=H(ee.empty()),[f,c]=H(null),g=m=>{if(t.isNone())return;let _=m.currentTarget,h=r(_);if(e&&_.classList.contains(xn[ce.Editing]))return;let y=Ds(t,a,l,m,h,f);y&&(u(y.selection),y.anchor&&(c(h),_.focus()),m.preventDefault())},d=m=>{if(e||t.isNone())return;let _=m.currentTarget,h=r(_),y=l.has(h);if(m.key==="Escape"){i(_),m.preventDefault();return}if(t.row===se._rowEnum.SINGLE){if(m.key===" "||m.key==="Enter")m.preventDefault(),n&&m.key==="Enter"?s(_):l.has(h)?u(ee.empty()):u(ee.just(h));else if(m.key==="ArrowUp"||m.key==="ArrowDown"){let R=o(h,m.key==="ArrowUp"?-1:1);R&&(m.preventDefault(),y&&u(ee.just(R)))}}else t.row===se._rowEnum.MULTIPLE&&(m.key===" "||m.key==="Enter"?(m.preventDefault(),n&&m.key==="Enter"?s(_):u(l.toggle(h))):(m.key==="ArrowUp"||m.key==="ArrowDown")&&o(h,m.key==="ArrowUp"?-1:1)&&m.preventDefault())};return{has(m){return l.has(m)},set(m,_){u(_?l.add(m):l.delete(m))},setMultiple(m){u(ee.just(...m))},clear(){u(l.clear())},keys(){return l},itemHandlers(){return{onMouseDown:g,onKeyDown:d}},focusOffset:o}}var So=/^mac/i.test(window.navigator.userAgentData?.platform??window.navigator.platform);function Ds(e,n,t,r,o,i){let{shiftKey:s,altKey:a}=r,l=So?r.metaKey:r.ctrlKey;if((So?r.ctrlKey:r.metaKey)||a||e.row===se._rowEnum.NONE)return null;if(e.row===se._rowEnum.SINGLE)return l&&!s?t.has(o)?{selection:ee.empty(),anchor:!0}:{selection:ee.just(o),anchor:!0}:{selection:ee.just(o),anchor:!0};if(e.row===se._rowEnum.MULTIPLE)if(s&&l){if(i!==null&&n){let f=n(i,o);return{selection:t.add(...f)}}}else{if(l)return{selection:t.toggle(o),anchor:!0};if(s){if(i!==null&&n){let f=n(i,o);return{selection:ee.just(...f)}}}else return{selection:ee.just(o),anchor:!0}}else throw new Error(`Unsupported row selection mode: ${e.row}`);return null}function Eo({getColDefs:e}){let[n,t]=H([]);return{sorting:n,sortTableStateOptions:{sorting:n},sortTableOptions:{onSortingChange:r=>{let o=typeof r=="function"?r(n):r,i=e(),s=new Set(i.filter(l=>l.meta.isHtmlColumn).map(l=>l.header)),a=s.size==0?o:o.filter(l=>!s.has(l.id));t(a)},getSortedRowModel:Nr()},setSorting:t}}var Ro="sort-arrow",bo={viewBox:[-1,-1,2,2].map(e=>e*1.4).join(" "),width:"100%",height:"100%",style:{paddingLeft:"3px"}},xo={stroke:"#333333",strokeWidth:"0.6",fill:"transparent"},$s=b.createElement("svg",{xmlns:"http://www.w3.org/2000/svg",...bo,className:`${Ro} sort-arrow-up`},b.createElement("path",{d:"M -1 0.5 L 0 -0.5 L 1 0.5",...xo,strokeLinecap:"round"})),Os=b.createElement("svg",{xmlns:"http://www.w3.org/2000/svg",...bo,className:`${Ro} sort-arrow-down`},b.createElement("path",{d:"M -1 -0.5 L 0 0.5 L 1 -0.5",...xo,strokeLinecap:"round"})),Mo=({direction:e})=>{if(!e)return null;if(e==="asc")return $s;if(e==="desc")return Os;throw new Error(`Unexpected sort direction: '${e}'`)};Et();var Fo=({location:e,rowIndex:n,columnIndex:t})=>`[${e}, ${n}, ${t}]`,Io=({initStyleInfos:e,nrow:n,ncol:t})=>{let[r,o]=He(new Map),i=Y(l=>{let{location:u,rows:f,cols:c}=l;o(g=>{let d=f??Array.from({length:n},(m,_)=>_),p=c??Array.from({length:t},(m,_)=>_);for(let m of d)for(let _ of p){let h=Fo({location:u,rowIndex:m,columnIndex:_}),y=g.get(h)??{style:{},class:void 0},R;y.class?l.class?R=`${y.class} ${l.class}`:R=y.class:l.class?R=l.class:R=void 0,g.set(h,{location:u,rowIndex:m,columnIndex:_,style:{...y.style,...l.style},class:R})}})},[t,n,o]),s=Y(()=>{o(l=>{l.clear()})},[o]),a=Y(l=>{s();for(let u of l)i(u)},[i,s]);return L(()=>{a(e)},[e,a]),{styleInfoMap:r,setStyleInfo:i,setStyleInfos:a,resetStyleInfos:s}};var To=(e,n,t,r)=>{let o=Fo({location:n,rowIndex:t,columnIndex:r}),i=e.get(o);return{cellStyle:i?.style,cellClassName:i?.class}},Da=document.createElement("cssStringToObj");var Po=` /* * * # Variables @@ -261,7 +261,7 @@ shiny-data-frame .shiny-data-grid > table > tbody > tr > td.cell-edit-saving { shiny-data-frame .shiny-data-grid > table > tbody > tr > td.cell-edit-failure { outline: 2px var(--shiny-datagrid-table-cell-edit-failure-border-style) var(--shiny-datagrid-table-cell-edit-failure-border-color); background-color: var(--shiny-datagrid-table-cell-edit-failure-bgcolor); -}`;function Po(e,n,t){let[r,o]=H(0),i=b.useCallback(a=>{o(-1),a.target===a.currentTarget&&Et(e,n(),t)?.focus()},[e,n,t]),s=b.useCallback(a=>{o(0)},[]);return{containerTabIndex:r,containerHandlers:{onFocus:i,onBlur:s}}}function Vo(e,n,t,r,o){return oe(()=>{let i=e??!0;if(!i)return null;let s=typeof i=="string"?i:"Viewing rows {start} through {end} of {total}";if(!n||t.length===0||!r)return null;let a=n.scrollTop+r.clientHeight,l=n.scrollTop+n.clientHeight,[u,f]=Ls(a,l,t,(p,h)=>p.start+p.size/2);if(u===null||f===null)return null;let c=t[u],g=t[f];if(c===void 0||g===void 0||c.index===0&&g.index===o-1)return null;let d=ks(s,c.index+1,g.index+1,o);return b.createElement("div",{className:"shiny-data-grid-summary"},d)},[e,n,t,r,o])}function Ls(e,n,t,r){let o=null,i=null;for(let s=0;s=e&&(o=s,i=s);else if(r(a,!1)<=n)i=s;else break}return[o,i]}function ks(e,n,t,r){return e.replace(/\{(start|end|total)\}/g,(o,i)=>i==="start"?n+"":i==="end"?t+"":i==="total"?r+"":o)}var Hs=({id:e,gridInfo:{payload:n,patchInfo:t,selectionModes:r},bgcolor:o})=>{let{columns:i,typeHints:s,data:a,options:l={width:void 0,height:void 0,fill:!1,styles:[]}}=n,{width:u,height:f,fill:c,filters:g,styles:d}=l,p=X(null),h=X(null),_=X(null),m=Fo({initStyleInfos:d??[],nrow:a.length,ncol:i.length}),y=m.styleInfoMap,{setStyleInfos:R}=m,V=co(),T=V.cellEditMap,D=V.setCellEditMapAtLoc,z=l.editable===!0,U=oe(()=>{for(let v of T.values())if(v.isEditing)return!0;return!1},[T]),G=oe(()=>i.map((v,S)=>{let E=s?.[S],F=E?.type==="html",B=F?!1:void 0;return{accessorFn:(W,Bo)=>W[S],filterFn:E?.type==="numeric"?"inNumberRange":"includesString",header:v,meta:{colIndex:S,isHtmlColumn:F,typeHint:E},cell:({getValue:W})=>W(),enableSorting:B}}),[i,s]),q=oe(()=>a,[a]),te=ke(a),Ce=te[0],Rt=te[1],Me=Co({getColDefs:()=>G}),Ae=Me.sorting,Ze=Me.sortTableStateOptions,Ne=Me.sortTableOptions,et=Me.setSorting,{columnFilters:ge,columnFiltersState:ze,filtersTableOptions:Ge,setColumnFilters:Be}=_o(g),x={data:Ce,columns:G,state:{...Ze,...ze},getCoreRowModel:Dr(),...Ne,...Ge},I=Nr(x),A=Wr({count:I.getFilteredRowModel().rows.length,getScrollElement:()=>p.current,estimateSize:()=>31,overscan:15,paddingStart:h.current?.clientHeight??0,isScrollingResetDelay:10});re(()=>{A.scrollToOffset(0)},[n,A]);let K=A.getTotalSize(),le=A.getVirtualItems(),tt=(le.length>0&&le?.[0]?.start||0)-(h.current?.clientHeight??0),Fe=le.length>0?K-(le?.[le.length-1]?.end||0):0,Oo=Vo(l.summary,p?.current,le,h.current,A.options.count),In=l.style??"grid",Lo=In==="grid"?"shiny-data-grid-grid":"shiny-data-grid-table",ko=In==="table"?"table table-sm":null,pe=So(r),zs=!pe.isNone(),Ho=pe.row!==se._rowEnum.NONE,ae=wo({isEditingCell:U,editCellsIsAllowed:z,selectionModes:pe,keyAccessor:v=>v.dataset.key,focusEscape:v=>{setTimeout(()=>{v?.blur(),p.current?.focus()},0)},focusOffset:(v,S=0)=>{let E=I.getSortedRowModel(),F=E.rows.findIndex(W=>W.id===v);if(F<0||(F+=S,F<0||F>=E.rows.length))return null;let B=E.rows[F].id;return A.scrollToIndex(F),setTimeout(()=>{p.current?.querySelector(`[data-key='${B}']`)?.focus()},0),B},between:(v,S)=>As(I.getSortedRowModel(),v,S),onKeyDownEnter:v=>{let S=Array(...v.childNodes.values()).filter(B=>B instanceof HTMLElement&&B.classList.contains("cell-editable"));if(S.length===0)return;let E=Et(p.current,S);if(!E)return;let F=new MouseEvent("dblclick",{bubbles:!0,cancelable:!0});E.dispatchEvent(F)}});L(()=>{let v=E=>{let F=E.detail.cellSelection;if(F.type==="none"){ae.clear();return}else if(F.type==="row"){ae.setMultiple(F.rows.map(String));return}else console.error("Unhandled cell selection update:",F)};if(!e)return;let S=document.getElementById(e);if(S)return S.addEventListener("updateCellSelection",v),()=>{S.removeEventListener("updateCellSelection",v)}},[e,ae,Ce]),L(()=>{let v=E=>{let F=E.detail.sort,B=[];F.map(W=>{B.push({id:i[W.col],desc:W.desc})}),et(B)};if(!e)return;let S=document.getElementById(e);if(S)return S.addEventListener("updateColumnSort",v),()=>{S.removeEventListener("updateColumnSort",v)}},[i,e,et]),L(()=>{let v=E=>{let F=E.detail.filter,B=[];F.map(W=>{B.push({id:i[W.col],value:W.value})}),Be(B)};if(!e)return;let S=document.getElementById(e);if(S)return S.addEventListener("updateColumnFilter",v),()=>{S.removeEventListener("updateColumnFilter",v)}},[i,e,Be]),L(()=>{let v=E=>{let F=E.detail.styles;R(F)};if(!e)return;let S=document.getElementById(e);if(S)return S.addEventListener("updateStyles",v),()=>{S.removeEventListener("updateStyles",v)}},[e,R]),L(()=>{if(!e)return;let v=null;if(pe.isNone())v=null;else if(pe.row!==se._rowEnum.NONE){let S=ae.keys().toList(),E=I.getSortedRowModel().rowsById;v={type:"row",rows:S.map(F=>F in E?E[F].index:null).filter(F=>F!==null)}}else console.error("Unhandled row selection mode:",pe);Shiny.setInputValue(`${e}_cell_selection`,v)},[e,ae,pe,I,I.getSortedRowModel]),L(()=>{if(!e)return;let v=[];Ae.map(S=>{let E=i.indexOf(S.id);v.push({col:E,desc:S.desc})}),Shiny.setInputValue(`${e}_sort`,v),Shiny.setInputValue(`${e}_column_sort`,v)},[i,e,Ae]),L(()=>{if(!e)return;let v=[];ge.map(S=>{let E=i.indexOf(S.id);v.push({col:E,value:S.value})}),Shiny.setInputValue(`${e}_filter`,v),Shiny.setInputValue(`${e}_column_filter`,v)},[e,ge,i]),L(()=>{if(!e)return;let v=I.getSortedRowModel().rows.map(S=>S.index);Shiny.setInputValue(`${e}_data_view_rows`,v),Shiny.setInputValue(`${e}_data_view_indices`,v)},[e,I,Ae,ge]),L(()=>{if(!e)return;let v=null;if(pe.row!==se._rowEnum.NONE){let S=ae.keys().toList(),E=I.getSortedRowModel().rowsById;v=S.map(F=>F in E?E[F].index:null).filter(F=>F!==null).sort()}Shiny.setInputValue(`${e}_selected_rows`,v)},[e,ae,pe,I]);let Ao=b.useCallback(()=>_.current.querySelectorAll("[tabindex='-1']"),[_.current]),Tn=Po(p.current,Ao,{top:h.current?.clientHeight??0});L(()=>()=>{I.resetSorting(),ae.clear()},[n]);let No=I.getHeaderGroups().length;re(()=>{let v=Ce.length>0;if(v){p.current?.classList.add("scrolling");let S=p.current?.scrollHeight,E=p.current?.clientHeight;S&&E&&S<=E&&(v=!1)}p.current?.classList.toggle("scrolling",v)},[Ce.length,p.current?.scrollHeight,p.current?.clientHeight]);let zo=v=>S=>{(S.key===" "||S.key==="Enter")&&v.toggleSorting(void 0,S.shiftKey)},Go=Ns(A),Pn=`shiny-data-grid ${Lo}`;c&&(Pn+=" html-fill-item");let bt=!1;return b.createElement(b.Fragment,null,b.createElement("div",{className:Pn,ref:p,style:{width:u,height:f,overflow:"auto"}},b.createElement("table",{className:ko+(g?" filtering":""),"aria-rowcount":Ce.length,"aria-multiselectable":Ho,style:{width:u===null||u==="auto"?void 0:"100%"}},b.createElement("thead",{ref:h,style:{backgroundColor:o}},I.getHeaderGroups().map((v,S)=>b.createElement("tr",{key:v.id,"aria-rowindex":S+1},bt&&b.createElement("th",{className:"table-corner"}),v.headers.map(E=>{let F=E.isPlaceholder?void 0:b.createElement("div",{style:{cursor:E.column.getCanSort()?"pointer":void 0,userSelect:E.column.getCanSort()?"none":void 0}},ft(E.column.columnDef.header,E.getContext()),b.createElement(xo,{direction:E.column.getIsSorted()}));return b.createElement("th",{key:E.id,colSpan:E.colSpan,style:{width:E.getSize()},scope:"col",tabIndex:0,onClick:E.column.getToggleSortingHandler(),onKeyDown:zo(E.column),className:E.column.getCanSort()?void 0:"header-html"},F)}))),g&&b.createElement("tr",{className:"filters"},bt&&b.createElement("th",{className:"table-corner"}),I.getFlatHeaders().map(v=>{let S=`filter-${v.id}`;return b.createElement("th",{key:S},b.createElement(yo,{header:v}))}))),b.createElement("tbody",{ref:_,tabIndex:Tn.containerTabIndex,...Tn.containerHandlers},tt>0&&b.createElement("tr",{style:{height:`${tt}px`}}),le.map(v=>{let S=I.getRowModel().rows[v.index];return S&&b.createElement("tr",{key:v.key,"data-index":v.index,"aria-rowindex":v.index+No,"data-key":S.id,ref:Go,"aria-selected":ae.has(S.id),tabIndex:-1,...ae.itemHandlers()},bt&&b.createElement("td",{className:"row-number"},S.index+1),S.getVisibleCells().map(E=>{let F=E.row.index,B=E.column.columnDef.meta.colIndex,[W,Bo]=go(T,F,B),{cellStyle:Uo,cellClassName:Ko}=Io(y,"body",F,B);return b.createElement(uo,{key:E.id,rowId:E.row.id,containerRef:p,cell:E,patchInfo:t,editCellsIsAllowed:z,columns:i,coldefs:G,rowIndex:F,columnIndex:B,getSortedRowModel:I.getSortedRowModel,cellEditInfo:W,cellStyle:Uo,cellClassName:Ko,setData:Rt,setCellEditMapAtLoc:D,selection:ae})}))}),Fe>0&&b.createElement("tr",{style:{height:`${Fe}px`}})))),Oo)};function As(e,n,t){let r=e.rows.findIndex(s=>s.id===n),o=e.rows.findIndex(s=>s.id===t);if(r<0||o<0)return[];r>o&&([r,o]=[o,r]);let i=[];for(let s=r;s<=o;s++)i.push(e.rows[s].id);return i}function Ns(e){let n=X([]),t=Y(r=>{r&&(r.isConnected?e.measureElement(r):n.current.push(r))},[e]);return re(()=>{n.current.length>0&&n.current.splice(0).forEach(e.measureElement)}),t}var Mn=class extends Shiny.OutputBinding{find(n){return $(n).find("shiny-data-frame")}renderValue(n,t){n.renderValue(t)}renderError(n,t){n.classList.add("shiny-output-error"),n.renderError(t)}clearError(n){n.classList.remove("shiny-output-error"),n.clearError()}};Shiny.outputBindings.register(new Mn,"shinyDataFrame");function Do(e){if(!e)return;let n=xn(e,"background-color");if(!n)return n;let t=n.match(/^rgba\(\s*([\d.]+)\s*,\s*([\d.]+)\s*,\s*([\d.]+)\s*,\s*([\d.]+)\s*\)$/);if(n==="transparent"||t&&parseFloat(t[4])===0){let r=xn(e,"background-image");return r&&r!=="none"?void 0:Do(e.parentElement)}return n}var $o=document.createElement("template");$o.innerHTML=``;var Fn=class extends HTMLElement{connectedCallback(){let[t]=[this];t.appendChild($o.content.cloneNode(!0)),this.errorRoot=document.createElement("span"),t.appendChild(this.errorRoot);let r=document.createElement("div");r.classList.add("html-fill-container","html-fill-item"),t.appendChild(r),this.reactRoot=Xr(r);let o=this.querySelector("script.data");if(o){let i=JSON.parse(o.innerText);this.renderValue(i)}}renderValue(t){if(this.clearError(),!t){this.reactRoot.render(null);return}this.reactRoot.render(b.createElement(Jt,null,b.createElement(Hs,{id:this.id,gridInfo:t,bgcolor:Do(this)})))}renderError(t){this.reactRoot.render(null),this.errorRoot.innerText=t.message}clearError(){this.reactRoot.render(null),this.errorRoot.innerText=""}};customElements.define("shiny-data-frame",Fn);$(function(){Shiny.addCustomMessageHandler("shinyDataFrameMessage",function(e){let n=new CustomEvent(e.handler,{detail:e.obj});document.getElementById(e.id)?.dispatchEvent(n)})});export{Fn as ShinyDataFrameOutput}; +}`;function Vo(e,n,t){let[r,o]=H(0),i=b.useCallback(a=>{o(-1),a.target===a.currentTarget&&Rt(e,n(),t)?.focus()},[e,n,t]),s=b.useCallback(a=>{o(0)},[]);return{containerTabIndex:r,containerHandlers:{onFocus:i,onBlur:s}}}function Do(e,n,t,r,o){return oe(()=>{let i=e??!0;if(!i)return null;let s=typeof i=="string"?i:"Viewing rows {start} through {end} of {total}";if(!n||t.length===0||!r)return null;let a=n.scrollTop+r.clientHeight,l=n.scrollTop+n.clientHeight,[u,f]=Ls(a,l,t,(p,m)=>p.start+p.size/2);if(u===null||f===null)return null;let c=t[u],g=t[f];if(c===void 0||g===void 0||c.index===0&&g.index===o-1)return null;let d=ks(s,c.index+1,g.index+1,o);return b.createElement("div",{className:"shiny-data-grid-summary"},d)},[e,n,t,r,o])}function Ls(e,n,t,r){let o=null,i=null;for(let s=0;s=e&&(o=s,i=s);else if(r(a,!1)<=n)i=s;else break}return[o,i]}function ks(e,n,t,r){return e.replace(/\{(start|end|total)\}/g,(o,i)=>i==="start"?n+"":i==="end"?t+"":i==="total"?r+"":o)}var Hs=({id:e,gridInfo:{payload:n,patchInfo:t,selectionModes:r},bgcolor:o})=>{let{columns:i,typeHints:s,data:a,options:l={width:void 0,height:void 0,fill:!1,styles:[]}}=n,{width:u,height:f,fill:c,filters:g,styles:d}=l,p=X(null),m=X(null),_=X(null),h=Io({initStyleInfos:d??[],nrow:a.length,ncol:i.length}),y=h.styleInfoMap,{setStyleInfos:R}=h,V=fo(),T=V.cellEditMap,D=V.setCellEditMapAtLoc,z=l.editable===!0,U=oe(()=>{for(let v of T.values())if(v.isEditing)return!0;return!1},[T]),G=oe(()=>i.map((v,S)=>{let E=s?.[S],F=E?.type==="html",B=F?!1:void 0;return{accessorFn:(W,ve)=>W[S],filterFn:E?.type==="numeric"?"inNumberRange":"includesString",header:v,meta:{colIndex:S,isHtmlColumn:F,typeHint:E},cell:({getValue:W})=>{let ve=W();switch(E?.type){case"numeric":case"date":case"datetime":case"duration":case"categorical":case"html":return ve;case"string":case"boolean":return String(ve);case"unknown":case"object":return typeof ve=="string"?ve:JSON.stringify(ve);default:return ve}},enableSorting:B}}),[i,s]),q=oe(()=>a,[a]),te=He(a),Ee=te[0],bt=te[1],Fe=Eo({getColDefs:()=>G}),Ne=Fe.sorting,et=Fe.sortTableStateOptions,ze=Fe.sortTableOptions,tt=Fe.setSorting,{columnFilters:ge,columnFiltersState:Ge,filtersTableOptions:Be,setColumnFilters:Ue}=yo(g),x={data:Ee,columns:G,state:{...et,...Ge},getCoreRowModel:$r(),...ze,...Be},I=zr(x),A=Xr({count:I.getFilteredRowModel().rows.length,getScrollElement:()=>p.current,estimateSize:()=>31,overscan:15,paddingStart:m.current?.clientHeight??0,isScrollingResetDelay:10});re(()=>{A.scrollToOffset(0)},[n,A]);let K=A.getTotalSize(),le=A.getVirtualItems(),nt=(le.length>0&&le?.[0]?.start||0)-(m.current?.clientHeight??0),Ie=le.length>0?K-(le?.[le.length-1]?.end||0):0,Lo=Do(l.summary,p?.current,le,m.current,A.options.count),Tn=l.style??"grid",ko=Tn==="grid"?"shiny-data-grid-grid":"shiny-data-grid-table",Ho=Tn==="table"?"table table-sm":null,pe=wo(r),zs=!pe.isNone(),Ao=pe.row!==se._rowEnum.NONE,ae=Co({isEditingCell:U,editCellsIsAllowed:z,selectionModes:pe,keyAccessor:v=>v.dataset.key,focusEscape:v=>{setTimeout(()=>{v?.blur(),p.current?.focus()},0)},focusOffset:(v,S=0)=>{let E=I.getSortedRowModel(),F=E.rows.findIndex(W=>W.id===v);if(F<0||(F+=S,F<0||F>=E.rows.length))return null;let B=E.rows[F].id;return A.scrollToIndex(F),setTimeout(()=>{p.current?.querySelector(`[data-key='${B}']`)?.focus()},0),B},between:(v,S)=>As(I.getSortedRowModel(),v,S),onKeyDownEnter:v=>{let S=Array(...v.childNodes.values()).filter(B=>B instanceof HTMLElement&&B.classList.contains("cell-editable"));if(S.length===0)return;let E=Rt(p.current,S);if(!E)return;let F=new MouseEvent("dblclick",{bubbles:!0,cancelable:!0});E.dispatchEvent(F)}});L(()=>{let v=E=>{let F=E.detail.cellSelection;if(F.type==="none"){ae.clear();return}else if(F.type==="row"){ae.setMultiple(F.rows.map(String));return}else console.error("Unhandled cell selection update:",F)};if(!e)return;let S=document.getElementById(e);if(S)return S.addEventListener("updateCellSelection",v),()=>{S.removeEventListener("updateCellSelection",v)}},[e,ae,Ee]),L(()=>{let v=E=>{let F=E.detail.sort,B=[];F.map(W=>{B.push({id:i[W.col],desc:W.desc})}),tt(B)};if(!e)return;let S=document.getElementById(e);if(S)return S.addEventListener("updateColumnSort",v),()=>{S.removeEventListener("updateColumnSort",v)}},[i,e,tt]),L(()=>{let v=E=>{let F=E.detail.filter,B=[];F.map(W=>{B.push({id:i[W.col],value:W.value})}),Ue(B)};if(!e)return;let S=document.getElementById(e);if(S)return S.addEventListener("updateColumnFilter",v),()=>{S.removeEventListener("updateColumnFilter",v)}},[i,e,Ue]),L(()=>{let v=E=>{let F=E.detail.styles;R(F)};if(!e)return;let S=document.getElementById(e);if(S)return S.addEventListener("updateStyles",v),()=>{S.removeEventListener("updateStyles",v)}},[e,R]),L(()=>{if(!e)return;let v=null;if(pe.isNone())v=null;else if(pe.row!==se._rowEnum.NONE){let S=ae.keys().toList(),E=I.getSortedRowModel().rowsById;v={type:"row",rows:S.map(F=>F in E?E[F].index:null).filter(F=>F!==null)}}else console.error("Unhandled row selection mode:",pe);Shiny.setInputValue(`${e}_cell_selection`,v)},[e,ae,pe,I,I.getSortedRowModel]),L(()=>{if(!e)return;let v=[];Ne.map(S=>{let E=i.indexOf(S.id);v.push({col:E,desc:S.desc})}),Shiny.setInputValue(`${e}_sort`,v),Shiny.setInputValue(`${e}_column_sort`,v)},[i,e,Ne]),L(()=>{if(!e)return;let v=[];ge.map(S=>{let E=i.indexOf(S.id);v.push({col:E,value:S.value})}),Shiny.setInputValue(`${e}_filter`,v),Shiny.setInputValue(`${e}_column_filter`,v)},[e,ge,i]),L(()=>{if(!e)return;let v=I.getSortedRowModel().rows.map(S=>S.index);Shiny.setInputValue(`${e}_data_view_rows`,v),Shiny.setInputValue(`${e}_data_view_indices`,v)},[e,I,Ne,ge]),L(()=>{if(!e)return;let v=null;if(pe.row!==se._rowEnum.NONE){let S=ae.keys().toList(),E=I.getSortedRowModel().rowsById;v=S.map(F=>F in E?E[F].index:null).filter(F=>F!==null).sort()}Shiny.setInputValue(`${e}_selected_rows`,v)},[e,ae,pe,I]);let No=b.useCallback(()=>_.current.querySelectorAll("[tabindex='-1']"),[_.current]),Pn=Vo(p.current,No,{top:m.current?.clientHeight??0});L(()=>()=>{I.resetSorting(),ae.clear()},[n]);let zo=I.getHeaderGroups().length;re(()=>{let v=Ee.length>0;if(v){p.current?.classList.add("scrolling");let S=p.current?.scrollHeight,E=p.current?.clientHeight;S&&E&&S<=E&&(v=!1)}p.current?.classList.toggle("scrolling",v)},[Ee.length,p.current?.scrollHeight,p.current?.clientHeight]);let Go=v=>S=>{(S.key===" "||S.key==="Enter")&&v.toggleSorting(void 0,S.shiftKey)},Bo=Ns(A),Vn=`shiny-data-grid ${ko}`;c&&(Vn+=" html-fill-item");let xt=!1;return b.createElement(b.Fragment,null,b.createElement("div",{className:Vn,ref:p,style:{width:u,height:f,overflow:"auto"}},b.createElement("table",{className:Ho+(g?" filtering":""),"aria-rowcount":Ee.length,"aria-multiselectable":Ao,style:{width:u===null||u==="auto"?void 0:"100%"}},b.createElement("thead",{ref:m,style:{backgroundColor:o}},I.getHeaderGroups().map((v,S)=>b.createElement("tr",{key:v.id,"aria-rowindex":S+1},xt&&b.createElement("th",{className:"table-corner"}),v.headers.map(E=>{let F=E.isPlaceholder?void 0:b.createElement("div",{style:{cursor:E.column.getCanSort()?"pointer":void 0,userSelect:E.column.getCanSort()?"none":void 0}},gt(E.column.columnDef.header,E.getContext()),b.createElement(Mo,{direction:E.column.getIsSorted()}));return b.createElement("th",{key:E.id,colSpan:E.colSpan,style:{width:E.getSize()},scope:"col",tabIndex:0,onClick:E.column.getToggleSortingHandler(),onKeyDown:Go(E.column),className:E.column.getCanSort()?void 0:"header-html"},F)}))),g&&b.createElement("tr",{className:"filters"},xt&&b.createElement("th",{className:"table-corner"}),I.getFlatHeaders().map(v=>{let S=`filter-${v.id}`;return b.createElement("th",{key:S},b.createElement(vo,{header:v}))}))),b.createElement("tbody",{ref:_,tabIndex:Pn.containerTabIndex,...Pn.containerHandlers},nt>0&&b.createElement("tr",{style:{height:`${nt}px`}}),le.map(v=>{let S=I.getRowModel().rows[v.index];return S&&b.createElement("tr",{key:v.key,"data-index":v.index,"aria-rowindex":v.index+zo,"data-key":S.id,ref:Bo,"aria-selected":ae.has(S.id),tabIndex:-1,...ae.itemHandlers()},xt&&b.createElement("td",{className:"row-number"},S.index+1),S.getVisibleCells().map(E=>{let F=E.row.index,B=E.column.columnDef.meta.colIndex,[W,ve]=po(T,F,B),{cellStyle:Uo,cellClassName:Ko}=To(y,"body",F,B);return b.createElement(co,{key:E.id,rowId:E.row.id,containerRef:p,cell:E,patchInfo:t,editCellsIsAllowed:z,columns:i,coldefs:G,rowIndex:F,columnIndex:B,getSortedRowModel:I.getSortedRowModel,cellEditInfo:W,cellStyle:Uo,cellClassName:Ko,setData:bt,setCellEditMapAtLoc:D,selection:ae})}))}),Ie>0&&b.createElement("tr",{style:{height:`${Ie}px`}})))),Lo)};function As(e,n,t){let r=e.rows.findIndex(s=>s.id===n),o=e.rows.findIndex(s=>s.id===t);if(r<0||o<0)return[];r>o&&([r,o]=[o,r]);let i=[];for(let s=r;s<=o;s++)i.push(e.rows[s].id);return i}function Ns(e){let n=X([]),t=Y(r=>{r&&(r.isConnected?e.measureElement(r):n.current.push(r))},[e]);return re(()=>{n.current.length>0&&n.current.splice(0).forEach(e.measureElement)}),t}var Fn=class extends Shiny.OutputBinding{find(n){return $(n).find("shiny-data-frame")}renderValue(n,t){n.renderValue(t)}renderError(n,t){n.classList.add("shiny-output-error"),n.renderError(t)}clearError(n){n.classList.remove("shiny-output-error"),n.clearError()}};Shiny.outputBindings.register(new Fn,"shinyDataFrame");function $o(e){if(!e)return;let n=Mn(e,"background-color");if(!n)return n;let t=n.match(/^rgba\(\s*([\d.]+)\s*,\s*([\d.]+)\s*,\s*([\d.]+)\s*,\s*([\d.]+)\s*\)$/);if(n==="transparent"||t&&parseFloat(t[4])===0){let r=Mn(e,"background-image");return r&&r!=="none"?void 0:$o(e.parentElement)}return n}var Oo=document.createElement("template");Oo.innerHTML=``;var In=class extends HTMLElement{connectedCallback(){let[t]=[this];t.appendChild(Oo.content.cloneNode(!0)),this.errorRoot=document.createElement("span"),t.appendChild(this.errorRoot);let r=document.createElement("div");r.classList.add("html-fill-container","html-fill-item"),t.appendChild(r),this.reactRoot=Yr(r);let o=this.querySelector("script.data");if(o){let i=JSON.parse(o.innerText);this.renderValue(i)}}renderValue(t){if(this.clearError(),!t){this.reactRoot.render(null);return}this.reactRoot.render(b.createElement(Qt,null,b.createElement(Hs,{id:this.id,gridInfo:t,bgcolor:$o(this)})))}renderError(t){this.reactRoot.render(null),this.errorRoot.innerText=t.message}clearError(){this.reactRoot.render(null),this.errorRoot.innerText=""}};customElements.define("shiny-data-frame",In);$(function(){Shiny.addCustomMessageHandler("shinyDataFrameMessage",function(e){let n=new CustomEvent(e.handler,{detail:e.obj});document.getElementById(e.id)?.dispatchEvent(n)})});export{In as ShinyDataFrameOutput}; /*! Bundled license information: @tanstack/table-core/build/lib/index.mjs: diff --git a/shiny/www/py-shiny/data-frame/data-frame.js.map b/shiny/www/py-shiny/data-frame/data-frame.js.map index 408365f63..4594d354e 100644 --- a/shiny/www/py-shiny/data-frame/data-frame.js.map +++ b/shiny/www/py-shiny/data-frame/data-frame.js.map @@ -1,7 +1,7 @@ { "version": 3, "sources": ["../../../../js/node_modules/preact/src/constants.js", "../../../../js/node_modules/preact/src/util.js", "../../../../js/node_modules/preact/src/options.js", "../../../../js/node_modules/preact/src/create-element.js", "../../../../js/node_modules/preact/src/component.js", "../../../../js/node_modules/preact/src/diff/props.js", "../../../../js/node_modules/preact/src/create-context.js", "../../../../js/node_modules/preact/src/diff/children.js", "../../../../js/node_modules/preact/src/diff/index.js", "../../../../js/node_modules/preact/src/render.js", "../../../../js/node_modules/preact/src/clone-element.js", "../../../../js/node_modules/preact/src/diff/catch-error.js", "../../../../js/node_modules/preact/hooks/src/index.js", "../../../../js/node_modules/preact/compat/src/util.js", "../../../../js/node_modules/preact/compat/src/PureComponent.js", "../../../../js/node_modules/preact/compat/src/memo.js", "../../../../js/node_modules/preact/compat/src/forwardRef.js", "../../../../js/node_modules/preact/compat/src/Children.js", "../../../../js/node_modules/preact/compat/src/suspense.js", "../../../../js/node_modules/preact/compat/src/suspense-list.js", "../../../../js/node_modules/preact/src/constants.js", "../../../../js/node_modules/preact/compat/src/portals.js", "../../../../js/node_modules/preact/compat/src/render.js", "../../../../js/node_modules/preact/compat/src/index.js", "../../../../js/node_modules/@tanstack/table-core/src/columnHelper.ts", "../../../../js/node_modules/@tanstack/table-core/src/utils.ts", "../../../../js/node_modules/@tanstack/table-core/src/core/cell.ts", "../../../../js/node_modules/@tanstack/table-core/src/core/column.ts", "../../../../js/node_modules/@tanstack/table-core/src/core/headers.ts", "../../../../js/node_modules/@tanstack/table-core/src/core/row.ts", "../../../../js/node_modules/@tanstack/table-core/src/features/ColumnFaceting.ts", "../../../../js/node_modules/@tanstack/table-core/src/filterFns.ts", "../../../../js/node_modules/@tanstack/table-core/src/features/ColumnFiltering.ts", "../../../../js/node_modules/@tanstack/table-core/src/aggregationFns.ts", "../../../../js/node_modules/@tanstack/table-core/src/features/ColumnGrouping.ts", "../../../../js/node_modules/@tanstack/table-core/src/features/ColumnOrdering.ts", "../../../../js/node_modules/@tanstack/table-core/src/features/ColumnPinning.ts", "../../../../js/node_modules/@tanstack/table-core/src/features/ColumnSizing.ts", "../../../../js/node_modules/@tanstack/table-core/src/features/ColumnVisibility.ts", "../../../../js/node_modules/@tanstack/table-core/src/features/GlobalFaceting.ts", "../../../../js/node_modules/@tanstack/table-core/src/features/GlobalFiltering.ts", "../../../../js/node_modules/@tanstack/table-core/src/features/RowExpanding.ts", "../../../../js/node_modules/@tanstack/table-core/src/features/RowPagination.ts", "../../../../js/node_modules/@tanstack/table-core/src/features/RowPinning.ts", "../../../../js/node_modules/@tanstack/table-core/src/features/RowSelection.ts", "../../../../js/node_modules/@tanstack/table-core/src/sortingFns.ts", "../../../../js/node_modules/@tanstack/table-core/src/features/RowSorting.ts", "../../../../js/node_modules/@tanstack/table-core/src/core/table.ts", "../../../../js/node_modules/@tanstack/table-core/src/utils/getCoreRowModel.ts", "../../../../js/node_modules/@tanstack/table-core/src/utils/getExpandedRowModel.ts", "../../../../js/node_modules/@tanstack/table-core/src/utils/getFacetedMinMaxValues.ts", "../../../../js/node_modules/@tanstack/table-core/src/utils/filterRowsUtils.ts", "../../../../js/node_modules/@tanstack/table-core/src/utils/getFacetedRowModel.ts", "../../../../js/node_modules/@tanstack/table-core/src/utils/getFacetedUniqueValues.ts", "../../../../js/node_modules/@tanstack/table-core/src/utils/getFilteredRowModel.ts", "../../../../js/node_modules/@tanstack/table-core/src/utils/getGroupedRowModel.ts", "../../../../js/node_modules/@tanstack/table-core/src/utils/getPaginationRowModel.ts", "../../../../js/node_modules/@tanstack/table-core/src/utils/getSortedRowModel.ts", "../../../../js/node_modules/@tanstack/react-table/src/index.tsx", "../../../../js/node_modules/@tanstack/virtual-core/src/utils.ts", "../../../../js/node_modules/@tanstack/virtual-core/src/index.ts", "../../../../js/node_modules/@tanstack/react-virtual/src/index.tsx", "../../../../js/node_modules/preact/compat/client.mjs", "../../../../js/node_modules/immer/src/utils/env.ts", "../../../../js/node_modules/immer/src/utils/errors.ts", "../../../../js/node_modules/immer/src/utils/common.ts", "../../../../js/node_modules/immer/src/utils/plugins.ts", "../../../../js/node_modules/immer/src/core/scope.ts", "../../../../js/node_modules/immer/src/core/finalize.ts", "../../../../js/node_modules/immer/src/core/proxy.ts", "../../../../js/node_modules/immer/src/core/immerClass.ts", "../../../../js/node_modules/immer/src/core/current.ts", "../../../../js/node_modules/immer/src/plugins/patches.ts", "../../../../js/node_modules/immer/src/plugins/mapset.ts", "../../../../js/node_modules/immer/src/immer.ts", "../../../../js/node_modules/use-immer/src/index.ts", "../../../../js/data-frame/request.ts", "../../../../js/data-frame/data-update.tsx", "../../../../js/data-frame/cell.tsx", "../../../../js/data-frame/cell-edit-map.tsx", "../../../../js/data-frame/dom-utils.tsx", "../../../../js/data-frame/filter-numeric.tsx", "../../../../js/data-frame/filter.tsx", "../../../../js/data-frame/immutable-set.tsx", "../../../../js/data-frame/selection.tsx", "../../../../js/data-frame/sort.ts", "../../../../js/data-frame/sort-arrows.tsx", "../../../../js/data-frame/style-info.ts", "../../../../js/data-frame/styles.scss", "../../../../js/data-frame/tabindex-group.ts", "../../../../js/data-frame/table-summary.tsx", "../../../../js/data-frame/index.tsx"], - "sourcesContent": ["/** Normal hydration that attaches to a DOM tree but does not diff it. */\nexport const MODE_HYDRATE = 1 << 5;\n/** Signifies this VNode suspended on the previous render */\nexport const MODE_SUSPENDED = 1 << 7;\n/** Indicates that this node needs to be inserted while patching children */\nexport const INSERT_VNODE = 1 << 16;\n/** Indicates a VNode has been matched with another VNode in the diff */\nexport const MATCHED = 1 << 17;\n\n/** Reset all mode flags */\nexport const RESET_MODE = ~(MODE_HYDRATE | MODE_SUSPENDED);\n\nexport const EMPTY_OBJ = /** @type {any} */ ({});\nexport const EMPTY_ARR = [];\nexport const IS_NON_DIMENSIONAL =\n\t/acit|ex(?:s|g|n|p|$)|rph|grid|ows|mnc|ntw|ine[ch]|zoo|^ord|itera/i;\n", "import { EMPTY_ARR } from './constants';\n\nexport const isArray = Array.isArray;\n\n/**\n * Assign properties from `props` to `obj`\n * @template O, P The obj and props types\n * @param {O} obj The object to copy properties to\n * @param {P} props The object to copy properties from\n * @returns {O & P}\n */\nexport function assign(obj, props) {\n\t// @ts-expect-error We change the type of `obj` to be `O & P`\n\tfor (let i in props) obj[i] = props[i];\n\treturn /** @type {O & P} */ (obj);\n}\n\n/**\n * Remove a child node from its parent if attached. This is a workaround for\n * IE11 which doesn't support `Element.prototype.remove()`. Using this function\n * is smaller than including a dedicated polyfill.\n * @param {preact.ContainerNode} node The node to remove\n */\nexport function removeNode(node) {\n\tlet parentNode = node.parentNode;\n\tif (parentNode) parentNode.removeChild(node);\n}\n\nexport const slice = EMPTY_ARR.slice;\n", "import { _catchError } from './diff/catch-error';\n\n/**\n * The `option` object can potentially contain callback functions\n * that are called during various stages of our renderer. This is the\n * foundation on which all our addons like `preact/debug`, `preact/compat`,\n * and `preact/hooks` are based on. See the `Options` type in `internal.d.ts`\n * for a full list of available option hooks (most editors/IDEs allow you to\n * ctrl+click or cmd+click on mac the type definition below).\n * @type {Options}\n */\nconst options = {\n\t_catchError\n};\n\nexport default options;\n", "import { slice } from './util';\nimport options from './options';\n\nlet vnodeId = 0;\n\n/**\n * Create an virtual node (used for JSX)\n * @param {VNode[\"type\"]} type The node name or Component constructor for this\n * virtual node\n * @param {object | null | undefined} [props] The properties of the virtual node\n * @param {Array} [children] The children of the\n * virtual node\n * @returns {VNode}\n */\nexport function createElement(type, props, children) {\n\tlet normalizedProps = {},\n\t\tkey,\n\t\tref,\n\t\ti;\n\tfor (i in props) {\n\t\tif (i == 'key') key = props[i];\n\t\telse if (i == 'ref') ref = props[i];\n\t\telse normalizedProps[i] = props[i];\n\t}\n\n\tif (arguments.length > 2) {\n\t\tnormalizedProps.children =\n\t\t\targuments.length > 3 ? slice.call(arguments, 2) : children;\n\t}\n\n\t// If a Component VNode, check for and apply defaultProps\n\t// Note: type may be undefined in development, must never error here.\n\tif (typeof type == 'function' && type.defaultProps != null) {\n\t\tfor (i in type.defaultProps) {\n\t\t\tif (normalizedProps[i] === undefined) {\n\t\t\t\tnormalizedProps[i] = type.defaultProps[i];\n\t\t\t}\n\t\t}\n\t}\n\n\treturn createVNode(type, normalizedProps, key, ref, null);\n}\n\n/**\n * Create a VNode (used internally by Preact)\n * @param {VNode[\"type\"]} type The node name or Component\n * Constructor for this virtual node\n * @param {object | string | number | null} props The properties of this virtual node.\n * If this virtual node represents a text node, this is the text of the node (string or number).\n * @param {string | number | null} key The key for this virtual node, used when\n * diffing it against its children\n * @param {VNode[\"ref\"]} ref The ref property that will\n * receive a reference to its created child\n * @returns {VNode}\n */\nexport function createVNode(type, props, key, ref, original) {\n\t// V8 seems to be better at detecting type shapes if the object is allocated from the same call site\n\t// Do not inline into createElement and coerceToVNode!\n\t/** @type {VNode} */\n\tconst vnode = {\n\t\ttype,\n\t\tprops,\n\t\tkey,\n\t\tref,\n\t\t_children: null,\n\t\t_parent: null,\n\t\t_depth: 0,\n\t\t_dom: null,\n\t\t// _nextDom must be initialized to undefined b/c it will eventually\n\t\t// be set to dom.nextSibling which can return `null` and it is important\n\t\t// to be able to distinguish between an uninitialized _nextDom and\n\t\t// a _nextDom that has been set to `null`\n\t\t_nextDom: undefined,\n\t\t_component: null,\n\t\tconstructor: undefined,\n\t\t_original: original == null ? ++vnodeId : original,\n\t\t_index: -1,\n\t\t_flags: 0\n\t};\n\n\t// Only invoke the vnode hook if this was *not* a direct copy:\n\tif (original == null && options.vnode != null) options.vnode(vnode);\n\n\treturn vnode;\n}\n\nexport function createRef() {\n\treturn { current: null };\n}\n\nexport function Fragment(props) {\n\treturn props.children;\n}\n\n/**\n * Check if a the argument is a valid Preact VNode.\n * @param {*} vnode\n * @returns {vnode is VNode}\n */\nexport const isValidElement = vnode =>\n\tvnode != null && vnode.constructor == undefined;\n", "import { assign } from './util';\nimport { diff, commitRoot } from './diff/index';\nimport options from './options';\nimport { Fragment } from './create-element';\nimport { MODE_HYDRATE } from './constants';\n\n/**\n * Base Component class. Provides `setState()` and `forceUpdate()`, which\n * trigger rendering\n * @param {object} props The initial component props\n * @param {object} context The initial context from parent components'\n * getChildContext\n */\nexport function BaseComponent(props, context) {\n\tthis.props = props;\n\tthis.context = context;\n}\n\n/**\n * Update component state and schedule a re-render.\n * @this {Component}\n * @param {object | ((s: object, p: object) => object)} update A hash of state\n * properties to update with new values or a function that given the current\n * state and props returns a new partial state\n * @param {() => void} [callback] A function to be called once component state is\n * updated\n */\nBaseComponent.prototype.setState = function (update, callback) {\n\t// only clone state when copying to nextState the first time.\n\tlet s;\n\tif (this._nextState != null && this._nextState !== this.state) {\n\t\ts = this._nextState;\n\t} else {\n\t\ts = this._nextState = assign({}, this.state);\n\t}\n\n\tif (typeof update == 'function') {\n\t\t// Some libraries like `immer` mark the current state as readonly,\n\t\t// preventing us from mutating it, so we need to clone it. See #2716\n\t\tupdate = update(assign({}, s), this.props);\n\t}\n\n\tif (update) {\n\t\tassign(s, update);\n\t}\n\n\t// Skip update if updater function returned null\n\tif (update == null) return;\n\n\tif (this._vnode) {\n\t\tif (callback) {\n\t\t\tthis._stateCallbacks.push(callback);\n\t\t}\n\t\tenqueueRender(this);\n\t}\n};\n\n/**\n * Immediately perform a synchronous re-render of the component\n * @this {Component}\n * @param {() => void} [callback] A function to be called after component is\n * re-rendered\n */\nBaseComponent.prototype.forceUpdate = function (callback) {\n\tif (this._vnode) {\n\t\t// Set render mode so that we can differentiate where the render request\n\t\t// is coming from. We need this because forceUpdate should never call\n\t\t// shouldComponentUpdate\n\t\tthis._force = true;\n\t\tif (callback) this._renderCallbacks.push(callback);\n\t\tenqueueRender(this);\n\t}\n};\n\n/**\n * Accepts `props` and `state`, and returns a new Virtual DOM tree to build.\n * Virtual DOM is generally constructed via [JSX](http://jasonformat.com/wtf-is-jsx).\n * @param {object} props Props (eg: JSX attributes) received from parent\n * element/component\n * @param {object} state The component's current state\n * @param {object} context Context object, as returned by the nearest\n * ancestor's `getChildContext()`\n * @returns {ComponentChildren | void}\n */\nBaseComponent.prototype.render = Fragment;\n\n/**\n * @param {VNode} vnode\n * @param {number | null} [childIndex]\n */\nexport function getDomSibling(vnode, childIndex) {\n\tif (childIndex == null) {\n\t\t// Use childIndex==null as a signal to resume the search from the vnode's sibling\n\t\treturn vnode._parent\n\t\t\t? getDomSibling(vnode._parent, vnode._index + 1)\n\t\t\t: null;\n\t}\n\n\tlet sibling;\n\tfor (; childIndex < vnode._children.length; childIndex++) {\n\t\tsibling = vnode._children[childIndex];\n\n\t\tif (sibling != null && sibling._dom != null) {\n\t\t\t// Since updateParentDomPointers keeps _dom pointer correct,\n\t\t\t// we can rely on _dom to tell us if this subtree contains a\n\t\t\t// rendered DOM node, and what the first rendered DOM node is\n\t\t\treturn sibling._dom;\n\t\t}\n\t}\n\n\t// If we get here, we have not found a DOM node in this vnode's children.\n\t// We must resume from this vnode's sibling (in it's parent _children array)\n\t// Only climb up and search the parent if we aren't searching through a DOM\n\t// VNode (meaning we reached the DOM parent of the original vnode that began\n\t// the search)\n\treturn typeof vnode.type == 'function' ? getDomSibling(vnode) : null;\n}\n\n/**\n * Trigger in-place re-rendering of a component.\n * @param {Component} component The component to rerender\n */\nfunction renderComponent(component) {\n\tlet oldVNode = component._vnode,\n\t\toldDom = oldVNode._dom,\n\t\tcommitQueue = [],\n\t\trefQueue = [];\n\n\tif (component._parentDom) {\n\t\tconst newVNode = assign({}, oldVNode);\n\t\tnewVNode._original = oldVNode._original + 1;\n\t\tif (options.vnode) options.vnode(newVNode);\n\n\t\tdiff(\n\t\t\tcomponent._parentDom,\n\t\t\tnewVNode,\n\t\t\toldVNode,\n\t\t\tcomponent._globalContext,\n\t\t\tcomponent._parentDom.namespaceURI,\n\t\t\toldVNode._flags & MODE_HYDRATE ? [oldDom] : null,\n\t\t\tcommitQueue,\n\t\t\toldDom == null ? getDomSibling(oldVNode) : oldDom,\n\t\t\t!!(oldVNode._flags & MODE_HYDRATE),\n\t\t\trefQueue\n\t\t);\n\n\t\tnewVNode._original = oldVNode._original;\n\t\tnewVNode._parent._children[newVNode._index] = newVNode;\n\t\tcommitRoot(commitQueue, newVNode, refQueue);\n\n\t\tif (newVNode._dom != oldDom) {\n\t\t\tupdateParentDomPointers(newVNode);\n\t\t}\n\t}\n}\n\n/**\n * @param {VNode} vnode\n */\nfunction updateParentDomPointers(vnode) {\n\tif ((vnode = vnode._parent) != null && vnode._component != null) {\n\t\tvnode._dom = vnode._component.base = null;\n\t\tfor (let i = 0; i < vnode._children.length; i++) {\n\t\t\tlet child = vnode._children[i];\n\t\t\tif (child != null && child._dom != null) {\n\t\t\t\tvnode._dom = vnode._component.base = child._dom;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\treturn updateParentDomPointers(vnode);\n\t}\n}\n\n/**\n * The render queue\n * @type {Array}\n */\nlet rerenderQueue = [];\n\n/*\n * The value of `Component.debounce` must asynchronously invoke the passed in callback. It is\n * important that contributors to Preact can consistently reason about what calls to `setState`, etc.\n * do, and when their effects will be applied. See the links below for some further reading on designing\n * asynchronous APIs.\n * * [Designing APIs for Asynchrony](https://blog.izs.me/2013/08/designing-apis-for-asynchrony)\n * * [Callbacks synchronous and asynchronous](https://blog.ometer.com/2011/07/24/callbacks-synchronous-and-asynchronous/)\n */\n\nlet prevDebounce;\n\nconst defer =\n\ttypeof Promise == 'function'\n\t\t? Promise.prototype.then.bind(Promise.resolve())\n\t\t: setTimeout;\n\n/**\n * Enqueue a rerender of a component\n * @param {Component} c The component to rerender\n */\nexport function enqueueRender(c) {\n\tif (\n\t\t(!c._dirty &&\n\t\t\t(c._dirty = true) &&\n\t\t\trerenderQueue.push(c) &&\n\t\t\t!process._rerenderCount++) ||\n\t\tprevDebounce !== options.debounceRendering\n\t) {\n\t\tprevDebounce = options.debounceRendering;\n\t\t(prevDebounce || defer)(process);\n\t}\n}\n\n/**\n * @param {Component} a\n * @param {Component} b\n */\nconst depthSort = (a, b) => a._vnode._depth - b._vnode._depth;\n\n/** Flush the render queue by rerendering all queued components */\nfunction process() {\n\tlet c;\n\trerenderQueue.sort(depthSort);\n\t// Don't update `renderCount` yet. Keep its value non-zero to prevent unnecessary\n\t// process() calls from getting scheduled while `queue` is still being consumed.\n\twhile ((c = rerenderQueue.shift())) {\n\t\tif (c._dirty) {\n\t\t\tlet renderQueueLength = rerenderQueue.length;\n\t\t\trenderComponent(c);\n\t\t\tif (rerenderQueue.length > renderQueueLength) {\n\t\t\t\t// When i.e. rerendering a provider additional new items can be injected, we want to\n\t\t\t\t// keep the order from top to bottom with those new items so we can handle them in a\n\t\t\t\t// single pass\n\t\t\t\trerenderQueue.sort(depthSort);\n\t\t\t}\n\t\t}\n\t}\n\tprocess._rerenderCount = 0;\n}\n\nprocess._rerenderCount = 0;\n", "import { IS_NON_DIMENSIONAL } from '../constants';\nimport options from '../options';\n\nfunction setStyle(style, key, value) {\n\tif (key[0] === '-') {\n\t\tstyle.setProperty(key, value == null ? '' : value);\n\t} else if (value == null) {\n\t\tstyle[key] = '';\n\t} else if (typeof value != 'number' || IS_NON_DIMENSIONAL.test(key)) {\n\t\tstyle[key] = value;\n\t} else {\n\t\tstyle[key] = value + 'px';\n\t}\n}\n\n// A logical clock to solve issues like https://github.com/preactjs/preact/issues/3927.\n// When the DOM performs an event it leaves micro-ticks in between bubbling up which means that\n// an event can trigger on a newly reated DOM-node while the event bubbles up.\n//\n// Originally inspired by Vue\n// (https://github.com/vuejs/core/blob/caeb8a68811a1b0f79/packages/runtime-dom/src/modules/events.ts#L90-L101),\n// but modified to use a logical clock instead of Date.now() in case event handlers get attached\n// and events get dispatched during the same millisecond.\n//\n// The clock is incremented after each new event dispatch. This allows 1 000 000 new events\n// per second for over 280 years before the value reaches Number.MAX_SAFE_INTEGER (2**53 - 1).\nlet eventClock = 0;\n\n/**\n * Set a property value on a DOM node\n * @param {PreactElement} dom The DOM node to modify\n * @param {string} name The name of the property to set\n * @param {*} value The value to set the property to\n * @param {*} oldValue The old value the property had\n * @param {string} namespace Whether or not this DOM node is an SVG node or not\n */\nexport function setProperty(dom, name, value, oldValue, namespace) {\n\tlet useCapture;\n\n\to: if (name === 'style') {\n\t\tif (typeof value == 'string') {\n\t\t\tdom.style.cssText = value;\n\t\t} else {\n\t\t\tif (typeof oldValue == 'string') {\n\t\t\t\tdom.style.cssText = oldValue = '';\n\t\t\t}\n\n\t\t\tif (oldValue) {\n\t\t\t\tfor (name in oldValue) {\n\t\t\t\t\tif (!(value && name in value)) {\n\t\t\t\t\t\tsetStyle(dom.style, name, '');\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (value) {\n\t\t\t\tfor (name in value) {\n\t\t\t\t\tif (!oldValue || value[name] !== oldValue[name]) {\n\t\t\t\t\t\tsetStyle(dom.style, name, value[name]);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t// Benchmark for comparison: https://esbench.com/bench/574c954bdb965b9a00965ac6\n\telse if (name[0] === 'o' && name[1] === 'n') {\n\t\tuseCapture =\n\t\t\tname !== (name = name.replace(/(PointerCapture)$|Capture$/i, '$1'));\n\n\t\t// Infer correct casing for DOM built-in events:\n\t\tif (\n\t\t\tname.toLowerCase() in dom ||\n\t\t\tname === 'onFocusOut' ||\n\t\t\tname === 'onFocusIn'\n\t\t)\n\t\t\tname = name.toLowerCase().slice(2);\n\t\telse name = name.slice(2);\n\n\t\tif (!dom._listeners) dom._listeners = {};\n\t\tdom._listeners[name + useCapture] = value;\n\n\t\tif (value) {\n\t\t\tif (!oldValue) {\n\t\t\t\tvalue._attached = eventClock;\n\t\t\t\tdom.addEventListener(\n\t\t\t\t\tname,\n\t\t\t\t\tuseCapture ? eventProxyCapture : eventProxy,\n\t\t\t\t\tuseCapture\n\t\t\t\t);\n\t\t\t} else {\n\t\t\t\tvalue._attached = oldValue._attached;\n\t\t\t}\n\t\t} else {\n\t\t\tdom.removeEventListener(\n\t\t\t\tname,\n\t\t\t\tuseCapture ? eventProxyCapture : eventProxy,\n\t\t\t\tuseCapture\n\t\t\t);\n\t\t}\n\t} else {\n\t\tif (namespace == 'http://www.w3.org/2000/svg') {\n\t\t\t// Normalize incorrect prop usage for SVG:\n\t\t\t// - xlink:href / xlinkHref --> href (xlink:href was removed from SVG and isn't needed)\n\t\t\t// - className --> class\n\t\t\tname = name.replace(/xlink(H|:h)/, 'h').replace(/sName$/, 's');\n\t\t} else if (\n\t\t\tname != 'width' &&\n\t\t\tname != 'height' &&\n\t\t\tname != 'href' &&\n\t\t\tname != 'list' &&\n\t\t\tname != 'form' &&\n\t\t\t// Default value in browsers is `-1` and an empty string is\n\t\t\t// cast to `0` instead\n\t\t\tname != 'tabIndex' &&\n\t\t\tname != 'download' &&\n\t\t\tname != 'rowSpan' &&\n\t\t\tname != 'colSpan' &&\n\t\t\tname != 'role' &&\n\t\t\tname != 'popover' &&\n\t\t\tname in dom\n\t\t) {\n\t\t\ttry {\n\t\t\t\tdom[name] = value == null ? '' : value;\n\t\t\t\t// labelled break is 1b smaller here than a return statement (sorry)\n\t\t\t\tbreak o;\n\t\t\t} catch (e) {}\n\t\t}\n\n\t\t// aria- and data- attributes have no boolean representation.\n\t\t// A `false` value is different from the attribute not being\n\t\t// present, so we can't remove it. For non-boolean aria\n\t\t// attributes we could treat false as a removal, but the\n\t\t// amount of exceptions would cost too many bytes. On top of\n\t\t// that other frameworks generally stringify `false`.\n\n\t\tif (typeof value == 'function') {\n\t\t\t// never serialize functions as attribute values\n\t\t} else if (value != null && (value !== false || name[4] === '-')) {\n\t\t\tdom.setAttribute(name, name == 'popover' && value == true ? '' : value);\n\t\t} else {\n\t\t\tdom.removeAttribute(name);\n\t\t}\n\t}\n}\n\n/**\n * Create an event proxy function.\n * @param {boolean} useCapture Is the event handler for the capture phase.\n * @private\n */\nfunction createEventProxy(useCapture) {\n\t/**\n\t * Proxy an event to hooked event handlers\n\t * @param {PreactEvent} e The event object from the browser\n\t * @private\n\t */\n\treturn function (e) {\n\t\tif (this._listeners) {\n\t\t\tconst eventHandler = this._listeners[e.type + useCapture];\n\t\t\tif (e._dispatched == null) {\n\t\t\t\te._dispatched = eventClock++;\n\n\t\t\t\t// When `e._dispatched` is smaller than the time when the targeted event\n\t\t\t\t// handler was attached we know we have bubbled up to an element that was added\n\t\t\t\t// during patching the DOM.\n\t\t\t} else if (e._dispatched < eventHandler._attached) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\treturn eventHandler(options.event ? options.event(e) : e);\n\t\t}\n\t};\n}\n\nconst eventProxy = createEventProxy(false);\nconst eventProxyCapture = createEventProxy(true);\n", "import { enqueueRender } from './component';\n\nexport let i = 0;\n\nexport function createContext(defaultValue, contextId) {\n\tcontextId = '__cC' + i++;\n\n\tconst context = {\n\t\t_id: contextId,\n\t\t_defaultValue: defaultValue,\n\t\t/** @type {FunctionComponent} */\n\t\tConsumer(props, contextValue) {\n\t\t\t// return props.children(\n\t\t\t// \tcontext[contextId] ? context[contextId].props.value : defaultValue\n\t\t\t// );\n\t\t\treturn props.children(contextValue);\n\t\t},\n\t\t/** @type {FunctionComponent} */\n\t\tProvider(props) {\n\t\t\tif (!this.getChildContext) {\n\t\t\t\t/** @type {Component[] | null} */\n\t\t\t\tlet subs = [];\n\t\t\t\tlet ctx = {};\n\t\t\t\tctx[contextId] = this;\n\n\t\t\t\tthis.getChildContext = () => ctx;\n\n\t\t\t\tthis.componentWillUnmount = () => {\n\t\t\t\t\tsubs = null;\n\t\t\t\t};\n\n\t\t\t\tthis.shouldComponentUpdate = function (_props) {\n\t\t\t\t\tif (this.props.value !== _props.value) {\n\t\t\t\t\t\tsubs.some(c => {\n\t\t\t\t\t\t\tc._force = true;\n\t\t\t\t\t\t\tenqueueRender(c);\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t};\n\n\t\t\t\tthis.sub = c => {\n\t\t\t\t\tsubs.push(c);\n\t\t\t\t\tlet old = c.componentWillUnmount;\n\t\t\t\t\tc.componentWillUnmount = () => {\n\t\t\t\t\t\tif (subs) {\n\t\t\t\t\t\t\tsubs.splice(subs.indexOf(c), 1);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (old) old.call(c);\n\t\t\t\t\t};\n\t\t\t\t};\n\t\t\t}\n\n\t\t\treturn props.children;\n\t\t}\n\t};\n\n\t// Devtools needs access to the context object when it\n\t// encounters a Provider. This is necessary to support\n\t// setting `displayName` on the context object instead\n\t// of on the component itself. See:\n\t// https://reactjs.org/docs/context.html#contextdisplayname\n\n\treturn (context.Provider._contextRef = context.Consumer.contextType =\n\t\tcontext);\n}\n", "import { diff, unmount, applyRef } from './index';\nimport { createVNode, Fragment } from '../create-element';\nimport { EMPTY_OBJ, EMPTY_ARR, INSERT_VNODE, MATCHED } from '../constants';\nimport { isArray } from '../util';\nimport { getDomSibling } from '../component';\n\n/**\n * Diff the children of a virtual node\n * @param {PreactElement} parentDom The DOM element whose children are being\n * diffed\n * @param {ComponentChildren[]} renderResult\n * @param {VNode} newParentVNode The new virtual node whose children should be\n * diff'ed against oldParentVNode\n * @param {VNode} oldParentVNode The old virtual node whose children should be\n * diff'ed against newParentVNode\n * @param {object} globalContext The current context object - modified by\n * getChildContext\n * @param {string} namespace Current namespace of the DOM node (HTML, SVG, or MathML)\n * @param {Array} excessDomChildren\n * @param {Array} commitQueue List of components which have callbacks\n * to invoke in commitRoot\n * @param {PreactElement} oldDom The current attached DOM element any new dom\n * elements should be placed around. Likely `null` on first render (except when\n * hydrating). Can be a sibling DOM element when diffing Fragments that have\n * siblings. In most cases, it starts out as `oldChildren[0]._dom`.\n * @param {boolean} isHydrating Whether or not we are in hydration\n * @param {any[]} refQueue an array of elements needed to invoke refs\n */\nexport function diffChildren(\n\tparentDom,\n\trenderResult,\n\tnewParentVNode,\n\toldParentVNode,\n\tglobalContext,\n\tnamespace,\n\texcessDomChildren,\n\tcommitQueue,\n\toldDom,\n\tisHydrating,\n\trefQueue\n) {\n\tlet i,\n\t\t/** @type {VNode} */\n\t\toldVNode,\n\t\t/** @type {VNode} */\n\t\tchildVNode,\n\t\t/** @type {PreactElement} */\n\t\tnewDom,\n\t\t/** @type {PreactElement} */\n\t\tfirstChildDom;\n\n\t// This is a compression of oldParentVNode!=null && oldParentVNode != EMPTY_OBJ && oldParentVNode._children || EMPTY_ARR\n\t// as EMPTY_OBJ._children should be `undefined`.\n\t/** @type {VNode[]} */\n\tlet oldChildren = (oldParentVNode && oldParentVNode._children) || EMPTY_ARR;\n\n\tlet newChildrenLength = renderResult.length;\n\n\tnewParentVNode._nextDom = oldDom;\n\tconstructNewChildrenArray(newParentVNode, renderResult, oldChildren);\n\toldDom = newParentVNode._nextDom;\n\n\tfor (i = 0; i < newChildrenLength; i++) {\n\t\tchildVNode = newParentVNode._children[i];\n\t\tif (\n\t\t\tchildVNode == null ||\n\t\t\ttypeof childVNode == 'boolean' ||\n\t\t\ttypeof childVNode == 'function'\n\t\t) {\n\t\t\tcontinue;\n\t\t}\n\n\t\t// At this point, constructNewChildrenArray has assigned _index to be the\n\t\t// matchingIndex for this VNode's oldVNode (or -1 if there is no oldVNode).\n\t\tif (childVNode._index === -1) {\n\t\t\toldVNode = EMPTY_OBJ;\n\t\t} else {\n\t\t\toldVNode = oldChildren[childVNode._index] || EMPTY_OBJ;\n\t\t}\n\n\t\t// Update childVNode._index to its final index\n\t\tchildVNode._index = i;\n\n\t\t// Morph the old element into the new one, but don't append it to the dom yet\n\t\tdiff(\n\t\t\tparentDom,\n\t\t\tchildVNode,\n\t\t\toldVNode,\n\t\t\tglobalContext,\n\t\t\tnamespace,\n\t\t\texcessDomChildren,\n\t\t\tcommitQueue,\n\t\t\toldDom,\n\t\t\tisHydrating,\n\t\t\trefQueue\n\t\t);\n\n\t\t// Adjust DOM nodes\n\t\tnewDom = childVNode._dom;\n\t\tif (childVNode.ref && oldVNode.ref != childVNode.ref) {\n\t\t\tif (oldVNode.ref) {\n\t\t\t\tapplyRef(oldVNode.ref, null, childVNode);\n\t\t\t}\n\t\t\trefQueue.push(\n\t\t\t\tchildVNode.ref,\n\t\t\t\tchildVNode._component || newDom,\n\t\t\t\tchildVNode\n\t\t\t);\n\t\t}\n\n\t\tif (firstChildDom == null && newDom != null) {\n\t\t\tfirstChildDom = newDom;\n\t\t}\n\n\t\tif (\n\t\t\tchildVNode._flags & INSERT_VNODE ||\n\t\t\toldVNode._children === childVNode._children\n\t\t) {\n\t\t\tif (\n\t\t\t\toldDom &&\n\t\t\t\ttypeof childVNode.type == 'string' &&\n\t\t\t\t// @ts-expect-error olDom should be present on a DOM node\n\t\t\t\t!parentDom.contains(oldDom)\n\t\t\t) {\n\t\t\t\toldDom = getDomSibling(oldVNode);\n\t\t\t}\n\t\t\toldDom = insert(childVNode, oldDom, parentDom);\n\t\t} else if (\n\t\t\ttypeof childVNode.type == 'function' &&\n\t\t\tchildVNode._nextDom !== undefined\n\t\t) {\n\t\t\t// Since Fragments or components that return Fragment like VNodes can\n\t\t\t// contain multiple DOM nodes as the same level, continue the diff from\n\t\t\t// the sibling of last DOM child of this child VNode\n\t\t\toldDom = childVNode._nextDom;\n\t\t} else if (newDom) {\n\t\t\toldDom = newDom.nextSibling;\n\t\t}\n\n\t\t// Eagerly cleanup _nextDom. We don't need to persist the value because it\n\t\t// is only used by `diffChildren` to determine where to resume the diff\n\t\t// after diffing Components and Fragments. Once we store it the nextDOM\n\t\t// local var, we can clean up the property. Also prevents us hanging on to\n\t\t// DOM nodes that may have been unmounted.\n\t\tchildVNode._nextDom = undefined;\n\n\t\t// Unset diffing flags\n\t\tchildVNode._flags &= ~(INSERT_VNODE | MATCHED);\n\t}\n\n\t// TODO: With new child diffing algo, consider alt ways to diff Fragments.\n\t// Such as dropping oldDom and moving fragments in place\n\t//\n\t// Because the newParentVNode is Fragment-like, we need to set it's\n\t// _nextDom property to the nextSibling of its last child DOM node.\n\t//\n\t// `oldDom` contains the correct value here because if the last child\n\t// is a Fragment-like, then oldDom has already been set to that child's _nextDom.\n\t// If the last child is a DOM VNode, then oldDom will be set to that DOM\n\t// node's nextSibling.\n\tnewParentVNode._nextDom = oldDom;\n\tnewParentVNode._dom = firstChildDom;\n}\n\n/**\n * @param {VNode} newParentVNode\n * @param {ComponentChildren[]} renderResult\n * @param {VNode[]} oldChildren\n */\nfunction constructNewChildrenArray(newParentVNode, renderResult, oldChildren) {\n\t/** @type {number} */\n\tlet i;\n\t/** @type {VNode} */\n\tlet childVNode;\n\t/** @type {VNode} */\n\tlet oldVNode;\n\n\tconst newChildrenLength = renderResult.length;\n\tlet oldChildrenLength = oldChildren.length,\n\t\tremainingOldChildren = oldChildrenLength;\n\n\tlet skew = 0;\n\n\tnewParentVNode._children = [];\n\tfor (i = 0; i < newChildrenLength; i++) {\n\t\t// @ts-expect-error We are reusing the childVNode variable to hold both the\n\t\t// pre and post normalized childVNode\n\t\tchildVNode = renderResult[i];\n\n\t\tif (\n\t\t\tchildVNode == null ||\n\t\t\ttypeof childVNode == 'boolean' ||\n\t\t\ttypeof childVNode == 'function'\n\t\t) {\n\t\t\tchildVNode = newParentVNode._children[i] = null;\n\t\t}\n\t\t// If this newVNode is being reused (e.g.
{reuse}{reuse}
) in the same diff,\n\t\t// or we are rendering a component (e.g. setState) copy the oldVNodes so it can have\n\t\t// it's own DOM & etc. pointers\n\t\telse if (\n\t\t\ttypeof childVNode == 'string' ||\n\t\t\ttypeof childVNode == 'number' ||\n\t\t\t// eslint-disable-next-line valid-typeof\n\t\t\ttypeof childVNode == 'bigint' ||\n\t\t\tchildVNode.constructor == String\n\t\t) {\n\t\t\tchildVNode = newParentVNode._children[i] = createVNode(\n\t\t\t\tnull,\n\t\t\t\tchildVNode,\n\t\t\t\tnull,\n\t\t\t\tnull,\n\t\t\t\tnull\n\t\t\t);\n\t\t} else if (isArray(childVNode)) {\n\t\t\tchildVNode = newParentVNode._children[i] = createVNode(\n\t\t\t\tFragment,\n\t\t\t\t{ children: childVNode },\n\t\t\t\tnull,\n\t\t\t\tnull,\n\t\t\t\tnull\n\t\t\t);\n\t\t} else if (childVNode.constructor === undefined && childVNode._depth > 0) {\n\t\t\t// VNode is already in use, clone it. This can happen in the following\n\t\t\t// scenario:\n\t\t\t// const reuse =
\n\t\t\t//
{reuse}{reuse}
\n\t\t\tchildVNode = newParentVNode._children[i] = createVNode(\n\t\t\t\tchildVNode.type,\n\t\t\t\tchildVNode.props,\n\t\t\t\tchildVNode.key,\n\t\t\t\tchildVNode.ref ? childVNode.ref : null,\n\t\t\t\tchildVNode._original\n\t\t\t);\n\t\t} else {\n\t\t\tchildVNode = newParentVNode._children[i] = childVNode;\n\t\t}\n\n\t\tconst skewedIndex = i + skew;\n\n\t\t// Handle unmounting null placeholders, i.e. VNode => null in unkeyed children\n\t\tif (childVNode == null) {\n\t\t\toldVNode = oldChildren[skewedIndex];\n\t\t\tif (\n\t\t\t\toldVNode &&\n\t\t\t\toldVNode.key == null &&\n\t\t\t\toldVNode._dom &&\n\t\t\t\t(oldVNode._flags & MATCHED) === 0\n\t\t\t) {\n\t\t\t\tif (oldVNode._dom == newParentVNode._nextDom) {\n\t\t\t\t\tnewParentVNode._nextDom = getDomSibling(oldVNode);\n\t\t\t\t}\n\n\t\t\t\tunmount(oldVNode, oldVNode, false);\n\n\t\t\t\t// Explicitly nullify this position in oldChildren instead of just\n\t\t\t\t// setting `_match=true` to prevent other routines (e.g.\n\t\t\t\t// `findMatchingIndex` or `getDomSibling`) from thinking VNodes or DOM\n\t\t\t\t// nodes in this position are still available to be used in diffing when\n\t\t\t\t// they have actually already been unmounted. For example, by only\n\t\t\t\t// setting `_match=true` here, the unmounting loop later would attempt\n\t\t\t\t// to unmount this VNode again seeing `_match==true`. Further,\n\t\t\t\t// getDomSibling doesn't know about _match and so would incorrectly\n\t\t\t\t// assume DOM nodes in this subtree are mounted and usable.\n\t\t\t\toldChildren[skewedIndex] = null;\n\t\t\t\tremainingOldChildren--;\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\n\t\tchildVNode._parent = newParentVNode;\n\t\tchildVNode._depth = newParentVNode._depth + 1;\n\n\t\tconst matchingIndex = findMatchingIndex(\n\t\t\tchildVNode,\n\t\t\toldChildren,\n\t\t\tskewedIndex,\n\t\t\tremainingOldChildren\n\t\t);\n\n\t\t// Temporarily store the matchingIndex on the _index property so we can pull\n\t\t// out the oldVNode in diffChildren. We'll override this to the VNode's\n\t\t// final index after using this property to get the oldVNode\n\t\tchildVNode._index = matchingIndex;\n\n\t\toldVNode = null;\n\t\tif (matchingIndex !== -1) {\n\t\t\toldVNode = oldChildren[matchingIndex];\n\t\t\tremainingOldChildren--;\n\t\t\tif (oldVNode) {\n\t\t\t\toldVNode._flags |= MATCHED;\n\t\t\t}\n\t\t}\n\n\t\t// Here, we define isMounting for the purposes of the skew diffing\n\t\t// algorithm. Nodes that are unsuspending are considered mounting and we detect\n\t\t// this by checking if oldVNode._original === null\n\t\tconst isMounting = oldVNode == null || oldVNode._original === null;\n\n\t\tif (isMounting) {\n\t\t\tif (matchingIndex == -1) {\n\t\t\t\tskew--;\n\t\t\t}\n\n\t\t\t// If we are mounting a DOM VNode, mark it for insertion\n\t\t\tif (typeof childVNode.type != 'function') {\n\t\t\t\tchildVNode._flags |= INSERT_VNODE;\n\t\t\t}\n\t\t} else if (matchingIndex !== skewedIndex) {\n\t\t\tif (matchingIndex == skewedIndex - 1) {\n\t\t\t\tskew = matchingIndex - skewedIndex;\n\t\t\t} else if (matchingIndex == skewedIndex + 1) {\n\t\t\t\tskew++;\n\t\t\t} else if (matchingIndex > skewedIndex) {\n\t\t\t\t// Our matched DOM-node is further in the list of children than\n\t\t\t\t// where it's at now.\n\n\t\t\t\t// When the remaining old children is bigger than the new-children\n\t\t\t\t// minus our skewed index we know we are dealing with a shrinking list\n\t\t\t\t// we have to increase our skew with the matchedIndex - the skewed index\n\t\t\t\tif (remainingOldChildren > newChildrenLength - skewedIndex) {\n\t\t\t\t\tskew += matchingIndex - skewedIndex;\n\t\t\t\t} else {\n\t\t\t\t\t// If we have matched all the children just decrease the skew\n\t\t\t\t\tskew--;\n\t\t\t\t}\n\t\t\t} else if (matchingIndex < skewedIndex) {\n\t\t\t\t// When our new position is in front of our old position than we increase the skew\n\t\t\t\tskew++;\n\t\t\t}\n\n\t\t\t// Move this VNode's DOM if the original index (matchingIndex) doesn't\n\t\t\t// match the new skew index (i + new skew)\n\t\t\tif (matchingIndex !== i + skew) {\n\t\t\t\tchildVNode._flags |= INSERT_VNODE;\n\t\t\t}\n\t\t}\n\t}\n\n\t// Remove remaining oldChildren if there are any. Loop forwards so that as we\n\t// unmount DOM from the beginning of the oldChildren, we can adjust oldDom to\n\t// point to the next child, which needs to be the first DOM node that won't be\n\t// unmounted.\n\tif (remainingOldChildren) {\n\t\tfor (i = 0; i < oldChildrenLength; i++) {\n\t\t\toldVNode = oldChildren[i];\n\t\t\tif (oldVNode != null && (oldVNode._flags & MATCHED) === 0) {\n\t\t\t\tif (oldVNode._dom == newParentVNode._nextDom) {\n\t\t\t\t\tnewParentVNode._nextDom = getDomSibling(oldVNode);\n\t\t\t\t}\n\n\t\t\t\tunmount(oldVNode, oldVNode);\n\t\t\t}\n\t\t}\n\t}\n}\n\n/**\n * @param {VNode} parentVNode\n * @param {PreactElement} oldDom\n * @param {PreactElement} parentDom\n * @returns {PreactElement}\n */\nfunction insert(parentVNode, oldDom, parentDom) {\n\t// Note: VNodes in nested suspended trees may be missing _children.\n\n\tif (typeof parentVNode.type == 'function') {\n\t\tlet children = parentVNode._children;\n\t\tfor (let i = 0; children && i < children.length; i++) {\n\t\t\tif (children[i]) {\n\t\t\t\t// If we enter this code path on sCU bailout, where we copy\n\t\t\t\t// oldVNode._children to newVNode._children, we need to update the old\n\t\t\t\t// children's _parent pointer to point to the newVNode (parentVNode\n\t\t\t\t// here).\n\t\t\t\tchildren[i]._parent = parentVNode;\n\t\t\t\toldDom = insert(children[i], oldDom, parentDom);\n\t\t\t}\n\t\t}\n\n\t\treturn oldDom;\n\t} else if (parentVNode._dom != oldDom) {\n\t\tparentDom.insertBefore(parentVNode._dom, oldDom || null);\n\t\toldDom = parentVNode._dom;\n\t}\n\n\tdo {\n\t\toldDom = oldDom && oldDom.nextSibling;\n\t} while (oldDom != null && oldDom.nodeType === 8);\n\n\treturn oldDom;\n}\n\n/**\n * Flatten and loop through the children of a virtual node\n * @param {ComponentChildren} children The unflattened children of a virtual\n * node\n * @returns {VNode[]}\n */\nexport function toChildArray(children, out) {\n\tout = out || [];\n\tif (children == null || typeof children == 'boolean') {\n\t} else if (isArray(children)) {\n\t\tchildren.some(child => {\n\t\t\ttoChildArray(child, out);\n\t\t});\n\t} else {\n\t\tout.push(children);\n\t}\n\treturn out;\n}\n\n/**\n * @param {VNode} childVNode\n * @param {VNode[]} oldChildren\n * @param {number} skewedIndex\n * @param {number} remainingOldChildren\n * @returns {number}\n */\nfunction findMatchingIndex(\n\tchildVNode,\n\toldChildren,\n\tskewedIndex,\n\tremainingOldChildren\n) {\n\tconst key = childVNode.key;\n\tconst type = childVNode.type;\n\tlet x = skewedIndex - 1;\n\tlet y = skewedIndex + 1;\n\tlet oldVNode = oldChildren[skewedIndex];\n\n\t// We only need to perform a search if there are more children\n\t// (remainingOldChildren) to search. However, if the oldVNode we just looked\n\t// at skewedIndex was not already used in this diff, then there must be at\n\t// least 1 other (so greater than 1) remainingOldChildren to attempt to match\n\t// against. So the following condition checks that ensuring\n\t// remainingOldChildren > 1 if the oldVNode is not already used/matched. Else\n\t// if the oldVNode was null or matched, then there could needs to be at least\n\t// 1 (aka `remainingOldChildren > 0`) children to find and compare against.\n\tlet shouldSearch =\n\t\tremainingOldChildren >\n\t\t(oldVNode != null && (oldVNode._flags & MATCHED) === 0 ? 1 : 0);\n\n\tif (\n\t\toldVNode === null ||\n\t\t(oldVNode &&\n\t\t\tkey == oldVNode.key &&\n\t\t\ttype === oldVNode.type &&\n\t\t\t(oldVNode._flags & MATCHED) === 0)\n\t) {\n\t\treturn skewedIndex;\n\t} else if (shouldSearch) {\n\t\twhile (x >= 0 || y < oldChildren.length) {\n\t\t\tif (x >= 0) {\n\t\t\t\toldVNode = oldChildren[x];\n\t\t\t\tif (\n\t\t\t\t\toldVNode &&\n\t\t\t\t\t(oldVNode._flags & MATCHED) === 0 &&\n\t\t\t\t\tkey == oldVNode.key &&\n\t\t\t\t\ttype === oldVNode.type\n\t\t\t\t) {\n\t\t\t\t\treturn x;\n\t\t\t\t}\n\t\t\t\tx--;\n\t\t\t}\n\n\t\t\tif (y < oldChildren.length) {\n\t\t\t\toldVNode = oldChildren[y];\n\t\t\t\tif (\n\t\t\t\t\toldVNode &&\n\t\t\t\t\t(oldVNode._flags & MATCHED) === 0 &&\n\t\t\t\t\tkey == oldVNode.key &&\n\t\t\t\t\ttype === oldVNode.type\n\t\t\t\t) {\n\t\t\t\t\treturn y;\n\t\t\t\t}\n\t\t\t\ty++;\n\t\t\t}\n\t\t}\n\t}\n\n\treturn -1;\n}\n", "import {\n\tEMPTY_OBJ,\n\tMODE_HYDRATE,\n\tMODE_SUSPENDED,\n\tRESET_MODE\n} from '../constants';\nimport { BaseComponent, getDomSibling } from '../component';\nimport { Fragment } from '../create-element';\nimport { diffChildren } from './children';\nimport { setProperty } from './props';\nimport { assign, isArray, removeNode, slice } from '../util';\nimport options from '../options';\n\n/**\n * Diff two virtual nodes and apply proper changes to the DOM\n * @param {PreactElement} parentDom The parent of the DOM element\n * @param {VNode} newVNode The new virtual node\n * @param {VNode} oldVNode The old virtual node\n * @param {object} globalContext The current context object. Modified by\n * getChildContext\n * @param {string} namespace Current namespace of the DOM node (HTML, SVG, or MathML)\n * @param {Array} excessDomChildren\n * @param {Array} commitQueue List of components which have callbacks\n * to invoke in commitRoot\n * @param {PreactElement} oldDom The current attached DOM element any new dom\n * elements should be placed around. Likely `null` on first render (except when\n * hydrating). Can be a sibling DOM element when diffing Fragments that have\n * siblings. In most cases, it starts out as `oldChildren[0]._dom`.\n * @param {boolean} isHydrating Whether or not we are in hydration\n * @param {any[]} refQueue an array of elements needed to invoke refs\n */\nexport function diff(\n\tparentDom,\n\tnewVNode,\n\toldVNode,\n\tglobalContext,\n\tnamespace,\n\texcessDomChildren,\n\tcommitQueue,\n\toldDom,\n\tisHydrating,\n\trefQueue\n) {\n\t/** @type {any} */\n\tlet tmp,\n\t\tnewType = newVNode.type;\n\n\t// When passing through createElement it assigns the object\n\t// constructor as undefined. This to prevent JSON-injection.\n\tif (newVNode.constructor !== undefined) return null;\n\n\t// If the previous diff bailed out, resume creating/hydrating.\n\tif (oldVNode._flags & MODE_SUSPENDED) {\n\t\tisHydrating = !!(oldVNode._flags & MODE_HYDRATE);\n\t\toldDom = newVNode._dom = oldVNode._dom;\n\t\texcessDomChildren = [oldDom];\n\t}\n\n\tif ((tmp = options._diff)) tmp(newVNode);\n\n\touter: if (typeof newType == 'function') {\n\t\ttry {\n\t\t\tlet c, isNew, oldProps, oldState, snapshot, clearProcessingException;\n\t\t\tlet newProps = newVNode.props;\n\t\t\tconst isClassComponent =\n\t\t\t\t'prototype' in newType && newType.prototype.render;\n\n\t\t\t// Necessary for createContext api. Setting this property will pass\n\t\t\t// the context value as `this.context` just for this component.\n\t\t\ttmp = newType.contextType;\n\t\t\tlet provider = tmp && globalContext[tmp._id];\n\t\t\tlet componentContext = tmp\n\t\t\t\t? provider\n\t\t\t\t\t? provider.props.value\n\t\t\t\t\t: tmp._defaultValue\n\t\t\t\t: globalContext;\n\n\t\t\t// Get component and set it to `c`\n\t\t\tif (oldVNode._component) {\n\t\t\t\tc = newVNode._component = oldVNode._component;\n\t\t\t\tclearProcessingException = c._processingException = c._pendingError;\n\t\t\t} else {\n\t\t\t\t// Instantiate the new component\n\t\t\t\tif (isClassComponent) {\n\t\t\t\t\t// @ts-expect-error The check above verifies that newType is suppose to be constructed\n\t\t\t\t\tnewVNode._component = c = new newType(newProps, componentContext); // eslint-disable-line new-cap\n\t\t\t\t} else {\n\t\t\t\t\t// @ts-expect-error Trust me, Component implements the interface we want\n\t\t\t\t\tnewVNode._component = c = new BaseComponent(\n\t\t\t\t\t\tnewProps,\n\t\t\t\t\t\tcomponentContext\n\t\t\t\t\t);\n\t\t\t\t\tc.constructor = newType;\n\t\t\t\t\tc.render = doRender;\n\t\t\t\t}\n\t\t\t\tif (provider) provider.sub(c);\n\n\t\t\t\tc.props = newProps;\n\t\t\t\tif (!c.state) c.state = {};\n\t\t\t\tc.context = componentContext;\n\t\t\t\tc._globalContext = globalContext;\n\t\t\t\tisNew = c._dirty = true;\n\t\t\t\tc._renderCallbacks = [];\n\t\t\t\tc._stateCallbacks = [];\n\t\t\t}\n\n\t\t\t// Invoke getDerivedStateFromProps\n\t\t\tif (isClassComponent && c._nextState == null) {\n\t\t\t\tc._nextState = c.state;\n\t\t\t}\n\n\t\t\tif (isClassComponent && newType.getDerivedStateFromProps != null) {\n\t\t\t\tif (c._nextState == c.state) {\n\t\t\t\t\tc._nextState = assign({}, c._nextState);\n\t\t\t\t}\n\n\t\t\t\tassign(\n\t\t\t\t\tc._nextState,\n\t\t\t\t\tnewType.getDerivedStateFromProps(newProps, c._nextState)\n\t\t\t\t);\n\t\t\t}\n\n\t\t\toldProps = c.props;\n\t\t\toldState = c.state;\n\t\t\tc._vnode = newVNode;\n\n\t\t\t// Invoke pre-render lifecycle methods\n\t\t\tif (isNew) {\n\t\t\t\tif (\n\t\t\t\t\tisClassComponent &&\n\t\t\t\t\tnewType.getDerivedStateFromProps == null &&\n\t\t\t\t\tc.componentWillMount != null\n\t\t\t\t) {\n\t\t\t\t\tc.componentWillMount();\n\t\t\t\t}\n\n\t\t\t\tif (isClassComponent && c.componentDidMount != null) {\n\t\t\t\t\tc._renderCallbacks.push(c.componentDidMount);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif (\n\t\t\t\t\tisClassComponent &&\n\t\t\t\t\tnewType.getDerivedStateFromProps == null &&\n\t\t\t\t\tnewProps !== oldProps &&\n\t\t\t\t\tc.componentWillReceiveProps != null\n\t\t\t\t) {\n\t\t\t\t\tc.componentWillReceiveProps(newProps, componentContext);\n\t\t\t\t}\n\n\t\t\t\tif (\n\t\t\t\t\t!c._force &&\n\t\t\t\t\t((c.shouldComponentUpdate != null &&\n\t\t\t\t\t\tc.shouldComponentUpdate(\n\t\t\t\t\t\t\tnewProps,\n\t\t\t\t\t\t\tc._nextState,\n\t\t\t\t\t\t\tcomponentContext\n\t\t\t\t\t\t) === false) ||\n\t\t\t\t\t\tnewVNode._original === oldVNode._original)\n\t\t\t\t) {\n\t\t\t\t\t// More info about this here: https://gist.github.com/JoviDeCroock/bec5f2ce93544d2e6070ef8e0036e4e8\n\t\t\t\t\tif (newVNode._original !== oldVNode._original) {\n\t\t\t\t\t\t// When we are dealing with a bail because of sCU we have to update\n\t\t\t\t\t\t// the props, state and dirty-state.\n\t\t\t\t\t\t// when we are dealing with strict-equality we don't as the child could still\n\t\t\t\t\t\t// be dirtied see #3883\n\t\t\t\t\t\tc.props = newProps;\n\t\t\t\t\t\tc.state = c._nextState;\n\t\t\t\t\t\tc._dirty = false;\n\t\t\t\t\t}\n\n\t\t\t\t\tnewVNode._dom = oldVNode._dom;\n\t\t\t\t\tnewVNode._children = oldVNode._children;\n\t\t\t\t\tnewVNode._children.forEach(vnode => {\n\t\t\t\t\t\tif (vnode) vnode._parent = newVNode;\n\t\t\t\t\t});\n\n\t\t\t\t\tfor (let i = 0; i < c._stateCallbacks.length; i++) {\n\t\t\t\t\t\tc._renderCallbacks.push(c._stateCallbacks[i]);\n\t\t\t\t\t}\n\t\t\t\t\tc._stateCallbacks = [];\n\n\t\t\t\t\tif (c._renderCallbacks.length) {\n\t\t\t\t\t\tcommitQueue.push(c);\n\t\t\t\t\t}\n\n\t\t\t\t\tbreak outer;\n\t\t\t\t}\n\n\t\t\t\tif (c.componentWillUpdate != null) {\n\t\t\t\t\tc.componentWillUpdate(newProps, c._nextState, componentContext);\n\t\t\t\t}\n\n\t\t\t\tif (isClassComponent && c.componentDidUpdate != null) {\n\t\t\t\t\tc._renderCallbacks.push(() => {\n\t\t\t\t\t\tc.componentDidUpdate(oldProps, oldState, snapshot);\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tc.context = componentContext;\n\t\t\tc.props = newProps;\n\t\t\tc._parentDom = parentDom;\n\t\t\tc._force = false;\n\n\t\t\tlet renderHook = options._render,\n\t\t\t\tcount = 0;\n\t\t\tif (isClassComponent) {\n\t\t\t\tc.state = c._nextState;\n\t\t\t\tc._dirty = false;\n\n\t\t\t\tif (renderHook) renderHook(newVNode);\n\n\t\t\t\ttmp = c.render(c.props, c.state, c.context);\n\n\t\t\t\tfor (let i = 0; i < c._stateCallbacks.length; i++) {\n\t\t\t\t\tc._renderCallbacks.push(c._stateCallbacks[i]);\n\t\t\t\t}\n\t\t\t\tc._stateCallbacks = [];\n\t\t\t} else {\n\t\t\t\tdo {\n\t\t\t\t\tc._dirty = false;\n\t\t\t\t\tif (renderHook) renderHook(newVNode);\n\n\t\t\t\t\ttmp = c.render(c.props, c.state, c.context);\n\n\t\t\t\t\t// Handle setState called in render, see #2553\n\t\t\t\t\tc.state = c._nextState;\n\t\t\t\t} while (c._dirty && ++count < 25);\n\t\t\t}\n\n\t\t\t// Handle setState called in render, see #2553\n\t\t\tc.state = c._nextState;\n\n\t\t\tif (c.getChildContext != null) {\n\t\t\t\tglobalContext = assign(assign({}, globalContext), c.getChildContext());\n\t\t\t}\n\n\t\t\tif (isClassComponent && !isNew && c.getSnapshotBeforeUpdate != null) {\n\t\t\t\tsnapshot = c.getSnapshotBeforeUpdate(oldProps, oldState);\n\t\t\t}\n\n\t\t\tlet isTopLevelFragment =\n\t\t\t\ttmp != null && tmp.type === Fragment && tmp.key == null;\n\t\t\tlet renderResult = isTopLevelFragment ? tmp.props.children : tmp;\n\n\t\t\tdiffChildren(\n\t\t\t\tparentDom,\n\t\t\t\tisArray(renderResult) ? renderResult : [renderResult],\n\t\t\t\tnewVNode,\n\t\t\t\toldVNode,\n\t\t\t\tglobalContext,\n\t\t\t\tnamespace,\n\t\t\t\texcessDomChildren,\n\t\t\t\tcommitQueue,\n\t\t\t\toldDom,\n\t\t\t\tisHydrating,\n\t\t\t\trefQueue\n\t\t\t);\n\n\t\t\tc.base = newVNode._dom;\n\n\t\t\t// We successfully rendered this VNode, unset any stored hydration/bailout state:\n\t\t\tnewVNode._flags &= RESET_MODE;\n\n\t\t\tif (c._renderCallbacks.length) {\n\t\t\t\tcommitQueue.push(c);\n\t\t\t}\n\n\t\t\tif (clearProcessingException) {\n\t\t\t\tc._pendingError = c._processingException = null;\n\t\t\t}\n\t\t} catch (e) {\n\t\t\tnewVNode._original = null;\n\t\t\t// if hydrating or creating initial tree, bailout preserves DOM:\n\t\t\tif (isHydrating || excessDomChildren != null) {\n\t\t\t\tnewVNode._dom = oldDom;\n\t\t\t\tnewVNode._flags |= isHydrating\n\t\t\t\t\t? MODE_HYDRATE | MODE_SUSPENDED\n\t\t\t\t\t: MODE_HYDRATE;\n\t\t\t\texcessDomChildren[excessDomChildren.indexOf(oldDom)] = null;\n\t\t\t\t// ^ could possibly be simplified to:\n\t\t\t\t// excessDomChildren.length = 0;\n\t\t\t} else {\n\t\t\t\tnewVNode._dom = oldVNode._dom;\n\t\t\t\tnewVNode._children = oldVNode._children;\n\t\t\t}\n\t\t\toptions._catchError(e, newVNode, oldVNode);\n\t\t}\n\t} else if (\n\t\texcessDomChildren == null &&\n\t\tnewVNode._original === oldVNode._original\n\t) {\n\t\tnewVNode._children = oldVNode._children;\n\t\tnewVNode._dom = oldVNode._dom;\n\t} else {\n\t\tnewVNode._dom = diffElementNodes(\n\t\t\toldVNode._dom,\n\t\t\tnewVNode,\n\t\t\toldVNode,\n\t\t\tglobalContext,\n\t\t\tnamespace,\n\t\t\texcessDomChildren,\n\t\t\tcommitQueue,\n\t\t\tisHydrating,\n\t\t\trefQueue\n\t\t);\n\t}\n\n\tif ((tmp = options.diffed)) tmp(newVNode);\n}\n\n/**\n * @param {Array} commitQueue List of components\n * which have callbacks to invoke in commitRoot\n * @param {VNode} root\n */\nexport function commitRoot(commitQueue, root, refQueue) {\n\troot._nextDom = undefined;\n\n\tfor (let i = 0; i < refQueue.length; i++) {\n\t\tapplyRef(refQueue[i], refQueue[++i], refQueue[++i]);\n\t}\n\n\tif (options._commit) options._commit(root, commitQueue);\n\n\tcommitQueue.some(c => {\n\t\ttry {\n\t\t\t// @ts-expect-error Reuse the commitQueue variable here so the type changes\n\t\t\tcommitQueue = c._renderCallbacks;\n\t\t\tc._renderCallbacks = [];\n\t\t\tcommitQueue.some(cb => {\n\t\t\t\t// @ts-expect-error See above comment on commitQueue\n\t\t\t\tcb.call(c);\n\t\t\t});\n\t\t} catch (e) {\n\t\t\toptions._catchError(e, c._vnode);\n\t\t}\n\t});\n}\n\n/**\n * Diff two virtual nodes representing DOM element\n * @param {PreactElement} dom The DOM element representing the virtual nodes\n * being diffed\n * @param {VNode} newVNode The new virtual node\n * @param {VNode} oldVNode The old virtual node\n * @param {object} globalContext The current context object\n * @param {string} namespace Current namespace of the DOM node (HTML, SVG, or MathML)\n * @param {Array} excessDomChildren\n * @param {Array} commitQueue List of components which have callbacks\n * to invoke in commitRoot\n * @param {boolean} isHydrating Whether or not we are in hydration\n * @param {any[]} refQueue an array of elements needed to invoke refs\n * @returns {PreactElement}\n */\nfunction diffElementNodes(\n\tdom,\n\tnewVNode,\n\toldVNode,\n\tglobalContext,\n\tnamespace,\n\texcessDomChildren,\n\tcommitQueue,\n\tisHydrating,\n\trefQueue\n) {\n\tlet oldProps = oldVNode.props;\n\tlet newProps = newVNode.props;\n\tlet nodeType = /** @type {string} */ (newVNode.type);\n\t/** @type {any} */\n\tlet i;\n\t/** @type {{ __html?: string }} */\n\tlet newHtml;\n\t/** @type {{ __html?: string }} */\n\tlet oldHtml;\n\t/** @type {ComponentChildren} */\n\tlet newChildren;\n\tlet value;\n\tlet inputValue;\n\tlet checked;\n\n\t// Tracks entering and exiting namespaces when descending through the tree.\n\tif (nodeType === 'svg') namespace = 'http://www.w3.org/2000/svg';\n\telse if (nodeType === 'math')\n\t\tnamespace = 'http://www.w3.org/1998/Math/MathML';\n\telse if (!namespace) namespace = 'http://www.w3.org/1999/xhtml';\n\n\tif (excessDomChildren != null) {\n\t\tfor (i = 0; i < excessDomChildren.length; i++) {\n\t\t\tvalue = excessDomChildren[i];\n\n\t\t\t// if newVNode matches an element in excessDomChildren or the `dom`\n\t\t\t// argument matches an element in excessDomChildren, remove it from\n\t\t\t// excessDomChildren so it isn't later removed in diffChildren\n\t\t\tif (\n\t\t\t\tvalue &&\n\t\t\t\t'setAttribute' in value === !!nodeType &&\n\t\t\t\t(nodeType ? value.localName === nodeType : value.nodeType === 3)\n\t\t\t) {\n\t\t\t\tdom = value;\n\t\t\t\texcessDomChildren[i] = null;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\tif (dom == null) {\n\t\tif (nodeType === null) {\n\t\t\treturn document.createTextNode(newProps);\n\t\t}\n\n\t\tdom = document.createElementNS(\n\t\t\tnamespace,\n\t\t\tnodeType,\n\t\t\tnewProps.is && newProps\n\t\t);\n\n\t\t// we created a new parent, so none of the previously attached children can be reused:\n\t\texcessDomChildren = null;\n\t\t// we are creating a new node, so we can assume this is a new subtree (in\n\t\t// case we are hydrating), this deopts the hydrate\n\t\tisHydrating = false;\n\t}\n\n\tif (nodeType === null) {\n\t\t// During hydration, we still have to split merged text from SSR'd HTML.\n\t\tif (oldProps !== newProps && (!isHydrating || dom.data !== newProps)) {\n\t\t\tdom.data = newProps;\n\t\t}\n\t} else {\n\t\t// If excessDomChildren was not null, repopulate it with the current element's children:\n\t\texcessDomChildren = excessDomChildren && slice.call(dom.childNodes);\n\n\t\toldProps = oldVNode.props || EMPTY_OBJ;\n\n\t\t// If we are in a situation where we are not hydrating but are using\n\t\t// existing DOM (e.g. replaceNode) we should read the existing DOM\n\t\t// attributes to diff them\n\t\tif (!isHydrating && excessDomChildren != null) {\n\t\t\toldProps = {};\n\t\t\tfor (i = 0; i < dom.attributes.length; i++) {\n\t\t\t\tvalue = dom.attributes[i];\n\t\t\t\toldProps[value.name] = value.value;\n\t\t\t}\n\t\t}\n\n\t\tfor (i in oldProps) {\n\t\t\tvalue = oldProps[i];\n\t\t\tif (i == 'children') {\n\t\t\t} else if (i == 'dangerouslySetInnerHTML') {\n\t\t\t\toldHtml = value;\n\t\t\t} else if (i !== 'key' && !(i in newProps)) {\n\t\t\t\tif (\n\t\t\t\t\t(i == 'value' && 'defaultValue' in newProps) ||\n\t\t\t\t\t(i == 'checked' && 'defaultChecked' in newProps)\n\t\t\t\t) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tsetProperty(dom, i, null, value, namespace);\n\t\t\t}\n\t\t}\n\n\t\t// During hydration, props are not diffed at all (including dangerouslySetInnerHTML)\n\t\t// @TODO we should warn in debug mode when props don't match here.\n\t\tfor (i in newProps) {\n\t\t\tvalue = newProps[i];\n\t\t\tif (i == 'children') {\n\t\t\t\tnewChildren = value;\n\t\t\t} else if (i == 'dangerouslySetInnerHTML') {\n\t\t\t\tnewHtml = value;\n\t\t\t} else if (i == 'value') {\n\t\t\t\tinputValue = value;\n\t\t\t} else if (i == 'checked') {\n\t\t\t\tchecked = value;\n\t\t\t} else if (\n\t\t\t\ti !== 'key' &&\n\t\t\t\t(!isHydrating || typeof value == 'function') &&\n\t\t\t\toldProps[i] !== value\n\t\t\t) {\n\t\t\t\tsetProperty(dom, i, value, oldProps[i], namespace);\n\t\t\t}\n\t\t}\n\n\t\t// If the new vnode didn't have dangerouslySetInnerHTML, diff its children\n\t\tif (newHtml) {\n\t\t\t// Avoid re-applying the same '__html' if it did not changed between re-render\n\t\t\tif (\n\t\t\t\t!isHydrating &&\n\t\t\t\t(!oldHtml ||\n\t\t\t\t\t(newHtml.__html !== oldHtml.__html &&\n\t\t\t\t\t\tnewHtml.__html !== dom.innerHTML))\n\t\t\t) {\n\t\t\t\tdom.innerHTML = newHtml.__html;\n\t\t\t}\n\n\t\t\tnewVNode._children = [];\n\t\t} else {\n\t\t\tif (oldHtml) dom.innerHTML = '';\n\n\t\t\tdiffChildren(\n\t\t\t\tdom,\n\t\t\t\tisArray(newChildren) ? newChildren : [newChildren],\n\t\t\t\tnewVNode,\n\t\t\t\toldVNode,\n\t\t\t\tglobalContext,\n\t\t\t\tnodeType === 'foreignObject'\n\t\t\t\t\t? 'http://www.w3.org/1999/xhtml'\n\t\t\t\t\t: namespace,\n\t\t\t\texcessDomChildren,\n\t\t\t\tcommitQueue,\n\t\t\t\texcessDomChildren\n\t\t\t\t\t? excessDomChildren[0]\n\t\t\t\t\t: oldVNode._children && getDomSibling(oldVNode, 0),\n\t\t\t\tisHydrating,\n\t\t\t\trefQueue\n\t\t\t);\n\n\t\t\t// Remove children that are not part of any vnode.\n\t\t\tif (excessDomChildren != null) {\n\t\t\t\tfor (i = excessDomChildren.length; i--; ) {\n\t\t\t\t\tif (excessDomChildren[i] != null) removeNode(excessDomChildren[i]);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// As above, don't diff props during hydration\n\t\tif (!isHydrating) {\n\t\t\ti = 'value';\n\t\t\tif (\n\t\t\t\tinputValue !== undefined &&\n\t\t\t\t// #2756 For the -element the initial value is 0,\n\t\t\t\t// despite the attribute not being present. When the attribute\n\t\t\t\t// is missing the progress bar is treated as indeterminate.\n\t\t\t\t// To fix that we'll always update it when it is 0 for progress elements\n\t\t\t\t(inputValue !== dom[i] ||\n\t\t\t\t\t(nodeType === 'progress' && !inputValue) ||\n\t\t\t\t\t// This is only for IE 11 to fix \n\tif (\n\t\ttype == 'select' &&\n\t\tnormalizedProps.multiple &&\n\t\tArray.isArray(normalizedProps.value)\n\t) {\n\t\t// forEach() always returns undefined, which we abuse here to unset the value prop.\n\t\tnormalizedProps.value = toChildArray(props.children).forEach(child => {\n\t\t\tchild.props.selected =\n\t\t\t\tnormalizedProps.value.indexOf(child.props.value) != -1;\n\t\t});\n\t}\n\n\t// Adding support for defaultValue in select tag\n\tif (type == 'select' && normalizedProps.defaultValue != null) {\n\t\tnormalizedProps.value = toChildArray(props.children).forEach(child => {\n\t\t\tif (normalizedProps.multiple) {\n\t\t\t\tchild.props.selected =\n\t\t\t\t\tnormalizedProps.defaultValue.indexOf(child.props.value) != -1;\n\t\t\t} else {\n\t\t\t\tchild.props.selected =\n\t\t\t\t\tnormalizedProps.defaultValue == child.props.value;\n\t\t\t}\n\t\t});\n\t}\n\n\tif (props.class && !props.className) {\n\t\tnormalizedProps.class = props.class;\n\t\tObject.defineProperty(\n\t\t\tnormalizedProps,\n\t\t\t'className',\n\t\t\tclassNameDescriptorNonEnumberable\n\t\t);\n\t} else if (props.className && !props.class) {\n\t\tnormalizedProps.class = normalizedProps.className = props.className;\n\t} else if (props.class && props.className) {\n\t\tnormalizedProps.class = normalizedProps.className = props.className;\n\t}\n\n\tvnode.props = normalizedProps;\n}\n\nlet oldVNodeHook = options.vnode;\noptions.vnode = vnode => {\n\t// only normalize props on Element nodes\n\tif (typeof vnode.type === 'string') {\n\t\thandleDomVNode(vnode);\n\t}\n\n\tvnode.$$typeof = REACT_ELEMENT_TYPE;\n\n\tif (oldVNodeHook) oldVNodeHook(vnode);\n};\n\n// Only needed for react-relay\nlet currentComponent;\nconst oldBeforeRender = options._render;\noptions._render = function (vnode) {\n\tif (oldBeforeRender) {\n\t\toldBeforeRender(vnode);\n\t}\n\tcurrentComponent = vnode._component;\n};\n\nconst oldDiffed = options.diffed;\n/** @type {(vnode: import('./internal').VNode) => void} */\noptions.diffed = function (vnode) {\n\tif (oldDiffed) {\n\t\toldDiffed(vnode);\n\t}\n\n\tconst props = vnode.props;\n\tconst dom = vnode._dom;\n\n\tif (\n\t\tdom != null &&\n\t\tvnode.type === 'textarea' &&\n\t\t'value' in props &&\n\t\tprops.value !== dom.value\n\t) {\n\t\tdom.value = props.value == null ? '' : props.value;\n\t}\n\n\tcurrentComponent = null;\n};\n\n// This is a very very private internal function for React it\n// is used to sort-of do runtime dependency injection.\nexport const __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED = {\n\tReactCurrentDispatcher: {\n\t\tcurrent: {\n\t\t\treadContext(context) {\n\t\t\t\treturn currentComponent._globalContext[context._id].props.value;\n\t\t\t},\n\t\t\tuseCallback,\n\t\t\tuseContext,\n\t\t\tuseDebugValue,\n\t\t\tuseDeferredValue,\n\t\t\tuseEffect,\n\t\t\tuseId,\n\t\t\tuseImperativeHandle,\n\t\t\tuseInsertionEffect,\n\t\t\tuseLayoutEffect,\n\t\t\tuseMemo,\n\t\t\t// useMutableSource, // experimental-only and replaced by uSES, likely not worth supporting\n\t\t\tuseReducer,\n\t\t\tuseRef,\n\t\t\tuseState,\n\t\t\tuseSyncExternalStore,\n\t\t\tuseTransition\n\t\t}\n\t}\n};\n", "import {\n\tcreateElement,\n\trender as preactRender,\n\tcloneElement as preactCloneElement,\n\tcreateRef,\n\tComponent,\n\tcreateContext,\n\tFragment\n} from 'preact';\nimport {\n\tuseState,\n\tuseId,\n\tuseReducer,\n\tuseEffect,\n\tuseLayoutEffect,\n\tuseRef,\n\tuseImperativeHandle,\n\tuseMemo,\n\tuseCallback,\n\tuseContext,\n\tuseDebugValue\n} from 'preact/hooks';\nimport { PureComponent } from './PureComponent';\nimport { memo } from './memo';\nimport { forwardRef } from './forwardRef';\nimport { Children } from './Children';\nimport { Suspense, lazy } from './suspense';\nimport { SuspenseList } from './suspense-list';\nimport { createPortal } from './portals';\nimport { is } from './util';\nimport {\n\thydrate,\n\trender,\n\tREACT_ELEMENT_TYPE,\n\t__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED\n} from './render';\n\nconst version = '17.0.2'; // trick libraries to think we are react\n\n/**\n * Legacy version of createElement.\n * @param {import('./internal').VNode[\"type\"]} type The node name or Component constructor\n */\nfunction createFactory(type) {\n\treturn createElement.bind(null, type);\n}\n\n/**\n * Check if the passed element is a valid (p)react node.\n * @param {*} element The element to check\n * @returns {boolean}\n */\nfunction isValidElement(element) {\n\treturn !!element && element.$$typeof === REACT_ELEMENT_TYPE;\n}\n\n/**\n * Check if the passed element is a Fragment node.\n * @param {*} element The element to check\n * @returns {boolean}\n */\nfunction isFragment(element) {\n\treturn isValidElement(element) && element.type === Fragment;\n}\n\n/**\n * Check if the passed element is a Memo node.\n * @param {*} element The element to check\n * @returns {boolean}\n */\nfunction isMemo(element) {\n\treturn (\n\t\t!!element &&\n\t\t!!element.displayName &&\n\t\t(typeof element.displayName === 'string' ||\n\t\t\telement.displayName instanceof String) &&\n\t\telement.displayName.startsWith('Memo(')\n\t);\n}\n\n/**\n * Wrap `cloneElement` to abort if the passed element is not a valid element and apply\n * all vnode normalizations.\n * @param {import('./internal').VNode} element The vnode to clone\n * @param {object} props Props to add when cloning\n * @param {Array} rest Optional component children\n */\nfunction cloneElement(element) {\n\tif (!isValidElement(element)) return element;\n\treturn preactCloneElement.apply(null, arguments);\n}\n\n/**\n * Remove a component tree from the DOM, including state and event handlers.\n * @param {import('./internal').PreactElement} container\n * @returns {boolean}\n */\nfunction unmountComponentAtNode(container) {\n\tif (container._children) {\n\t\tpreactRender(null, container);\n\t\treturn true;\n\t}\n\treturn false;\n}\n\n/**\n * Get the matching DOM node for a component\n * @param {import('./internal').Component} component\n * @returns {import('./internal').PreactElement | null}\n */\nfunction findDOMNode(component) {\n\treturn (\n\t\t(component &&\n\t\t\t(component.base || (component.nodeType === 1 && component))) ||\n\t\tnull\n\t);\n}\n\n/**\n * Deprecated way to control batched rendering inside the reconciler, but we\n * already schedule in batches inside our rendering code\n * @template Arg\n * @param {(arg: Arg) => void} callback function that triggers the updated\n * @param {Arg} [arg] Optional argument that can be passed to the callback\n */\n// eslint-disable-next-line camelcase\nconst unstable_batchedUpdates = (callback, arg) => callback(arg);\n\n/**\n * In React, `flushSync` flushes the entire tree and forces a rerender. It's\n * implmented here as a no-op.\n * @template Arg\n * @template Result\n * @param {(arg: Arg) => Result} callback function that runs before the flush\n * @param {Arg} [arg] Optional argument that can be passed to the callback\n * @returns\n */\nconst flushSync = (callback, arg) => callback(arg);\n\n/**\n * Strict Mode is not implemented in Preact, so we provide a stand-in for it\n * that just renders its children without imposing any restrictions.\n */\nconst StrictMode = Fragment;\n\nexport function startTransition(cb) {\n\tcb();\n}\n\nexport function useDeferredValue(val) {\n\treturn val;\n}\n\nexport function useTransition() {\n\treturn [false, startTransition];\n}\n\n// TODO: in theory this should be done after a VNode is diffed as we want to insert\n// styles/... before it attaches\nexport const useInsertionEffect = useLayoutEffect;\n\n// compat to react-is\nexport const isElement = isValidElement;\n\n/**\n * This is taken from https://github.com/facebook/react/blob/main/packages/use-sync-external-store/src/useSyncExternalStoreShimClient.js#L84\n * on a high level this cuts out the warnings, ... and attempts a smaller implementation\n * @typedef {{ _value: any; _getSnapshot: () => any }} Store\n */\nexport function useSyncExternalStore(subscribe, getSnapshot) {\n\tconst value = getSnapshot();\n\n\t/**\n\t * @typedef {{ _instance: Store }} StoreRef\n\t * @type {[StoreRef, (store: StoreRef) => void]}\n\t */\n\tconst [{ _instance }, forceUpdate] = useState({\n\t\t_instance: { _value: value, _getSnapshot: getSnapshot }\n\t});\n\n\tuseLayoutEffect(() => {\n\t\t_instance._value = value;\n\t\t_instance._getSnapshot = getSnapshot;\n\n\t\tif (didSnapshotChange(_instance)) {\n\t\t\tforceUpdate({ _instance });\n\t\t}\n\t}, [subscribe, value, getSnapshot]);\n\n\tuseEffect(() => {\n\t\tif (didSnapshotChange(_instance)) {\n\t\t\tforceUpdate({ _instance });\n\t\t}\n\n\t\treturn subscribe(() => {\n\t\t\tif (didSnapshotChange(_instance)) {\n\t\t\t\tforceUpdate({ _instance });\n\t\t\t}\n\t\t});\n\t}, [subscribe]);\n\n\treturn value;\n}\n\n/** @type {(inst: Store) => boolean} */\nfunction didSnapshotChange(inst) {\n\tconst latestGetSnapshot = inst._getSnapshot;\n\tconst prevValue = inst._value;\n\ttry {\n\t\tconst nextValue = latestGetSnapshot();\n\t\treturn !is(prevValue, nextValue);\n\t} catch (error) {\n\t\treturn true;\n\t}\n}\n\nexport * from 'preact/hooks';\nexport {\n\tversion,\n\tChildren,\n\trender,\n\thydrate,\n\tunmountComponentAtNode,\n\tcreatePortal,\n\tcreateElement,\n\tcreateContext,\n\tcreateFactory,\n\tcloneElement,\n\tcreateRef,\n\tFragment,\n\tisValidElement,\n\tisFragment,\n\tisMemo,\n\tfindDOMNode,\n\tComponent,\n\tPureComponent,\n\tmemo,\n\tforwardRef,\n\tflushSync,\n\t// eslint-disable-next-line camelcase\n\tunstable_batchedUpdates,\n\tStrictMode,\n\tSuspense,\n\tSuspenseList,\n\tlazy,\n\t__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED\n};\n\n// React copies the named exports to the default one.\nexport default {\n\tuseState,\n\tuseId,\n\tuseReducer,\n\tuseEffect,\n\tuseLayoutEffect,\n\tuseInsertionEffect,\n\tuseTransition,\n\tuseDeferredValue,\n\tuseSyncExternalStore,\n\tstartTransition,\n\tuseRef,\n\tuseImperativeHandle,\n\tuseMemo,\n\tuseCallback,\n\tuseContext,\n\tuseDebugValue,\n\tversion,\n\tChildren,\n\trender,\n\thydrate,\n\tunmountComponentAtNode,\n\tcreatePortal,\n\tcreateElement,\n\tcreateContext,\n\tcreateFactory,\n\tcloneElement,\n\tcreateRef,\n\tFragment,\n\tisValidElement,\n\tisElement,\n\tisFragment,\n\tisMemo,\n\tfindDOMNode,\n\tComponent,\n\tPureComponent,\n\tmemo,\n\tforwardRef,\n\tflushSync,\n\tunstable_batchedUpdates,\n\tStrictMode,\n\tSuspense,\n\tSuspenseList,\n\tlazy,\n\t__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED\n};\n", "import {\n AccessorFn,\n AccessorFnColumnDef,\n AccessorKeyColumnDef,\n DisplayColumnDef,\n GroupColumnDef,\n IdentifiedColumnDef,\n RowData,\n} from './types'\nimport { DeepKeys, DeepValue } from './utils'\n\n// type Person = {\n// firstName: string\n// lastName: string\n// age: number\n// visits: number\n// status: string\n// progress: number\n// createdAt: Date\n// nested: {\n// foo: [\n// {\n// bar: 'bar'\n// }\n// ]\n// bar: { subBar: boolean }[]\n// baz: {\n// foo: 'foo'\n// bar: {\n// baz: 'baz'\n// }\n// }\n// }\n// }\n\n// const test: DeepKeys = 'nested.foo.0.bar'\n// const test2: DeepKeys = 'nested.bar'\n\n// const helper = createColumnHelper()\n\n// helper.accessor('nested.foo', {\n// cell: info => info.getValue(),\n// })\n\n// helper.accessor('nested.foo.0.bar', {\n// cell: info => info.getValue(),\n// })\n\n// helper.accessor('nested.bar', {\n// cell: info => info.getValue(),\n// })\n\nexport type ColumnHelper = {\n accessor: <\n TAccessor extends AccessorFn | DeepKeys,\n TValue extends TAccessor extends AccessorFn\n ? TReturn\n : TAccessor extends DeepKeys\n ? DeepValue\n : never,\n >(\n accessor: TAccessor,\n column: TAccessor extends AccessorFn\n ? DisplayColumnDef\n : IdentifiedColumnDef\n ) => TAccessor extends AccessorFn\n ? AccessorFnColumnDef\n : AccessorKeyColumnDef\n display: (column: DisplayColumnDef) => DisplayColumnDef\n group: (column: GroupColumnDef) => GroupColumnDef\n}\n\nexport function createColumnHelper<\n TData extends RowData,\n>(): ColumnHelper {\n return {\n accessor: (accessor, column) => {\n return typeof accessor === 'function'\n ? ({\n ...column,\n accessorFn: accessor,\n } as any)\n : {\n ...column,\n accessorKey: accessor,\n }\n },\n display: column => column,\n group: column => column,\n }\n}\n", "import { TableOptionsResolved, TableState, Updater } from './types'\n\nexport type PartialKeys = Omit & Partial>\nexport type RequiredKeys = Omit &\n Required>\nexport type Overwrite = Omit<\n T,\n keyof U\n> &\n U\n\nexport type UnionToIntersection = (\n T extends any ? (x: T) => any : never\n) extends (x: infer R) => any\n ? R\n : never\n\nexport type IsAny = 1 extends 0 & T ? Y : N\nexport type IsKnown = unknown extends T ? N : Y\n\ntype ComputeRange<\n N extends number,\n Result extends Array = [],\n> = Result['length'] extends N\n ? Result\n : ComputeRange\ntype Index40 = ComputeRange<40>[number]\n\n// Is this type a tuple?\ntype IsTuple = T extends readonly any[] & { length: infer Length }\n ? Length extends Index40\n ? T\n : never\n : never\n\n// If this type is a tuple, what indices are allowed?\ntype AllowedIndexes<\n Tuple extends ReadonlyArray,\n Keys extends number = never,\n> = Tuple extends readonly []\n ? Keys\n : Tuple extends readonly [infer _, ...infer Tail]\n ? AllowedIndexes\n : Keys\n\nexport type DeepKeys = TDepth['length'] extends 5\n ? never\n : unknown extends T\n ? string\n : T extends readonly any[] & IsTuple\n ? AllowedIndexes | DeepKeysPrefix, TDepth>\n : T extends any[]\n ? DeepKeys\n : T extends Date\n ? never\n : T extends object\n ? (keyof T & string) | DeepKeysPrefix\n : never\n\ntype DeepKeysPrefix<\n T,\n TPrefix,\n TDepth extends any[],\n> = TPrefix extends keyof T & (number | string)\n ? `${TPrefix}.${DeepKeys & string}`\n : never\n\nexport type DeepValue =\n T extends Record\n ? TProp extends `${infer TBranch}.${infer TDeepProp}`\n ? DeepValue\n : T[TProp & string]\n : never\n\nexport type NoInfer = [T][T extends any ? 0 : never]\n\nexport type Getter = () => NoInfer\n\n///\n\nexport function functionalUpdate(updater: Updater, input: T): T {\n return typeof updater === 'function'\n ? (updater as (input: T) => T)(input)\n : updater\n}\n\nexport function noop() {\n //\n}\n\nexport function makeStateUpdater(\n key: K,\n instance: unknown\n) {\n return (updater: Updater) => {\n ;(instance as any).setState((old: TTableState) => {\n return {\n ...old,\n [key]: functionalUpdate(updater, (old as any)[key]),\n }\n })\n }\n}\n\ntype AnyFunction = (...args: any) => any\n\nexport function isFunction(d: any): d is T {\n return d instanceof Function\n}\n\nexport function isNumberArray(d: any): d is number[] {\n return Array.isArray(d) && d.every(val => typeof val === 'number')\n}\n\nexport function flattenBy(\n arr: TNode[],\n getChildren: (item: TNode) => TNode[]\n) {\n const flat: TNode[] = []\n\n const recurse = (subArr: TNode[]) => {\n subArr.forEach(item => {\n flat.push(item)\n const children = getChildren(item)\n if (children?.length) {\n recurse(children)\n }\n })\n }\n\n recurse(arr)\n\n return flat\n}\n\nexport function memo(\n getDeps: (depArgs?: TDepArgs) => [...TDeps],\n fn: (...args: NoInfer<[...TDeps]>) => TResult,\n opts: {\n key: any\n debug?: () => any\n onChange?: (result: TResult) => void\n }\n): (depArgs?: TDepArgs) => TResult {\n let deps: any[] = []\n let result: TResult | undefined\n\n return depArgs => {\n let depTime: number\n if (opts.key && opts.debug) depTime = Date.now()\n\n const newDeps = getDeps(depArgs)\n\n const depsChanged =\n newDeps.length !== deps.length ||\n newDeps.some((dep: any, index: number) => deps[index] !== dep)\n\n if (!depsChanged) {\n return result!\n }\n\n deps = newDeps\n\n let resultTime: number\n if (opts.key && opts.debug) resultTime = Date.now()\n\n result = fn(...newDeps)\n opts?.onChange?.(result)\n\n if (opts.key && opts.debug) {\n if (opts?.debug()) {\n const depEndTime = Math.round((Date.now() - depTime!) * 100) / 100\n const resultEndTime = Math.round((Date.now() - resultTime!) * 100) / 100\n const resultFpsPercentage = resultEndTime / 16\n\n const pad = (str: number | string, num: number) => {\n str = String(str)\n while (str.length < num) {\n str = ' ' + str\n }\n return str\n }\n\n console.info(\n `%c⏱ ${pad(resultEndTime, 5)} /${pad(depEndTime, 5)} ms`,\n `\n font-size: .6rem;\n font-weight: bold;\n color: hsl(${Math.max(\n 0,\n Math.min(120 - 120 * resultFpsPercentage, 120)\n )}deg 100% 31%);`,\n opts?.key\n )\n }\n }\n\n return result!\n }\n}\n\nexport function getMemoOptions(\n tableOptions: Partial>,\n debugLevel:\n | 'debugAll'\n | 'debugCells'\n | 'debugTable'\n | 'debugColumns'\n | 'debugRows'\n | 'debugHeaders',\n key: string,\n onChange?: (result: any) => void\n) {\n return {\n debug: () => tableOptions?.debugAll ?? tableOptions[debugLevel],\n key: process.env.NODE_ENV === 'development' && key,\n onChange,\n }\n}\n", "import { RowData, Cell, Column, Row, Table } from '../types'\nimport { Getter, getMemoOptions, memo } from '../utils'\n\nexport interface CellContext {\n cell: Cell\n column: Column\n getValue: Getter\n renderValue: Getter\n row: Row\n table: Table\n}\n\nexport interface CoreCell {\n /**\n * The associated Column object for the cell.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/core/cell#column)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/cells)\n */\n column: Column\n /**\n * Returns the rendering context (or props) for cell-based components like cells and aggregated cells. Use these props with your framework's `flexRender` utility to render these using the template of your choice:\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/core/cell#getcontext)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/cells)\n */\n getContext: () => CellContext\n /**\n * Returns the value for the cell, accessed via the associated column's accessor key or accessor function.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/core/cell#getvalue)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/cells)\n */\n getValue: CellContext['getValue']\n /**\n * The unique ID for the cell across the entire table.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/core/cell#id)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/cells)\n */\n id: string\n /**\n * Renders the value for a cell the same as `getValue`, but will return the `renderFallbackValue` if no value is found.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/core/cell#rendervalue)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/cells)\n */\n renderValue: CellContext['renderValue']\n /**\n * The associated Row object for the cell.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/core/cell#row)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/cells)\n */\n row: Row\n}\n\nexport function createCell(\n table: Table,\n row: Row,\n column: Column,\n columnId: string\n): Cell {\n const getRenderValue = () =>\n cell.getValue() ?? table.options.renderFallbackValue\n\n const cell: CoreCell = {\n id: `${row.id}_${column.id}`,\n row,\n column,\n getValue: () => row.getValue(columnId),\n renderValue: getRenderValue,\n getContext: memo(\n () => [table, column, row, cell],\n (table, column, row, cell) => ({\n table,\n column,\n row,\n cell: cell as Cell,\n getValue: cell.getValue,\n renderValue: cell.renderValue,\n }),\n getMemoOptions(table.options, 'debugCells', 'cell.getContext')\n ),\n }\n\n table._features.forEach(feature => {\n feature.createCell?.(\n cell as Cell,\n column,\n row as Row,\n table\n )\n }, {})\n\n return cell as Cell\n}\n", "import {\n Column,\n Table,\n AccessorFn,\n ColumnDef,\n RowData,\n ColumnDefResolved,\n} from '../types'\nimport { getMemoOptions, memo } from '../utils'\n\nexport interface CoreColumn {\n /**\n * The resolved accessor function to use when extracting the value for the column from each row. Will only be defined if the column def has a valid accessor key or function defined.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/core/column#accessorfn)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/column-defs)\n */\n accessorFn?: AccessorFn\n /**\n * The original column def used to create the column.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/core/column#columndef)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/column-defs)\n */\n columnDef: ColumnDef\n /**\n * The child column (if the column is a group column). Will be an empty array if the column is not a group column.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/core/column#columns)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/column-defs)\n */\n columns: Column[]\n /**\n * The depth of the column (if grouped) relative to the root column def array.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/core/column#depth)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/column-defs)\n */\n depth: number\n /**\n * Returns the flattened array of this column and all child/grand-child columns for this column.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/core/column#getflatcolumns)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/column-defs)\n */\n getFlatColumns: () => Column[]\n /**\n * Returns an array of all leaf-node columns for this column. If a column has no children, it is considered the only leaf-node column.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/core/column#getleafcolumns)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/column-defs)\n */\n getLeafColumns: () => Column[]\n /**\n * The resolved unique identifier for the column resolved in this priority:\n - A manual `id` property from the column def\n - The accessor key from the column def\n - The header string from the column def\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/core/column#id)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/column-defs)\n */\n id: string\n /**\n * The parent column for this column. Will be undefined if this is a root column.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/core/column#parent)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/column-defs)\n */\n parent?: Column\n}\n\nexport function createColumn(\n table: Table,\n columnDef: ColumnDef,\n depth: number,\n parent?: Column\n): Column {\n const defaultColumn = table._getDefaultColumnDef()\n\n const resolvedColumnDef = {\n ...defaultColumn,\n ...columnDef,\n } as ColumnDefResolved\n\n const accessorKey = resolvedColumnDef.accessorKey\n\n let id =\n resolvedColumnDef.id ??\n (accessorKey ? accessorKey.replace('.', '_') : undefined) ??\n (typeof resolvedColumnDef.header === 'string'\n ? resolvedColumnDef.header\n : undefined)\n\n let accessorFn: AccessorFn | undefined\n\n if (resolvedColumnDef.accessorFn) {\n accessorFn = resolvedColumnDef.accessorFn\n } else if (accessorKey) {\n // Support deep accessor keys\n if (accessorKey.includes('.')) {\n accessorFn = (originalRow: TData) => {\n let result = originalRow as Record\n\n for (const key of accessorKey.split('.')) {\n result = result?.[key]\n if (process.env.NODE_ENV !== 'production' && result === undefined) {\n console.warn(\n `\"${key}\" in deeply nested key \"${accessorKey}\" returned undefined.`\n )\n }\n }\n\n return result\n }\n } else {\n accessorFn = (originalRow: TData) =>\n (originalRow as any)[resolvedColumnDef.accessorKey]\n }\n }\n\n if (!id) {\n if (process.env.NODE_ENV !== 'production') {\n throw new Error(\n resolvedColumnDef.accessorFn\n ? `Columns require an id when using an accessorFn`\n : `Columns require an id when using a non-string header`\n )\n }\n throw new Error()\n }\n\n let column: CoreColumn = {\n id: `${String(id)}`,\n accessorFn,\n parent: parent as any,\n depth,\n columnDef: resolvedColumnDef as ColumnDef,\n columns: [],\n getFlatColumns: memo(\n () => [true],\n () => {\n return [\n column as Column,\n ...column.columns?.flatMap(d => d.getFlatColumns()),\n ]\n },\n getMemoOptions(table.options, 'debugColumns', 'column.getFlatColumns')\n ),\n getLeafColumns: memo(\n () => [table._getOrderColumnsFn()],\n orderColumns => {\n if (column.columns?.length) {\n let leafColumns = column.columns.flatMap(column =>\n column.getLeafColumns()\n )\n\n return orderColumns(leafColumns)\n }\n\n return [column as Column]\n },\n getMemoOptions(table.options, 'debugColumns', 'column.getLeafColumns')\n ),\n }\n\n for (const feature of table._features) {\n feature.createColumn?.(column as Column, table)\n }\n\n // Yes, we have to convert table to unknown, because we know more than the compiler here.\n return column as Column\n}\n", "import {\n RowData,\n Column,\n Header,\n HeaderGroup,\n Table,\n TableFeature,\n} from '../types'\nimport { getMemoOptions, memo } from '../utils'\n\nconst debug = 'debugHeaders'\n\nexport interface CoreHeaderGroup {\n depth: number\n headers: Header[]\n id: string\n}\n\nexport interface HeaderContext {\n /**\n * An instance of a column.\n */\n column: Column\n /**\n * An instance of a header.\n */\n header: Header\n /**\n * The table instance.\n */\n table: Table\n}\n\nexport interface CoreHeader {\n /**\n * The col-span for the header.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/core/header#colspan)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/headers)\n */\n colSpan: number\n /**\n * The header's associated column object.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/core/header#column)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/headers)\n */\n column: Column\n /**\n * The depth of the header, zero-indexed based.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/core/header#depth)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/headers)\n */\n depth: number\n /**\n * Returns the rendering context (or props) for column-based components like headers, footers and filters.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/core/header#getcontext)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/headers)\n */\n getContext: () => HeaderContext\n /**\n * Returns the leaf headers hierarchically nested under this header.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/core/header#getleafheaders)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/headers)\n */\n getLeafHeaders: () => Header[]\n /**\n * The header's associated header group object.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/core/header#headergroup)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/headers)\n */\n headerGroup: HeaderGroup\n /**\n * The unique identifier for the header.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/core/header#id)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/headers)\n */\n id: string\n /**\n * The index for the header within the header group.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/core/header#index)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/headers)\n */\n index: number\n /**\n * A boolean denoting if the header is a placeholder header.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/core/header#isplaceholder)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/headers)\n */\n isPlaceholder: boolean\n /**\n * If the header is a placeholder header, this will be a unique header ID that does not conflict with any other headers across the table.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/core/header#placeholderid)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/headers)\n */\n placeholderId?: string\n /**\n * The row-span for the header.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/core/header#rowspan)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/headers)\n */\n rowSpan: number\n /**\n * The header's hierarchical sub/child headers. Will be empty if the header's associated column is a leaf-column.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/core/header#subheaders)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/headers)\n */\n subHeaders: Header[]\n}\n\nexport interface HeadersInstance {\n /**\n * Returns all header groups for the table.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/core/headers#getheadergroups)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/headers)\n */\n getHeaderGroups: () => HeaderGroup[]\n /**\n * If pinning, returns the header groups for the left pinned columns.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/core/headers#getleftheadergroups)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/headers)\n */\n getLeftHeaderGroups: () => HeaderGroup[]\n /**\n * If pinning, returns the header groups for columns that are not pinned.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/core/headers#getcenterheadergroups)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/headers)\n */\n getCenterHeaderGroups: () => HeaderGroup[]\n /**\n * If pinning, returns the header groups for the right pinned columns.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/core/headers#getrightheadergroups)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/headers)\n */\n getRightHeaderGroups: () => HeaderGroup[]\n\n /**\n * Returns the footer groups for the table.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/core/headers#getfootergroups)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/headers)\n */\n getFooterGroups: () => HeaderGroup[]\n /**\n * If pinning, returns the footer groups for the left pinned columns.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/core/headers#getleftfootergroups)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/headers)\n */\n getLeftFooterGroups: () => HeaderGroup[]\n /**\n * If pinning, returns the footer groups for columns that are not pinned.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/core/headers#getcenterfootergroups)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/headers)\n */\n getCenterFooterGroups: () => HeaderGroup[]\n /**\n * If pinning, returns the footer groups for the right pinned columns.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/core/headers#getrightfootergroups)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/headers)\n */\n getRightFooterGroups: () => HeaderGroup[]\n\n /**\n * Returns headers for all columns in the table, including parent headers.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/core/headers#getflatheaders)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/headers)\n */\n getFlatHeaders: () => Header[]\n /**\n * If pinning, returns headers for all left pinned columns in the table, including parent headers.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/core/headers#getleftflatheaders)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/headers)\n */\n getLeftFlatHeaders: () => Header[]\n /**\n * If pinning, returns headers for all columns that are not pinned, including parent headers.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/core/headers#getcenterflatheaders)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/headers)\n */\n getCenterFlatHeaders: () => Header[]\n /**\n * If pinning, returns headers for all right pinned columns in the table, including parent headers.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/core/headers#getrightflatheaders)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/headers)\n */\n getRightFlatHeaders: () => Header[]\n\n /**\n * Returns headers for all leaf columns in the table, (not including parent headers).\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/core/headers#getleafheaders)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/headers)\n */\n getLeafHeaders: () => Header[]\n /**\n * If pinning, returns headers for all left pinned leaf columns in the table, (not including parent headers).\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/core/headers#getleftleafheaders)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/headers)\n */\n getLeftLeafHeaders: () => Header[]\n /**\n * If pinning, returns headers for all columns that are not pinned, (not including parent headers).\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/core/headers#getcenterleafheaders)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/headers)\n */\n getCenterLeafHeaders: () => Header[]\n /**\n * If pinning, returns headers for all right pinned leaf columns in the table, (not including parent headers).\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/core/headers#getrightleafheaders)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/headers)\n */\n getRightLeafHeaders: () => Header[]\n}\n\n//\n\nfunction createHeader(\n table: Table,\n column: Column,\n options: {\n id?: string\n isPlaceholder?: boolean\n placeholderId?: string\n index: number\n depth: number\n }\n): Header {\n const id = options.id ?? column.id\n\n let header: CoreHeader = {\n id,\n column,\n index: options.index,\n isPlaceholder: !!options.isPlaceholder,\n placeholderId: options.placeholderId,\n depth: options.depth,\n subHeaders: [],\n colSpan: 0,\n rowSpan: 0,\n headerGroup: null!,\n getLeafHeaders: (): Header[] => {\n const leafHeaders: Header[] = []\n\n const recurseHeader = (h: CoreHeader) => {\n if (h.subHeaders && h.subHeaders.length) {\n h.subHeaders.map(recurseHeader)\n }\n leafHeaders.push(h as Header)\n }\n\n recurseHeader(header)\n\n return leafHeaders\n },\n getContext: () => ({\n table,\n header: header as Header,\n column,\n }),\n }\n\n table._features.forEach(feature => {\n feature.createHeader?.(header as Header, table)\n })\n\n return header as Header\n}\n\nexport const Headers: TableFeature = {\n createTable: (table: Table): void => {\n // Header Groups\n\n table.getHeaderGroups = memo(\n () => [\n table.getAllColumns(),\n table.getVisibleLeafColumns(),\n table.getState().columnPinning.left,\n table.getState().columnPinning.right,\n ],\n (allColumns, leafColumns, left, right) => {\n const leftColumns =\n left\n ?.map(columnId => leafColumns.find(d => d.id === columnId)!)\n .filter(Boolean) ?? []\n\n const rightColumns =\n right\n ?.map(columnId => leafColumns.find(d => d.id === columnId)!)\n .filter(Boolean) ?? []\n\n const centerColumns = leafColumns.filter(\n column => !left?.includes(column.id) && !right?.includes(column.id)\n )\n\n const headerGroups = buildHeaderGroups(\n allColumns,\n [...leftColumns, ...centerColumns, ...rightColumns],\n table\n )\n\n return headerGroups\n },\n getMemoOptions(table.options, debug, 'getHeaderGroups')\n )\n\n table.getCenterHeaderGroups = memo(\n () => [\n table.getAllColumns(),\n table.getVisibleLeafColumns(),\n table.getState().columnPinning.left,\n table.getState().columnPinning.right,\n ],\n (allColumns, leafColumns, left, right) => {\n leafColumns = leafColumns.filter(\n column => !left?.includes(column.id) && !right?.includes(column.id)\n )\n return buildHeaderGroups(allColumns, leafColumns, table, 'center')\n },\n getMemoOptions(table.options, debug, 'getCenterHeaderGroups')\n )\n\n table.getLeftHeaderGroups = memo(\n () => [\n table.getAllColumns(),\n table.getVisibleLeafColumns(),\n table.getState().columnPinning.left,\n ],\n (allColumns, leafColumns, left) => {\n const orderedLeafColumns =\n left\n ?.map(columnId => leafColumns.find(d => d.id === columnId)!)\n .filter(Boolean) ?? []\n\n return buildHeaderGroups(allColumns, orderedLeafColumns, table, 'left')\n },\n getMemoOptions(table.options, debug, 'getLeftHeaderGroups')\n )\n\n table.getRightHeaderGroups = memo(\n () => [\n table.getAllColumns(),\n table.getVisibleLeafColumns(),\n table.getState().columnPinning.right,\n ],\n (allColumns, leafColumns, right) => {\n const orderedLeafColumns =\n right\n ?.map(columnId => leafColumns.find(d => d.id === columnId)!)\n .filter(Boolean) ?? []\n\n return buildHeaderGroups(allColumns, orderedLeafColumns, table, 'right')\n },\n getMemoOptions(table.options, debug, 'getRightHeaderGroups')\n )\n\n // Footer Groups\n\n table.getFooterGroups = memo(\n () => [table.getHeaderGroups()],\n headerGroups => {\n return [...headerGroups].reverse()\n },\n getMemoOptions(table.options, debug, 'getFooterGroups')\n )\n\n table.getLeftFooterGroups = memo(\n () => [table.getLeftHeaderGroups()],\n headerGroups => {\n return [...headerGroups].reverse()\n },\n getMemoOptions(table.options, debug, 'getLeftFooterGroups')\n )\n\n table.getCenterFooterGroups = memo(\n () => [table.getCenterHeaderGroups()],\n headerGroups => {\n return [...headerGroups].reverse()\n },\n getMemoOptions(table.options, debug, 'getCenterFooterGroups')\n )\n\n table.getRightFooterGroups = memo(\n () => [table.getRightHeaderGroups()],\n headerGroups => {\n return [...headerGroups].reverse()\n },\n getMemoOptions(table.options, debug, 'getRightFooterGroups')\n )\n\n // Flat Headers\n\n table.getFlatHeaders = memo(\n () => [table.getHeaderGroups()],\n headerGroups => {\n return headerGroups\n .map(headerGroup => {\n return headerGroup.headers\n })\n .flat()\n },\n getMemoOptions(table.options, debug, 'getFlatHeaders')\n )\n\n table.getLeftFlatHeaders = memo(\n () => [table.getLeftHeaderGroups()],\n left => {\n return left\n .map(headerGroup => {\n return headerGroup.headers\n })\n .flat()\n },\n getMemoOptions(table.options, debug, 'getLeftFlatHeaders')\n )\n\n table.getCenterFlatHeaders = memo(\n () => [table.getCenterHeaderGroups()],\n left => {\n return left\n .map(headerGroup => {\n return headerGroup.headers\n })\n .flat()\n },\n getMemoOptions(table.options, debug, 'getCenterFlatHeaders')\n )\n\n table.getRightFlatHeaders = memo(\n () => [table.getRightHeaderGroups()],\n left => {\n return left\n .map(headerGroup => {\n return headerGroup.headers\n })\n .flat()\n },\n getMemoOptions(table.options, debug, 'getRightFlatHeaders')\n )\n\n // Leaf Headers\n\n table.getCenterLeafHeaders = memo(\n () => [table.getCenterFlatHeaders()],\n flatHeaders => {\n return flatHeaders.filter(header => !header.subHeaders?.length)\n },\n getMemoOptions(table.options, debug, 'getCenterLeafHeaders')\n )\n\n table.getLeftLeafHeaders = memo(\n () => [table.getLeftFlatHeaders()],\n flatHeaders => {\n return flatHeaders.filter(header => !header.subHeaders?.length)\n },\n getMemoOptions(table.options, debug, 'getLeftLeafHeaders')\n )\n\n table.getRightLeafHeaders = memo(\n () => [table.getRightFlatHeaders()],\n flatHeaders => {\n return flatHeaders.filter(header => !header.subHeaders?.length)\n },\n getMemoOptions(table.options, debug, 'getRightLeafHeaders')\n )\n\n table.getLeafHeaders = memo(\n () => [\n table.getLeftHeaderGroups(),\n table.getCenterHeaderGroups(),\n table.getRightHeaderGroups(),\n ],\n (left, center, right) => {\n return [\n ...(left[0]?.headers ?? []),\n ...(center[0]?.headers ?? []),\n ...(right[0]?.headers ?? []),\n ]\n .map(header => {\n return header.getLeafHeaders()\n })\n .flat()\n },\n getMemoOptions(table.options, debug, 'getLeafHeaders')\n )\n },\n}\n\nexport function buildHeaderGroups(\n allColumns: Column[],\n columnsToGroup: Column[],\n table: Table,\n headerFamily?: 'center' | 'left' | 'right'\n) {\n // Find the max depth of the columns:\n // build the leaf column row\n // build each buffer row going up\n // placeholder for non-existent level\n // real column for existing level\n\n let maxDepth = 0\n\n const findMaxDepth = (columns: Column[], depth = 1) => {\n maxDepth = Math.max(maxDepth, depth)\n\n columns\n .filter(column => column.getIsVisible())\n .forEach(column => {\n if (column.columns?.length) {\n findMaxDepth(column.columns, depth + 1)\n }\n }, 0)\n }\n\n findMaxDepth(allColumns)\n\n let headerGroups: HeaderGroup[] = []\n\n const createHeaderGroup = (\n headersToGroup: Header[],\n depth: number\n ) => {\n // The header group we are creating\n const headerGroup: HeaderGroup = {\n depth,\n id: [headerFamily, `${depth}`].filter(Boolean).join('_'),\n headers: [],\n }\n\n // The parent columns we're going to scan next\n const pendingParentHeaders: Header[] = []\n\n // Scan each column for parents\n headersToGroup.forEach(headerToGroup => {\n // What is the latest (last) parent column?\n\n const latestPendingParentHeader = [...pendingParentHeaders].reverse()[0]\n\n const isLeafHeader = headerToGroup.column.depth === headerGroup.depth\n\n let column: Column\n let isPlaceholder = false\n\n if (isLeafHeader && headerToGroup.column.parent) {\n // The parent header is new\n column = headerToGroup.column.parent\n } else {\n // The parent header is repeated\n column = headerToGroup.column\n isPlaceholder = true\n }\n\n if (\n latestPendingParentHeader &&\n latestPendingParentHeader?.column === column\n ) {\n // This column is repeated. Add it as a sub header to the next batch\n latestPendingParentHeader.subHeaders.push(headerToGroup)\n } else {\n // This is a new header. Let's create it\n const header = createHeader(table, column, {\n id: [headerFamily, depth, column.id, headerToGroup?.id]\n .filter(Boolean)\n .join('_'),\n isPlaceholder,\n placeholderId: isPlaceholder\n ? `${pendingParentHeaders.filter(d => d.column === column).length}`\n : undefined,\n depth,\n index: pendingParentHeaders.length,\n })\n\n // Add the headerToGroup as a subHeader of the new header\n header.subHeaders.push(headerToGroup)\n // Add the new header to the pendingParentHeaders to get grouped\n // in the next batch\n pendingParentHeaders.push(header)\n }\n\n headerGroup.headers.push(headerToGroup)\n headerToGroup.headerGroup = headerGroup\n })\n\n headerGroups.push(headerGroup)\n\n if (depth > 0) {\n createHeaderGroup(pendingParentHeaders, depth - 1)\n }\n }\n\n const bottomHeaders = columnsToGroup.map((column, index) =>\n createHeader(table, column, {\n depth: maxDepth,\n index,\n })\n )\n\n createHeaderGroup(bottomHeaders, maxDepth - 1)\n\n headerGroups.reverse()\n\n // headerGroups = headerGroups.filter(headerGroup => {\n // return !headerGroup.headers.every(header => header.isPlaceholder)\n // })\n\n const recurseHeadersForSpans = (\n headers: Header[]\n ): { colSpan: number; rowSpan: number }[] => {\n const filteredHeaders = headers.filter(header =>\n header.column.getIsVisible()\n )\n\n return filteredHeaders.map(header => {\n let colSpan = 0\n let rowSpan = 0\n let childRowSpans = [0]\n\n if (header.subHeaders && header.subHeaders.length) {\n childRowSpans = []\n\n recurseHeadersForSpans(header.subHeaders).forEach(\n ({ colSpan: childColSpan, rowSpan: childRowSpan }) => {\n colSpan += childColSpan\n childRowSpans.push(childRowSpan)\n }\n )\n } else {\n colSpan = 1\n }\n\n const minChildRowSpan = Math.min(...childRowSpans)\n rowSpan = rowSpan + minChildRowSpan\n\n header.colSpan = colSpan\n header.rowSpan = rowSpan\n\n return { colSpan, rowSpan }\n })\n }\n\n recurseHeadersForSpans(headerGroups[0]?.headers ?? [])\n\n return headerGroups\n}\n", "import { RowData, Cell, Row, Table } from '../types'\nimport { flattenBy, getMemoOptions, memo } from '../utils'\nimport { createCell } from './cell'\n\nexport interface CoreRow {\n _getAllCellsByColumnId: () => Record>\n _uniqueValuesCache: Record\n _valuesCache: Record\n /**\n * The depth of the row (if nested or grouped) relative to the root row array.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/core/row#depth)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/rows)\n */\n depth: number\n /**\n * Returns all of the cells for the row.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/core/row#getallcells)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/rows)\n */\n getAllCells: () => Cell[]\n /**\n * Returns the leaf rows for the row, not including any parent rows.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/core/row#getleafrows)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/rows)\n */\n getLeafRows: () => Row[]\n /**\n * Returns the parent row for the row, if it exists.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/core/row#getparentrow)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/rows)\n */\n getParentRow: () => Row | undefined\n /**\n * Returns the parent rows for the row, all the way up to a root row.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/core/row#getparentrows)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/rows)\n */\n getParentRows: () => Row[]\n /**\n * Returns a unique array of values from the row for a given columnId.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/core/row#getuniquevalues)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/rows)\n */\n getUniqueValues: (columnId: string) => TValue[]\n /**\n * Returns the value from the row for a given columnId.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/core/row#getvalue)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/rows)\n */\n getValue: (columnId: string) => TValue\n /**\n * The resolved unique identifier for the row resolved via the `options.getRowId` option. Defaults to the row's index (or relative index if it is a subRow).\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/core/row#id)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/rows)\n */\n id: string\n /**\n * The index of the row within its parent array (or the root data array).\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/core/row#index)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/rows)\n */\n index: number\n /**\n * The original row object provided to the table. If the row is a grouped row, the original row object will be the first original in the group.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/core/row#original)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/rows)\n */\n original: TData\n /**\n * An array of the original subRows as returned by the `options.getSubRows` option.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/core/row#originalsubrows)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/rows)\n */\n originalSubRows?: TData[]\n /**\n * If nested, this row's parent row id.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/core/row#parentid)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/rows)\n */\n parentId?: string\n /**\n * Renders the value for the row in a given columnId the same as `getValue`, but will return the `renderFallbackValue` if no value is found.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/core/row#rendervalue)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/rows)\n */\n renderValue: (columnId: string) => TValue\n /**\n * An array of subRows for the row as returned and created by the `options.getSubRows` option.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/core/row#subrows)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/rows)\n */\n subRows: Row[]\n}\n\nexport const createRow = (\n table: Table,\n id: string,\n original: TData,\n rowIndex: number,\n depth: number,\n subRows?: Row[],\n parentId?: string\n): Row => {\n let row: CoreRow = {\n id,\n index: rowIndex,\n original,\n depth,\n parentId,\n _valuesCache: {},\n _uniqueValuesCache: {},\n getValue: columnId => {\n if (row._valuesCache.hasOwnProperty(columnId)) {\n return row._valuesCache[columnId]\n }\n\n const column = table.getColumn(columnId)\n\n if (!column?.accessorFn) {\n return undefined\n }\n\n row._valuesCache[columnId] = column.accessorFn(\n row.original as TData,\n rowIndex\n )\n\n return row._valuesCache[columnId] as any\n },\n getUniqueValues: columnId => {\n if (row._uniqueValuesCache.hasOwnProperty(columnId)) {\n return row._uniqueValuesCache[columnId]\n }\n\n const column = table.getColumn(columnId)\n\n if (!column?.accessorFn) {\n return undefined\n }\n\n if (!column.columnDef.getUniqueValues) {\n row._uniqueValuesCache[columnId] = [row.getValue(columnId)]\n return row._uniqueValuesCache[columnId]\n }\n\n row._uniqueValuesCache[columnId] = column.columnDef.getUniqueValues(\n row.original as TData,\n rowIndex\n )\n\n return row._uniqueValuesCache[columnId] as any\n },\n renderValue: columnId =>\n row.getValue(columnId) ?? table.options.renderFallbackValue,\n subRows: subRows ?? [],\n getLeafRows: () => flattenBy(row.subRows, d => d.subRows),\n getParentRow: () =>\n row.parentId ? table.getRow(row.parentId, true) : undefined,\n getParentRows: () => {\n let parentRows: Row[] = []\n let currentRow = row\n while (true) {\n const parentRow = currentRow.getParentRow()\n if (!parentRow) break\n parentRows.push(parentRow)\n currentRow = parentRow\n }\n return parentRows.reverse()\n },\n getAllCells: memo(\n () => [table.getAllLeafColumns()],\n leafColumns => {\n return leafColumns.map(column => {\n return createCell(table, row as Row, column, column.id)\n })\n },\n getMemoOptions(table.options, 'debugRows', 'getAllCells')\n ),\n\n _getAllCellsByColumnId: memo(\n () => [row.getAllCells()],\n allCells => {\n return allCells.reduce(\n (acc, cell) => {\n acc[cell.column.id] = cell\n return acc\n },\n {} as Record>\n )\n },\n getMemoOptions(table.options, 'debugRows', 'getAllCellsByColumnId')\n ),\n }\n\n for (let i = 0; i < table._features.length; i++) {\n const feature = table._features[i]\n feature?.createRow?.(row as Row, table)\n }\n\n return row as Row\n}\n", "import { RowModel } from '..'\nimport { Column, RowData, Table, TableFeature } from '../types'\n\nexport interface FacetedColumn {\n _getFacetedMinMaxValues?: () => undefined | [number, number]\n _getFacetedRowModel?: () => RowModel\n _getFacetedUniqueValues?: () => Map\n /**\n * A function that **computes and returns** a min/max tuple derived from `column.getFacetedRowModel`. Useful for displaying faceted result values.\n * > ⚠️ Requires that you pass a valid `getFacetedMinMaxValues` function to `options.getFacetedMinMaxValues`. A default implementation is provided via the exported `getFacetedMinMaxValues` function.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/column-faceting#getfacetedminmaxvalues)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/column-faceting)\n */\n getFacetedMinMaxValues: () => undefined | [number, number]\n /**\n * Returns the row model with all other column filters applied, excluding its own filter. Useful for displaying faceted result counts.\n * > ⚠️ Requires that you pass a valid `getFacetedRowModel` function to `options.facetedRowModel`. A default implementation is provided via the exported `getFacetedRowModel` function.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/column-faceting#getfacetedrowmodel)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/column-faceting)\n */\n getFacetedRowModel: () => RowModel\n /**\n * A function that **computes and returns** a `Map` of unique values and their occurrences derived from `column.getFacetedRowModel`. Useful for displaying faceted result values.\n * > ⚠️ Requires that you pass a valid `getFacetedUniqueValues` function to `options.getFacetedUniqueValues`. A default implementation is provided via the exported `getFacetedUniqueValues` function.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/column-faceting#getfaceteduniquevalues)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/column-faceting)\n */\n getFacetedUniqueValues: () => Map\n}\n\nexport interface FacetedOptions {\n getFacetedMinMaxValues?: (\n table: Table,\n columnId: string\n ) => () => undefined | [number, number]\n getFacetedRowModel?: (\n table: Table,\n columnId: string\n ) => () => RowModel\n getFacetedUniqueValues?: (\n table: Table,\n columnId: string\n ) => () => Map\n}\n\n//\n\nexport const ColumnFaceting: TableFeature = {\n createColumn: (\n column: Column,\n table: Table\n ): void => {\n column._getFacetedRowModel =\n table.options.getFacetedRowModel &&\n table.options.getFacetedRowModel(table, column.id)\n column.getFacetedRowModel = () => {\n if (!column._getFacetedRowModel) {\n return table.getPreFilteredRowModel()\n }\n\n return column._getFacetedRowModel()\n }\n column._getFacetedUniqueValues =\n table.options.getFacetedUniqueValues &&\n table.options.getFacetedUniqueValues(table, column.id)\n column.getFacetedUniqueValues = () => {\n if (!column._getFacetedUniqueValues) {\n return new Map()\n }\n\n return column._getFacetedUniqueValues()\n }\n column._getFacetedMinMaxValues =\n table.options.getFacetedMinMaxValues &&\n table.options.getFacetedMinMaxValues(table, column.id)\n column.getFacetedMinMaxValues = () => {\n if (!column._getFacetedMinMaxValues) {\n return undefined\n }\n\n return column._getFacetedMinMaxValues()\n }\n },\n}\n", "import { FilterFn } from './features/ColumnFiltering'\n\nconst includesString: FilterFn = (\n row,\n columnId: string,\n filterValue: string\n) => {\n const search = filterValue.toLowerCase()\n return Boolean(\n row\n .getValue(columnId)\n ?.toString()\n ?.toLowerCase()\n ?.includes(search)\n )\n}\n\nincludesString.autoRemove = (val: any) => testFalsey(val)\n\nconst includesStringSensitive: FilterFn = (\n row,\n columnId: string,\n filterValue: string\n) => {\n return Boolean(\n row.getValue(columnId)?.toString()?.includes(filterValue)\n )\n}\n\nincludesStringSensitive.autoRemove = (val: any) => testFalsey(val)\n\nconst equalsString: FilterFn = (\n row,\n columnId: string,\n filterValue: string\n) => {\n return (\n row.getValue(columnId)?.toString()?.toLowerCase() ===\n filterValue?.toLowerCase()\n )\n}\n\nequalsString.autoRemove = (val: any) => testFalsey(val)\n\nconst arrIncludes: FilterFn = (\n row,\n columnId: string,\n filterValue: unknown\n) => {\n return row.getValue(columnId)?.includes(filterValue)\n}\n\narrIncludes.autoRemove = (val: any) => testFalsey(val) || !val?.length\n\nconst arrIncludesAll: FilterFn = (\n row,\n columnId: string,\n filterValue: unknown[]\n) => {\n return !filterValue.some(\n val => !row.getValue(columnId)?.includes(val)\n )\n}\n\narrIncludesAll.autoRemove = (val: any) => testFalsey(val) || !val?.length\n\nconst arrIncludesSome: FilterFn = (\n row,\n columnId: string,\n filterValue: unknown[]\n) => {\n return filterValue.some(val =>\n row.getValue(columnId)?.includes(val)\n )\n}\n\narrIncludesSome.autoRemove = (val: any) => testFalsey(val) || !val?.length\n\nconst equals: FilterFn = (row, columnId: string, filterValue: unknown) => {\n return row.getValue(columnId) === filterValue\n}\n\nequals.autoRemove = (val: any) => testFalsey(val)\n\nconst weakEquals: FilterFn = (\n row,\n columnId: string,\n filterValue: unknown\n) => {\n return row.getValue(columnId) == filterValue\n}\n\nweakEquals.autoRemove = (val: any) => testFalsey(val)\n\nconst inNumberRange: FilterFn = (\n row,\n columnId: string,\n filterValue: [number, number]\n) => {\n let [min, max] = filterValue\n\n const rowValue = row.getValue(columnId)\n return rowValue >= min && rowValue <= max\n}\n\ninNumberRange.resolveFilterValue = (val: [any, any]) => {\n let [unsafeMin, unsafeMax] = val\n\n let parsedMin =\n typeof unsafeMin !== 'number' ? parseFloat(unsafeMin as string) : unsafeMin\n let parsedMax =\n typeof unsafeMax !== 'number' ? parseFloat(unsafeMax as string) : unsafeMax\n\n let min =\n unsafeMin === null || Number.isNaN(parsedMin) ? -Infinity : parsedMin\n let max = unsafeMax === null || Number.isNaN(parsedMax) ? Infinity : parsedMax\n\n if (min > max) {\n const temp = min\n min = max\n max = temp\n }\n\n return [min, max] as const\n}\n\ninNumberRange.autoRemove = (val: any) =>\n testFalsey(val) || (testFalsey(val[0]) && testFalsey(val[1]))\n\n// Export\n\nexport const filterFns = {\n includesString,\n includesStringSensitive,\n equalsString,\n arrIncludes,\n arrIncludesAll,\n arrIncludesSome,\n equals,\n weakEquals,\n inNumberRange,\n}\n\nexport type BuiltInFilterFn = keyof typeof filterFns\n\n// Utils\n\nfunction testFalsey(val: any) {\n return val === undefined || val === null || val === ''\n}\n", "import { RowModel } from '..'\nimport { BuiltInFilterFn, filterFns } from '../filterFns'\nimport {\n Column,\n FilterFns,\n FilterMeta,\n OnChangeFn,\n Row,\n RowData,\n Table,\n TableFeature,\n Updater,\n} from '../types'\nimport { functionalUpdate, isFunction, makeStateUpdater } from '../utils'\n\nexport interface ColumnFiltersTableState {\n columnFilters: ColumnFiltersState\n}\n\nexport type ColumnFiltersState = ColumnFilter[]\n\nexport interface ColumnFilter {\n id: string\n value: unknown\n}\n\nexport interface ResolvedColumnFilter {\n filterFn: FilterFn\n id: string\n resolvedValue: unknown\n}\n\nexport interface FilterFn {\n (\n row: Row,\n columnId: string,\n filterValue: any,\n addMeta: (meta: FilterMeta) => void\n ): boolean\n autoRemove?: ColumnFilterAutoRemoveTestFn\n resolveFilterValue?: TransformFilterValueFn\n}\n\nexport type TransformFilterValueFn = (\n value: any,\n column?: Column\n) => unknown\n\nexport type ColumnFilterAutoRemoveTestFn = (\n value: any,\n column?: Column\n) => boolean\n\nexport type CustomFilterFns = Record<\n string,\n FilterFn\n>\n\nexport type FilterFnOption =\n | 'auto'\n | BuiltInFilterFn\n | keyof FilterFns\n | FilterFn\n\nexport interface ColumnFiltersColumnDef {\n /**\n * Enables/disables the **column** filter for this column.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/column-filtering#enablecolumnfilter)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/column-filtering)\n */\n enableColumnFilter?: boolean\n /**\n * The filter function to use with this column. Can be the name of a built-in filter function or a custom filter function.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/column-filtering#filterfn)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/column-filtering)\n */\n filterFn?: FilterFnOption\n}\n\nexport interface ColumnFiltersColumn {\n /**\n * Returns an automatically calculated filter function for the column based off of the columns first known value.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/column-filtering#getautofilterfn)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/column-filtering)\n */\n getAutoFilterFn: () => FilterFn | undefined\n /**\n * Returns whether or not the column can be **column** filtered.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/column-filtering#getcanfilter)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/column-filtering)\n */\n getCanFilter: () => boolean\n /**\n * Returns the filter function (either user-defined or automatic, depending on configuration) for the columnId specified.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/column-filtering#getfilterfn)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/column-filtering)\n */\n getFilterFn: () => FilterFn | undefined\n /**\n * Returns the index (including `-1`) of the column filter in the table's `state.columnFilters` array.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/column-filtering#getfilterindex)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/column-filtering)\n */\n getFilterIndex: () => number\n /**\n * Returns the current filter value for the column.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/column-filtering#getfiltervalue)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/column-filtering)\n */\n getFilterValue: () => unknown\n /**\n * Returns whether or not the column is currently filtered.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/column-filtering#getisfiltered)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/column-filtering)\n */\n getIsFiltered: () => boolean\n /**\n * A function that sets the current filter value for the column. You can pass it a value or an updater function for immutability-safe operations on existing values.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/column-filtering#setfiltervalue)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/column-filtering)\n */\n setFilterValue: (updater: Updater) => void\n}\n\nexport interface ColumnFiltersRow {\n /**\n * The column filters map for the row. This object tracks whether a row is passing/failing specific filters by their column ID.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/column-filtering#columnfilters)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/column-filtering)\n */\n columnFilters: Record\n /**\n * The column filters meta map for the row. This object tracks any filter meta for a row as optionally provided during the filtering process.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/column-filtering#columnfiltersmeta)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/column-filtering)\n */\n columnFiltersMeta: Record\n}\n\ninterface ColumnFiltersOptionsBase {\n /**\n * Enables/disables **column** filtering for all columns.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/column-filtering#enablecolumnfilters)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/column-filtering)\n */\n enableColumnFilters?: boolean\n /**\n * Enables/disables all filtering for the table.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/column-filtering#enablefilters)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/column-filtering)\n */\n enableFilters?: boolean\n /**\n * By default, filtering is done from parent rows down (so if a parent row is filtered out, all of its children will be filtered out as well). Setting this option to `true` will cause filtering to be done from leaf rows up (which means parent rows will be included so long as one of their child or grand-child rows is also included).\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/column-filtering#filterfromleafrows)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/column-filtering)\n */\n filterFromLeafRows?: boolean\n /**\n * If provided, this function is called **once** per table and should return a **new function** which will calculate and return the row model for the table when it's filtered.\n * - For server-side filtering, this function is unnecessary and can be ignored since the server should already return the filtered row model.\n * - For client-side filtering, this function is required. A default implementation is provided via any table adapter's `{ getFilteredRowModel }` export.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/column-filtering#getfilteredrowmodel)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/column-filtering)\n */\n getFilteredRowModel?: (table: Table) => () => RowModel\n /**\n * Disables the `getFilteredRowModel` from being used to filter data. This may be useful if your table needs to dynamically support both client-side and server-side filtering.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/column-filtering#manualfiltering)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/column-filtering)\n */\n manualFiltering?: boolean\n /**\n * By default, filtering is done for all rows (max depth of 100), no matter if they are root level parent rows or the child leaf rows of a parent row. Setting this option to `0` will cause filtering to only be applied to the root level parent rows, with all sub-rows remaining unfiltered. Similarly, setting this option to `1` will cause filtering to only be applied to child leaf rows 1 level deep, and so on.\n\n * This is useful for situations where you want a row's entire child hierarchy to be visible regardless of the applied filter.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/column-filtering#maxleafrowfilterdepth)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/column-filtering)\n */\n maxLeafRowFilterDepth?: number\n /**\n * If provided, this function will be called with an `updaterFn` when `state.columnFilters` changes. This overrides the default internal state management, so you will need to persist the state change either fully or partially outside of the table.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/column-filtering#oncolumnfilterschange)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/column-filtering)\n */\n onColumnFiltersChange?: OnChangeFn\n}\n\ntype ResolvedFilterFns = keyof FilterFns extends never\n ? {\n filterFns?: Record>\n }\n : {\n filterFns: Record>\n }\n\nexport interface ColumnFiltersOptions\n extends ColumnFiltersOptionsBase,\n ResolvedFilterFns {}\n\nexport interface ColumnFiltersInstance {\n _getFilteredRowModel?: () => RowModel\n /**\n * Returns the row model for the table after **column** filtering has been applied.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/column-filtering#getfilteredrowmodel)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/column-filtering)\n */\n getFilteredRowModel: () => RowModel\n /**\n * Returns the row model for the table before any **column** filtering has been applied.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/column-filtering#getprefilteredrowmodel)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/column-filtering)\n */\n getPreFilteredRowModel: () => RowModel\n /**\n * Resets the **columnFilters** state to `initialState.columnFilters`, or `true` can be passed to force a default blank state reset to `[]`.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/column-filtering#resetcolumnfilters)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/column-filtering)\n */\n resetColumnFilters: (defaultState?: boolean) => void\n /**\n * Resets the **globalFilter** state to `initialState.globalFilter`, or `true` can be passed to force a default blank state reset to `undefined`.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/column-filtering#resetglobalfilter)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/column-filtering)\n */\n resetGlobalFilter: (defaultState?: boolean) => void\n /**\n * Sets or updates the `state.columnFilters` state.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/column-filtering#setcolumnfilters)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/column-filtering)\n */\n setColumnFilters: (updater: Updater) => void\n /**\n * Sets or updates the `state.globalFilter` state.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/column-filtering#setglobalfilter)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/column-filtering)\n */\n setGlobalFilter: (updater: Updater) => void\n}\n\n//\n\nexport const ColumnFiltering: TableFeature = {\n getDefaultColumnDef: <\n TData extends RowData,\n >(): ColumnFiltersColumnDef => {\n return {\n filterFn: 'auto',\n }\n },\n\n getInitialState: (state): ColumnFiltersTableState => {\n return {\n columnFilters: [],\n ...state,\n }\n },\n\n getDefaultOptions: (\n table: Table\n ): ColumnFiltersOptions => {\n return {\n onColumnFiltersChange: makeStateUpdater('columnFilters', table),\n filterFromLeafRows: false,\n maxLeafRowFilterDepth: 100,\n } as ColumnFiltersOptions\n },\n\n createColumn: (\n column: Column,\n table: Table\n ): void => {\n column.getAutoFilterFn = () => {\n const firstRow = table.getCoreRowModel().flatRows[0]\n\n const value = firstRow?.getValue(column.id)\n\n if (typeof value === 'string') {\n return filterFns.includesString\n }\n\n if (typeof value === 'number') {\n return filterFns.inNumberRange\n }\n\n if (typeof value === 'boolean') {\n return filterFns.equals\n }\n\n if (value !== null && typeof value === 'object') {\n return filterFns.equals\n }\n\n if (Array.isArray(value)) {\n return filterFns.arrIncludes\n }\n\n return filterFns.weakEquals\n }\n column.getFilterFn = () => {\n return isFunction(column.columnDef.filterFn)\n ? column.columnDef.filterFn\n : column.columnDef.filterFn === 'auto'\n ? column.getAutoFilterFn()\n : // @ts-ignore\n table.options.filterFns?.[column.columnDef.filterFn as string] ??\n filterFns[column.columnDef.filterFn as BuiltInFilterFn]\n }\n column.getCanFilter = () => {\n return (\n (column.columnDef.enableColumnFilter ?? true) &&\n (table.options.enableColumnFilters ?? true) &&\n (table.options.enableFilters ?? true) &&\n !!column.accessorFn\n )\n }\n\n column.getIsFiltered = () => column.getFilterIndex() > -1\n\n column.getFilterValue = () =>\n table.getState().columnFilters?.find(d => d.id === column.id)?.value\n\n column.getFilterIndex = () =>\n table.getState().columnFilters?.findIndex(d => d.id === column.id) ?? -1\n\n column.setFilterValue = value => {\n table.setColumnFilters(old => {\n const filterFn = column.getFilterFn()\n const previousFilter = old?.find(d => d.id === column.id)\n\n const newFilter = functionalUpdate(\n value,\n previousFilter ? previousFilter.value : undefined\n )\n\n //\n if (\n shouldAutoRemoveFilter(filterFn as FilterFn, newFilter, column)\n ) {\n return old?.filter(d => d.id !== column.id) ?? []\n }\n\n const newFilterObj = { id: column.id, value: newFilter }\n\n if (previousFilter) {\n return (\n old?.map(d => {\n if (d.id === column.id) {\n return newFilterObj\n }\n return d\n }) ?? []\n )\n }\n\n if (old?.length) {\n return [...old, newFilterObj]\n }\n\n return [newFilterObj]\n })\n }\n },\n\n createRow: (\n row: Row,\n _table: Table\n ): void => {\n row.columnFilters = {}\n row.columnFiltersMeta = {}\n },\n\n createTable: (table: Table): void => {\n table.setColumnFilters = (updater: Updater) => {\n const leafColumns = table.getAllLeafColumns()\n\n const updateFn = (old: ColumnFiltersState) => {\n return functionalUpdate(updater, old)?.filter(filter => {\n const column = leafColumns.find(d => d.id === filter.id)\n\n if (column) {\n const filterFn = column.getFilterFn()\n\n if (shouldAutoRemoveFilter(filterFn, filter.value, column)) {\n return false\n }\n }\n\n return true\n })\n }\n\n table.options.onColumnFiltersChange?.(updateFn)\n }\n\n table.resetColumnFilters = defaultState => {\n table.setColumnFilters(\n defaultState ? [] : table.initialState?.columnFilters ?? []\n )\n }\n\n table.getPreFilteredRowModel = () => table.getCoreRowModel()\n table.getFilteredRowModel = () => {\n if (!table._getFilteredRowModel && table.options.getFilteredRowModel) {\n table._getFilteredRowModel = table.options.getFilteredRowModel(table)\n }\n\n if (table.options.manualFiltering || !table._getFilteredRowModel) {\n return table.getPreFilteredRowModel()\n }\n\n return table._getFilteredRowModel()\n }\n },\n}\n\nexport function shouldAutoRemoveFilter(\n filterFn?: FilterFn,\n value?: any,\n column?: Column\n) {\n return (\n (filterFn && filterFn.autoRemove\n ? filterFn.autoRemove(value, column)\n : false) ||\n typeof value === 'undefined' ||\n (typeof value === 'string' && !value)\n )\n}\n", "import { AggregationFn } from './features/ColumnGrouping'\nimport { isNumberArray } from './utils'\n\nconst sum: AggregationFn = (columnId, _leafRows, childRows) => {\n // It's faster to just add the aggregations together instead of\n // process leaf nodes individually\n return childRows.reduce((sum, next) => {\n const nextValue = next.getValue(columnId)\n return sum + (typeof nextValue === 'number' ? nextValue : 0)\n }, 0)\n}\n\nconst min: AggregationFn = (columnId, _leafRows, childRows) => {\n let min: number | undefined\n\n childRows.forEach(row => {\n const value = row.getValue(columnId)\n\n if (\n value != null &&\n (min! > value || (min === undefined && value >= value))\n ) {\n min = value\n }\n })\n\n return min\n}\n\nconst max: AggregationFn = (columnId, _leafRows, childRows) => {\n let max: number | undefined\n\n childRows.forEach(row => {\n const value = row.getValue(columnId)\n if (\n value != null &&\n (max! < value || (max === undefined && value >= value))\n ) {\n max = value\n }\n })\n\n return max\n}\n\nconst extent: AggregationFn = (columnId, _leafRows, childRows) => {\n let min: number | undefined\n let max: number | undefined\n\n childRows.forEach(row => {\n const value = row.getValue(columnId)\n if (value != null) {\n if (min === undefined) {\n if (value >= value) min = max = value\n } else {\n if (min > value) min = value\n if (max! < value) max = value\n }\n }\n })\n\n return [min, max]\n}\n\nconst mean: AggregationFn = (columnId, leafRows) => {\n let count = 0\n let sum = 0\n\n leafRows.forEach(row => {\n let value = row.getValue(columnId)\n if (value != null && (value = +value) >= value) {\n ++count, (sum += value)\n }\n })\n\n if (count) return sum / count\n\n return\n}\n\nconst median: AggregationFn = (columnId, leafRows) => {\n if (!leafRows.length) {\n return\n }\n\n const values = leafRows.map(row => row.getValue(columnId))\n if (!isNumberArray(values)) {\n return\n }\n if (values.length === 1) {\n return values[0]\n }\n\n const mid = Math.floor(values.length / 2)\n const nums = values.sort((a, b) => a - b)\n return values.length % 2 !== 0 ? nums[mid] : (nums[mid - 1]! + nums[mid]!) / 2\n}\n\nconst unique: AggregationFn = (columnId, leafRows) => {\n return Array.from(new Set(leafRows.map(d => d.getValue(columnId))).values())\n}\n\nconst uniqueCount: AggregationFn = (columnId, leafRows) => {\n return new Set(leafRows.map(d => d.getValue(columnId))).size\n}\n\nconst count: AggregationFn = (_columnId, leafRows) => {\n return leafRows.length\n}\n\nexport const aggregationFns = {\n sum,\n min,\n max,\n extent,\n mean,\n median,\n unique,\n uniqueCount,\n count,\n}\n\nexport type BuiltInAggregationFn = keyof typeof aggregationFns\n", "import { RowModel } from '..'\nimport { BuiltInAggregationFn, aggregationFns } from '../aggregationFns'\nimport {\n AggregationFns,\n Cell,\n Column,\n ColumnDefTemplate,\n OnChangeFn,\n Row,\n RowData,\n Table,\n TableFeature,\n Updater,\n} from '../types'\nimport { isFunction, makeStateUpdater } from '../utils'\n\nexport type GroupingState = string[]\n\nexport interface GroupingTableState {\n grouping: GroupingState\n}\n\nexport type AggregationFn = (\n columnId: string,\n leafRows: Row[],\n childRows: Row[]\n) => any\n\nexport type CustomAggregationFns = Record>\n\nexport type AggregationFnOption =\n | 'auto'\n | keyof AggregationFns\n | BuiltInAggregationFn\n | AggregationFn\n\nexport interface GroupingColumnDef {\n /**\n * The cell to display each row for the column if the cell is an aggregate. If a function is passed, it will be passed a props object with the context of the cell and should return the property type for your adapter (the exact type depends on the adapter being used).\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/grouping#aggregatedcell)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/grouping)\n */\n aggregatedCell?: ColumnDefTemplate<\n ReturnType['getContext']>\n >\n /**\n * The resolved aggregation function for the column.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/grouping#aggregationfn)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/grouping)\n */\n aggregationFn?: AggregationFnOption\n /**\n * Enables/disables grouping for this column.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/grouping#enablegrouping)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/grouping)\n */\n enableGrouping?: boolean\n /**\n * Specify a value to be used for grouping rows on this column. If this option is not specified, the value derived from `accessorKey` / `accessorFn` will be used instead.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/grouping#getgroupingvalue)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/grouping)\n */\n getGroupingValue?: (row: TData) => any\n}\n\nexport interface GroupingColumn {\n /**\n * Returns the aggregation function for the column.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/grouping#getaggregationfn)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/grouping)\n */\n getAggregationFn: () => AggregationFn | undefined\n /**\n * Returns the automatically inferred aggregation function for the column.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/grouping#getautoaggregationfn)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/grouping)\n */\n getAutoAggregationFn: () => AggregationFn | undefined\n /**\n * Returns whether or not the column can be grouped.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/grouping#getcangroup)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/grouping)\n */\n getCanGroup: () => boolean\n /**\n * Returns the index of the column in the grouping state.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/grouping#getgroupedindex)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/grouping)\n */\n getGroupedIndex: () => number\n /**\n * Returns whether or not the column is currently grouped.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/grouping#getisgrouped)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/grouping)\n */\n getIsGrouped: () => boolean\n /**\n * Returns a function that toggles the grouping state of the column. This is useful for passing to the `onClick` prop of a button.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/grouping#gettogglegroupinghandler)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/grouping)\n */\n getToggleGroupingHandler: () => () => void\n /**\n * Toggles the grouping state of the column.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/grouping#togglegrouping)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/grouping)\n */\n toggleGrouping: () => void\n}\n\nexport interface GroupingRow {\n _groupingValuesCache: Record\n /**\n * Returns the grouping value for any row and column (including leaf rows).\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/grouping#getgroupingvalue)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/grouping)\n */\n getGroupingValue: (columnId: string) => unknown\n /**\n * Returns whether or not the row is currently grouped.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/grouping#getisgrouped)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/grouping)\n */\n getIsGrouped: () => boolean\n /**\n * If this row is grouped, this is the id of the column that this row is grouped by.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/grouping#groupingcolumnid)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/grouping)\n */\n groupingColumnId?: string\n /**\n * If this row is grouped, this is the unique/shared value for the `groupingColumnId` for all of the rows in this group.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/grouping#groupingvalue)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/grouping)\n */\n groupingValue?: unknown\n}\n\nexport interface GroupingCell {\n /**\n * Returns whether or not the cell is currently aggregated.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/grouping#getisaggregated)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/grouping)\n */\n getIsAggregated: () => boolean\n /**\n * Returns whether or not the cell is currently grouped.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/grouping#getisgrouped)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/grouping)\n */\n getIsGrouped: () => boolean\n /**\n * Returns whether or not the cell is currently a placeholder cell.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/grouping#getisplaceholder)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/grouping)\n */\n getIsPlaceholder: () => boolean\n}\n\nexport interface ColumnDefaultOptions {\n enableGrouping: boolean\n onGroupingChange: OnChangeFn\n}\n\ninterface GroupingOptionsBase {\n /**\n * Enables/disables grouping for the table.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/grouping#enablegrouping)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/grouping)\n */\n enableGrouping?: boolean\n /**\n * Returns the row model after grouping has taken place, but no further.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/grouping#getgroupedrowmodel)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/grouping)\n */\n getGroupedRowModel?: (table: Table) => () => RowModel\n /**\n * Grouping columns are automatically reordered by default to the start of the columns list. If you would rather remove them or leave them as-is, set the appropriate mode here.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/grouping#groupedcolumnmode)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/grouping)\n */\n groupedColumnMode?: false | 'reorder' | 'remove'\n /**\n * Enables manual grouping. If this option is set to `true`, the table will not automatically group rows using `getGroupedRowModel()` and instead will expect you to manually group the rows before passing them to the table. This is useful if you are doing server-side grouping and aggregation.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/grouping#manualgrouping)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/grouping)\n */\n manualGrouping?: boolean\n /**\n * If this function is provided, it will be called when the grouping state changes and you will be expected to manage the state yourself. You can pass the managed state back to the table via the `tableOptions.state.grouping` option.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/grouping#ongroupingchange)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/grouping)\n */\n onGroupingChange?: OnChangeFn\n}\n\ntype ResolvedAggregationFns = keyof AggregationFns extends never\n ? {\n aggregationFns?: Record>\n }\n : {\n aggregationFns: Record>\n }\n\nexport interface GroupingOptions\n extends GroupingOptionsBase,\n ResolvedAggregationFns {}\n\nexport type GroupingColumnMode = false | 'reorder' | 'remove'\n\nexport interface GroupingInstance {\n _getGroupedRowModel?: () => RowModel\n /**\n * Returns the row model for the table after grouping has been applied.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/grouping#getgroupedrowmodel)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/grouping)\n */\n getGroupedRowModel: () => RowModel\n /**\n * Returns the row model for the table before any grouping has been applied.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/grouping#getpregroupedrowmodel)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/grouping)\n */\n getPreGroupedRowModel: () => RowModel\n /**\n * Resets the **grouping** state to `initialState.grouping`, or `true` can be passed to force a default blank state reset to `[]`.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/grouping#resetgrouping)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/grouping)\n */\n resetGrouping: (defaultState?: boolean) => void\n /**\n * Updates the grouping state of the table via an update function or value.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/grouping#setgrouping)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/grouping)\n */\n setGrouping: (updater: Updater) => void\n}\n\n//\n\nexport const ColumnGrouping: TableFeature = {\n getDefaultColumnDef: (): GroupingColumnDef<\n TData,\n unknown\n > => {\n return {\n aggregatedCell: props => (props.getValue() as any)?.toString?.() ?? null,\n aggregationFn: 'auto',\n }\n },\n\n getInitialState: (state): GroupingTableState => {\n return {\n grouping: [],\n ...state,\n }\n },\n\n getDefaultOptions: (\n table: Table\n ): GroupingOptions => {\n return {\n onGroupingChange: makeStateUpdater('grouping', table),\n groupedColumnMode: 'reorder',\n }\n },\n\n createColumn: (\n column: Column,\n table: Table\n ): void => {\n column.toggleGrouping = () => {\n table.setGrouping(old => {\n // Find any existing grouping for this column\n if (old?.includes(column.id)) {\n return old.filter(d => d !== column.id)\n }\n\n return [...(old ?? []), column.id]\n })\n }\n\n column.getCanGroup = () => {\n return (\n (column.columnDef.enableGrouping ?? true) &&\n (table.options.enableGrouping ?? true) &&\n (!!column.accessorFn || !!column.columnDef.getGroupingValue)\n )\n }\n\n column.getIsGrouped = () => {\n return table.getState().grouping?.includes(column.id)\n }\n\n column.getGroupedIndex = () => table.getState().grouping?.indexOf(column.id)\n\n column.getToggleGroupingHandler = () => {\n const canGroup = column.getCanGroup()\n\n return () => {\n if (!canGroup) return\n column.toggleGrouping()\n }\n }\n column.getAutoAggregationFn = () => {\n const firstRow = table.getCoreRowModel().flatRows[0]\n\n const value = firstRow?.getValue(column.id)\n\n if (typeof value === 'number') {\n return aggregationFns.sum\n }\n\n if (Object.prototype.toString.call(value) === '[object Date]') {\n return aggregationFns.extent\n }\n }\n column.getAggregationFn = () => {\n if (!column) {\n throw new Error()\n }\n\n return isFunction(column.columnDef.aggregationFn)\n ? column.columnDef.aggregationFn\n : column.columnDef.aggregationFn === 'auto'\n ? column.getAutoAggregationFn()\n : table.options.aggregationFns?.[\n column.columnDef.aggregationFn as string\n ] ??\n aggregationFns[\n column.columnDef.aggregationFn as BuiltInAggregationFn\n ]\n }\n },\n\n createTable: (table: Table): void => {\n table.setGrouping = updater => table.options.onGroupingChange?.(updater)\n\n table.resetGrouping = defaultState => {\n table.setGrouping(defaultState ? [] : table.initialState?.grouping ?? [])\n }\n\n table.getPreGroupedRowModel = () => table.getFilteredRowModel()\n table.getGroupedRowModel = () => {\n if (!table._getGroupedRowModel && table.options.getGroupedRowModel) {\n table._getGroupedRowModel = table.options.getGroupedRowModel(table)\n }\n\n if (table.options.manualGrouping || !table._getGroupedRowModel) {\n return table.getPreGroupedRowModel()\n }\n\n return table._getGroupedRowModel()\n }\n },\n\n createRow: (\n row: Row,\n table: Table\n ): void => {\n row.getIsGrouped = () => !!row.groupingColumnId\n row.getGroupingValue = columnId => {\n if (row._groupingValuesCache.hasOwnProperty(columnId)) {\n return row._groupingValuesCache[columnId]\n }\n\n const column = table.getColumn(columnId)\n\n if (!column?.columnDef.getGroupingValue) {\n return row.getValue(columnId)\n }\n\n row._groupingValuesCache[columnId] = column.columnDef.getGroupingValue(\n row.original\n )\n\n return row._groupingValuesCache[columnId]\n }\n row._groupingValuesCache = {}\n },\n\n createCell: (\n cell: Cell,\n column: Column,\n row: Row,\n table: Table\n ): void => {\n const getRenderValue = () =>\n cell.getValue() ?? table.options.renderFallbackValue\n\n cell.getIsGrouped = () =>\n column.getIsGrouped() && column.id === row.groupingColumnId\n cell.getIsPlaceholder = () => !cell.getIsGrouped() && column.getIsGrouped()\n cell.getIsAggregated = () =>\n !cell.getIsGrouped() && !cell.getIsPlaceholder() && !!row.subRows?.length\n },\n}\n\nexport function orderColumns(\n leafColumns: Column[],\n grouping: string[],\n groupedColumnMode?: GroupingColumnMode\n) {\n if (!grouping?.length || !groupedColumnMode) {\n return leafColumns\n }\n\n const nonGroupingColumns = leafColumns.filter(\n col => !grouping.includes(col.id)\n )\n\n if (groupedColumnMode === 'remove') {\n return nonGroupingColumns\n }\n\n const groupingColumns = grouping\n .map(g => leafColumns.find(col => col.id === g)!)\n .filter(Boolean)\n\n return [...groupingColumns, ...nonGroupingColumns]\n}\n", "import { getMemoOptions, makeStateUpdater, memo } from '../utils'\n\nimport {\n Column,\n OnChangeFn,\n RowData,\n Table,\n TableFeature,\n Updater,\n} from '../types'\n\nimport { orderColumns } from './ColumnGrouping'\nimport { ColumnPinningPosition, _getVisibleLeafColumns } from '..'\n\nexport interface ColumnOrderTableState {\n columnOrder: ColumnOrderState\n}\n\nexport type ColumnOrderState = string[]\n\nexport interface ColumnOrderOptions {\n /**\n * If provided, this function will be called with an `updaterFn` when `state.columnOrder` changes. This overrides the default internal state management, so you will need to persist the state change either fully or partially outside of the table.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/column-ordering#oncolumnorderchange)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/column-ordering)\n */\n onColumnOrderChange?: OnChangeFn\n}\n\nexport interface ColumnOrderColumn {\n /**\n * Returns the index of the column in the order of the visible columns. Optionally pass a `position` parameter to get the index of the column in a sub-section of the table\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/column-ordering#getindex)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/column-ordering)\n */\n getIndex: (position?: ColumnPinningPosition | 'center') => number\n /**\n * Returns `true` if the column is the first column in the order of the visible columns. Optionally pass a `position` parameter to check if the column is the first in a sub-section of the table.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/column-ordering#getisfirstcolumn)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/column-ordering)\n */\n getIsFirstColumn: (position?: ColumnPinningPosition | 'center') => boolean\n /**\n * Returns `true` if the column is the last column in the order of the visible columns. Optionally pass a `position` parameter to check if the column is the last in a sub-section of the table.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/column-ordering#getislastcolumn)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/column-ordering)\n */\n getIsLastColumn: (position?: ColumnPinningPosition | 'center') => boolean\n}\n\nexport interface ColumnOrderDefaultOptions {\n onColumnOrderChange: OnChangeFn\n}\n\nexport interface ColumnOrderInstance {\n _getOrderColumnsFn: () => (\n columns: Column[]\n ) => Column[]\n /**\n * Resets the **columnOrder** state to `initialState.columnOrder`, or `true` can be passed to force a default blank state reset to `[]`.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/column-ordering#resetcolumnorder)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/column-ordering)\n */\n resetColumnOrder: (defaultState?: boolean) => void\n /**\n * Sets or updates the `state.columnOrder` state.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/column-ordering#setcolumnorder)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/column-ordering)\n */\n setColumnOrder: (updater: Updater) => void\n}\n\n//\n\nexport const ColumnOrdering: TableFeature = {\n getInitialState: (state): ColumnOrderTableState => {\n return {\n columnOrder: [],\n ...state,\n }\n },\n\n getDefaultOptions: (\n table: Table\n ): ColumnOrderDefaultOptions => {\n return {\n onColumnOrderChange: makeStateUpdater('columnOrder', table),\n }\n },\n\n createColumn: (\n column: Column,\n table: Table\n ): void => {\n column.getIndex = memo(\n position => [_getVisibleLeafColumns(table, position)],\n columns => columns.findIndex(d => d.id === column.id),\n getMemoOptions(table.options, 'debugColumns', 'getIndex')\n )\n column.getIsFirstColumn = position => {\n const columns = _getVisibleLeafColumns(table, position)\n return columns[0]?.id === column.id\n }\n column.getIsLastColumn = position => {\n const columns = _getVisibleLeafColumns(table, position)\n return columns[columns.length - 1]?.id === column.id\n }\n },\n\n createTable: (table: Table): void => {\n table.setColumnOrder = updater =>\n table.options.onColumnOrderChange?.(updater)\n table.resetColumnOrder = defaultState => {\n table.setColumnOrder(\n defaultState ? [] : table.initialState.columnOrder ?? []\n )\n }\n table._getOrderColumnsFn = memo(\n () => [\n table.getState().columnOrder,\n table.getState().grouping,\n table.options.groupedColumnMode,\n ],\n (columnOrder, grouping, groupedColumnMode) =>\n (columns: Column[]) => {\n // Sort grouped columns to the start of the column list\n // before the headers are built\n let orderedColumns: Column[] = []\n\n // If there is no order, return the normal columns\n if (!columnOrder?.length) {\n orderedColumns = columns\n } else {\n const columnOrderCopy = [...columnOrder]\n\n // If there is an order, make a copy of the columns\n const columnsCopy = [...columns]\n\n // And make a new ordered array of the columns\n\n // Loop over the columns and place them in order into the new array\n while (columnsCopy.length && columnOrderCopy.length) {\n const targetColumnId = columnOrderCopy.shift()\n const foundIndex = columnsCopy.findIndex(\n d => d.id === targetColumnId\n )\n if (foundIndex > -1) {\n orderedColumns.push(columnsCopy.splice(foundIndex, 1)[0]!)\n }\n }\n\n // If there are any columns left, add them to the end\n orderedColumns = [...orderedColumns, ...columnsCopy]\n }\n\n return orderColumns(orderedColumns, grouping, groupedColumnMode)\n },\n getMemoOptions(table.options, 'debugTable', '_getOrderColumnsFn')\n )\n },\n}\n", "import {\n OnChangeFn,\n Updater,\n Table,\n Column,\n Row,\n Cell,\n RowData,\n TableFeature,\n} from '../types'\nimport { getMemoOptions, makeStateUpdater, memo } from '../utils'\n\nexport type ColumnPinningPosition = false | 'left' | 'right'\n\nexport interface ColumnPinningState {\n left?: string[]\n right?: string[]\n}\n\nexport interface ColumnPinningTableState {\n columnPinning: ColumnPinningState\n}\n\nexport interface ColumnPinningOptions {\n /**\n * Enables/disables column pinning for the table. Defaults to `true`.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/column-pinning#enablecolumnpinning)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/column-pinning)\n */\n enableColumnPinning?: boolean\n /**\n * @deprecated Use `enableColumnPinning` or `enableRowPinning` instead.\n * Enables/disables all pinning for the table. Defaults to `true`.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/column-pinning#enablepinning)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/column-pinning)\n */\n enablePinning?: boolean\n /**\n * If provided, this function will be called with an `updaterFn` when `state.columnPinning` changes. This overrides the default internal state management, so you will also need to supply `state.columnPinning` from your own managed state.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/column-pinning#oncolumnpinningchange)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/oncolumnpinningchange)\n */\n onColumnPinningChange?: OnChangeFn\n}\n\nexport interface ColumnPinningDefaultOptions {\n onColumnPinningChange: OnChangeFn\n}\n\nexport interface ColumnPinningColumnDef {\n /**\n * Enables/disables column pinning for this column. Defaults to `true`.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/column-pinning#enablepinning-1)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/column-pinning)\n */\n enablePinning?: boolean\n}\n\nexport interface ColumnPinningColumn {\n /**\n * Returns whether or not the column can be pinned.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/column-pinning#getcanpin)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/column-pinning)\n */\n getCanPin: () => boolean\n /**\n * Returns the pinned position of the column. (`'left'`, `'right'` or `false`)\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/column-pinning#getispinned)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/column-pinning)\n */\n getIsPinned: () => ColumnPinningPosition\n /**\n * Returns the numeric pinned index of the column within a pinned column group.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/column-pinning#getpinnedindex)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/column-pinning)\n */\n getPinnedIndex: () => number\n /**\n * Pins a column to the `'left'` or `'right'`, or unpins the column to the center if `false` is passed.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/column-pinning#pin)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/column-pinning)\n */\n pin: (position: ColumnPinningPosition) => void\n}\n\nexport interface ColumnPinningRow {\n /**\n * Returns all center pinned (unpinned) leaf cells in the row.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/column-pinning#getcentervisiblecells)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/column-pinning)\n */\n getCenterVisibleCells: () => Cell[]\n /**\n * Returns all left pinned leaf cells in the row.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/column-pinning#getleftvisiblecells)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/column-pinning)\n */\n getLeftVisibleCells: () => Cell[]\n /**\n * Returns all right pinned leaf cells in the row.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/column-pinning#getrightvisiblecells)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/column-pinning)\n */\n getRightVisibleCells: () => Cell[]\n}\n\nexport interface ColumnPinningInstance {\n /**\n * Returns all center pinned (unpinned) leaf columns.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/column-pinning#getcenterleafcolumns)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/column-pinning)\n */\n getCenterLeafColumns: () => Column[]\n /**\n * Returns whether or not any columns are pinned. Optionally specify to only check for pinned columns in either the `left` or `right` position.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/column-pinning#getissomecolumnspinned)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/column-pinning)\n */\n getIsSomeColumnsPinned: (position?: ColumnPinningPosition) => boolean\n /**\n * Returns all left pinned leaf columns.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/column-pinning#getleftleafcolumns)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/column-pinning)\n */\n getLeftLeafColumns: () => Column[]\n /**\n * Returns all right pinned leaf columns.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/column-pinning#getrightleafcolumns)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/column-pinning)\n */\n getRightLeafColumns: () => Column[]\n /**\n * Resets the **columnPinning** state to `initialState.columnPinning`, or `true` can be passed to force a default blank state reset to `{ left: [], right: [], }`.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/column-pinning#resetcolumnpinning)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/column-pinning)\n */\n resetColumnPinning: (defaultState?: boolean) => void\n /**\n * Sets or updates the `state.columnPinning` state.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/column-pinning#setcolumnpinning)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/column-pinning)\n */\n setColumnPinning: (updater: Updater) => void\n}\n\n//\n\nconst getDefaultColumnPinningState = (): ColumnPinningState => ({\n left: [],\n right: [],\n})\n\nexport const ColumnPinning: TableFeature = {\n getInitialState: (state): ColumnPinningTableState => {\n return {\n columnPinning: getDefaultColumnPinningState(),\n ...state,\n }\n },\n\n getDefaultOptions: (\n table: Table\n ): ColumnPinningDefaultOptions => {\n return {\n onColumnPinningChange: makeStateUpdater('columnPinning', table),\n }\n },\n\n createColumn: (\n column: Column,\n table: Table\n ): void => {\n column.pin = position => {\n const columnIds = column\n .getLeafColumns()\n .map(d => d.id)\n .filter(Boolean) as string[]\n\n table.setColumnPinning(old => {\n if (position === 'right') {\n return {\n left: (old?.left ?? []).filter(d => !columnIds?.includes(d)),\n right: [\n ...(old?.right ?? []).filter(d => !columnIds?.includes(d)),\n ...columnIds,\n ],\n }\n }\n\n if (position === 'left') {\n return {\n left: [\n ...(old?.left ?? []).filter(d => !columnIds?.includes(d)),\n ...columnIds,\n ],\n right: (old?.right ?? []).filter(d => !columnIds?.includes(d)),\n }\n }\n\n return {\n left: (old?.left ?? []).filter(d => !columnIds?.includes(d)),\n right: (old?.right ?? []).filter(d => !columnIds?.includes(d)),\n }\n })\n }\n\n column.getCanPin = () => {\n const leafColumns = column.getLeafColumns()\n\n return leafColumns.some(\n d =>\n (d.columnDef.enablePinning ?? true) &&\n (table.options.enableColumnPinning ??\n table.options.enablePinning ??\n true)\n )\n }\n\n column.getIsPinned = () => {\n const leafColumnIds = column.getLeafColumns().map(d => d.id)\n\n const { left, right } = table.getState().columnPinning\n\n const isLeft = leafColumnIds.some(d => left?.includes(d))\n const isRight = leafColumnIds.some(d => right?.includes(d))\n\n return isLeft ? 'left' : isRight ? 'right' : false\n }\n\n column.getPinnedIndex = () => {\n const position = column.getIsPinned()\n\n return position\n ? table.getState().columnPinning?.[position]?.indexOf(column.id) ?? -1\n : 0\n }\n },\n\n createRow: (\n row: Row,\n table: Table\n ): void => {\n row.getCenterVisibleCells = memo(\n () => [\n row._getAllVisibleCells(),\n table.getState().columnPinning.left,\n table.getState().columnPinning.right,\n ],\n (allCells, left, right) => {\n const leftAndRight: string[] = [...(left ?? []), ...(right ?? [])]\n\n return allCells.filter(d => !leftAndRight.includes(d.column.id))\n },\n getMemoOptions(table.options, 'debugRows', 'getCenterVisibleCells')\n )\n row.getLeftVisibleCells = memo(\n () => [row._getAllVisibleCells(), table.getState().columnPinning.left],\n (allCells, left) => {\n const cells = (left ?? [])\n .map(columnId => allCells.find(cell => cell.column.id === columnId)!)\n .filter(Boolean)\n .map(d => ({ ...d, position: 'left' }) as Cell)\n\n return cells\n },\n getMemoOptions(table.options, 'debugRows', 'getLeftVisibleCells')\n )\n row.getRightVisibleCells = memo(\n () => [row._getAllVisibleCells(), table.getState().columnPinning.right],\n (allCells, right) => {\n const cells = (right ?? [])\n .map(columnId => allCells.find(cell => cell.column.id === columnId)!)\n .filter(Boolean)\n .map(d => ({ ...d, position: 'right' }) as Cell)\n\n return cells\n },\n getMemoOptions(table.options, 'debugRows', 'getRightVisibleCells')\n )\n },\n\n createTable: (table: Table): void => {\n table.setColumnPinning = updater =>\n table.options.onColumnPinningChange?.(updater)\n\n table.resetColumnPinning = defaultState =>\n table.setColumnPinning(\n defaultState\n ? getDefaultColumnPinningState()\n : table.initialState?.columnPinning ?? getDefaultColumnPinningState()\n )\n\n table.getIsSomeColumnsPinned = position => {\n const pinningState = table.getState().columnPinning\n\n if (!position) {\n return Boolean(pinningState.left?.length || pinningState.right?.length)\n }\n return Boolean(pinningState[position]?.length)\n }\n\n table.getLeftLeafColumns = memo(\n () => [table.getAllLeafColumns(), table.getState().columnPinning.left],\n (allColumns, left) => {\n return (left ?? [])\n .map(columnId => allColumns.find(column => column.id === columnId)!)\n .filter(Boolean)\n },\n getMemoOptions(table.options, 'debugColumns', 'getLeftLeafColumns')\n )\n\n table.getRightLeafColumns = memo(\n () => [table.getAllLeafColumns(), table.getState().columnPinning.right],\n (allColumns, right) => {\n return (right ?? [])\n .map(columnId => allColumns.find(column => column.id === columnId)!)\n .filter(Boolean)\n },\n getMemoOptions(table.options, 'debugColumns', 'getRightLeafColumns')\n )\n\n table.getCenterLeafColumns = memo(\n () => [\n table.getAllLeafColumns(),\n table.getState().columnPinning.left,\n table.getState().columnPinning.right,\n ],\n (allColumns, left, right) => {\n const leftAndRight: string[] = [...(left ?? []), ...(right ?? [])]\n\n return allColumns.filter(d => !leftAndRight.includes(d.id))\n },\n getMemoOptions(table.options, 'debugColumns', 'getCenterLeafColumns')\n )\n },\n}\n", "import { _getVisibleLeafColumns } from '..'\nimport {\n RowData,\n Column,\n Header,\n OnChangeFn,\n Table,\n Updater,\n TableFeature,\n} from '../types'\nimport { getMemoOptions, makeStateUpdater, memo } from '../utils'\nimport { ColumnPinningPosition } from './ColumnPinning'\n\n//\n\nexport interface ColumnSizingTableState {\n columnSizing: ColumnSizingState\n columnSizingInfo: ColumnSizingInfoState\n}\n\nexport type ColumnSizingState = Record\n\nexport interface ColumnSizingInfoState {\n columnSizingStart: [string, number][]\n deltaOffset: null | number\n deltaPercentage: null | number\n isResizingColumn: false | string\n startOffset: null | number\n startSize: null | number\n}\n\nexport type ColumnResizeMode = 'onChange' | 'onEnd'\n\nexport type ColumnResizeDirection = 'ltr' | 'rtl'\n\nexport interface ColumnSizingOptions {\n /**\n * Determines when the columnSizing state is updated. `onChange` updates the state when the user is dragging the resize handle. `onEnd` updates the state when the user releases the resize handle.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/column-sizing#columnresizemode)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/column-sizing)\n */\n columnResizeMode?: ColumnResizeMode\n /**\n * Enables or disables column resizing for the column.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/column-sizing#enablecolumnresizing)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/column-sizing)\n */\n enableColumnResizing?: boolean\n /**\n * Enables or disables right-to-left support for resizing the column. defaults to 'ltr'.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/column-sizing#columnResizeDirection)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/column-sizing)\n */\n columnResizeDirection?: ColumnResizeDirection\n /**\n * If provided, this function will be called with an `updaterFn` when `state.columnSizing` changes. This overrides the default internal state management, so you will also need to supply `state.columnSizing` from your own managed state.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/column-sizing#oncolumnsizingchange)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/column-sizing)\n */\n onColumnSizingChange?: OnChangeFn\n /**\n * If provided, this function will be called with an `updaterFn` when `state.columnSizingInfo` changes. This overrides the default internal state management, so you will also need to supply `state.columnSizingInfo` from your own managed state.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/column-sizing#oncolumnsizinginfochange)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/column-sizing)\n */\n onColumnSizingInfoChange?: OnChangeFn\n}\n\nexport type ColumnSizingDefaultOptions = Pick<\n ColumnSizingOptions,\n | 'columnResizeMode'\n | 'onColumnSizingChange'\n | 'onColumnSizingInfoChange'\n | 'columnResizeDirection'\n>\n\nexport interface ColumnSizingInstance {\n /**\n * If pinning, returns the total size of the center portion of the table by calculating the sum of the sizes of all unpinned/center leaf-columns.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/column-sizing#getcentertotalsize)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/column-sizing)\n */\n getCenterTotalSize: () => number\n /**\n * Returns the total size of the left portion of the table by calculating the sum of the sizes of all left leaf-columns.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/column-sizing#getlefttotalsize)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/column-sizing)\n */\n getLeftTotalSize: () => number\n /**\n * Returns the total size of the right portion of the table by calculating the sum of the sizes of all right leaf-columns.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/column-sizing#getrighttotalsize)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/column-sizing)\n */\n getRightTotalSize: () => number\n /**\n * Returns the total size of the table by calculating the sum of the sizes of all leaf-columns.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/column-sizing#gettotalsize)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/column-sizing)\n */\n getTotalSize: () => number\n /**\n * Resets column sizing to its initial state. If `defaultState` is `true`, the default state for the table will be used instead of the initialValue provided to the table.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/column-sizing#resetcolumnsizing)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/column-sizing)\n */\n resetColumnSizing: (defaultState?: boolean) => void\n /**\n * Resets column sizing info to its initial state. If `defaultState` is `true`, the default state for the table will be used instead of the initialValue provided to the table.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/column-sizing#resetheadersizeinfo)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/column-sizing)\n */\n resetHeaderSizeInfo: (defaultState?: boolean) => void\n /**\n * Sets the column sizing state using an updater function or a value. This will trigger the underlying `onColumnSizingChange` function if one is passed to the table options, otherwise the state will be managed automatically by the table.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/column-sizing#setcolumnsizing)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/column-sizing)\n */\n setColumnSizing: (updater: Updater) => void\n /**\n * Sets the column sizing info state using an updater function or a value. This will trigger the underlying `onColumnSizingInfoChange` function if one is passed to the table options, otherwise the state will be managed automatically by the table.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/column-sizing#setcolumnsizinginfo)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/column-sizing)\n */\n setColumnSizingInfo: (updater: Updater) => void\n}\n\nexport interface ColumnSizingColumnDef {\n /**\n * Enables or disables column resizing for the column.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/column-sizing#enableresizing)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/column-sizing)\n */\n enableResizing?: boolean\n /**\n * The maximum allowed size for the column\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/column-sizing#maxsize)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/column-sizing)\n */\n maxSize?: number\n /**\n * The minimum allowed size for the column\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/column-sizing#minsize)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/column-sizing)\n */\n minSize?: number\n /**\n * The desired size for the column\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/column-sizing#size)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/column-sizing)\n */\n size?: number\n}\n\nexport interface ColumnSizingColumn {\n /**\n * Returns `true` if the column can be resized.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/column-sizing#getcanresize)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/column-sizing)\n */\n getCanResize: () => boolean\n /**\n * Returns `true` if the column is currently being resized.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/column-sizing#getisresizing)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/column-sizing)\n */\n getIsResizing: () => boolean\n /**\n * Returns the current size of the column.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/column-sizing#getsize)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/column-sizing)\n */\n getSize: () => number\n /**\n * Returns the offset measurement along the row-axis (usually the x-axis for standard tables) for the header. This is effectively a sum of the offset measurements of all preceding (left) headers in relation to the current column.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/column-sizing#getstart)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/column-sizing)\n */\n getStart: (position?: ColumnPinningPosition | 'center') => number\n /**\n * Returns the offset measurement along the row-axis (usually the x-axis for standard tables) for the header. This is effectively a sum of the offset measurements of all succeeding (right) headers in relation to the current column.\n */\n getAfter: (position?: ColumnPinningPosition | 'center') => number\n /**\n * Resets the column to its initial size.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/column-sizing#resetsize)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/column-sizing)\n */\n resetSize: () => void\n}\n\nexport interface ColumnSizingHeader {\n /**\n * Returns an event handler function that can be used to resize the header. It can be used as an:\n * - `onMouseDown` handler\n * - `onTouchStart` handler\n *\n * The dragging and release events are automatically handled for you.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/column-sizing#getresizehandler)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/column-sizing)\n */\n getResizeHandler: (context?: Document) => (event: unknown) => void\n /**\n * Returns the current size of the header.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/column-sizing#getsize)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/column-sizing)\n */\n getSize: () => number\n /**\n * Returns the offset measurement along the row-axis (usually the x-axis for standard tables) for the header. This is effectively a sum of the offset measurements of all preceding headers.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/column-sizing#getstart)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/column-sizing)\n */\n getStart: (position?: ColumnPinningPosition) => number\n}\n\n//\n\nexport const defaultColumnSizing = {\n size: 150,\n minSize: 20,\n maxSize: Number.MAX_SAFE_INTEGER,\n}\n\nconst getDefaultColumnSizingInfoState = (): ColumnSizingInfoState => ({\n startOffset: null,\n startSize: null,\n deltaOffset: null,\n deltaPercentage: null,\n isResizingColumn: false,\n columnSizingStart: [],\n})\n\nexport const ColumnSizing: TableFeature = {\n getDefaultColumnDef: (): ColumnSizingColumnDef => {\n return defaultColumnSizing\n },\n getInitialState: (state): ColumnSizingTableState => {\n return {\n columnSizing: {},\n columnSizingInfo: getDefaultColumnSizingInfoState(),\n ...state,\n }\n },\n\n getDefaultOptions: (\n table: Table\n ): ColumnSizingDefaultOptions => {\n return {\n columnResizeMode: 'onEnd',\n columnResizeDirection: 'ltr',\n onColumnSizingChange: makeStateUpdater('columnSizing', table),\n onColumnSizingInfoChange: makeStateUpdater('columnSizingInfo', table),\n }\n },\n\n createColumn: (\n column: Column,\n table: Table\n ): void => {\n column.getSize = () => {\n const columnSize = table.getState().columnSizing[column.id]\n\n return Math.min(\n Math.max(\n column.columnDef.minSize ?? defaultColumnSizing.minSize,\n columnSize ?? column.columnDef.size ?? defaultColumnSizing.size\n ),\n column.columnDef.maxSize ?? defaultColumnSizing.maxSize\n )\n }\n\n column.getStart = memo(\n position => [\n position,\n _getVisibleLeafColumns(table, position),\n table.getState().columnSizing,\n ],\n (position, columns) =>\n columns\n .slice(0, column.getIndex(position))\n .reduce((sum, column) => sum + column.getSize(), 0),\n getMemoOptions(table.options, 'debugColumns', 'getStart')\n )\n\n column.getAfter = memo(\n position => [\n position,\n _getVisibleLeafColumns(table, position),\n table.getState().columnSizing,\n ],\n (position, columns) =>\n columns\n .slice(column.getIndex(position) + 1)\n .reduce((sum, column) => sum + column.getSize(), 0),\n getMemoOptions(table.options, 'debugColumns', 'getAfter')\n )\n\n column.resetSize = () => {\n table.setColumnSizing(({ [column.id]: _, ...rest }) => {\n return rest\n })\n }\n column.getCanResize = () => {\n return (\n (column.columnDef.enableResizing ?? true) &&\n (table.options.enableColumnResizing ?? true)\n )\n }\n column.getIsResizing = () => {\n return table.getState().columnSizingInfo.isResizingColumn === column.id\n }\n },\n\n createHeader: (\n header: Header,\n table: Table\n ): void => {\n header.getSize = () => {\n let sum = 0\n\n const recurse = (header: Header) => {\n if (header.subHeaders.length) {\n header.subHeaders.forEach(recurse)\n } else {\n sum += header.column.getSize() ?? 0\n }\n }\n\n recurse(header)\n\n return sum\n }\n header.getStart = () => {\n if (header.index > 0) {\n const prevSiblingHeader = header.headerGroup.headers[header.index - 1]!\n return prevSiblingHeader.getStart() + prevSiblingHeader.getSize()\n }\n\n return 0\n }\n header.getResizeHandler = _contextDocument => {\n const column = table.getColumn(header.column.id)\n const canResize = column?.getCanResize()\n\n return (e: unknown) => {\n if (!column || !canResize) {\n return\n }\n\n ;(e as any).persist?.()\n\n if (isTouchStartEvent(e)) {\n // lets not respond to multiple touches (e.g. 2 or 3 fingers)\n if (e.touches && e.touches.length > 1) {\n return\n }\n }\n\n const startSize = header.getSize()\n\n const columnSizingStart: [string, number][] = header\n ? header.getLeafHeaders().map(d => [d.column.id, d.column.getSize()])\n : [[column.id, column.getSize()]]\n\n const clientX = isTouchStartEvent(e)\n ? Math.round(e.touches[0]!.clientX)\n : (e as MouseEvent).clientX\n\n const newColumnSizing: ColumnSizingState = {}\n\n const updateOffset = (\n eventType: 'move' | 'end',\n clientXPos?: number\n ) => {\n if (typeof clientXPos !== 'number') {\n return\n }\n\n table.setColumnSizingInfo(old => {\n const deltaDirection =\n table.options.columnResizeDirection === 'rtl' ? -1 : 1\n const deltaOffset =\n (clientXPos - (old?.startOffset ?? 0)) * deltaDirection\n const deltaPercentage = Math.max(\n deltaOffset / (old?.startSize ?? 0),\n -0.999999\n )\n\n old.columnSizingStart.forEach(([columnId, headerSize]) => {\n newColumnSizing[columnId] =\n Math.round(\n Math.max(headerSize + headerSize * deltaPercentage, 0) * 100\n ) / 100\n })\n\n return {\n ...old,\n deltaOffset,\n deltaPercentage,\n }\n })\n\n if (\n table.options.columnResizeMode === 'onChange' ||\n eventType === 'end'\n ) {\n table.setColumnSizing(old => ({\n ...old,\n ...newColumnSizing,\n }))\n }\n }\n\n const onMove = (clientXPos?: number) => updateOffset('move', clientXPos)\n\n const onEnd = (clientXPos?: number) => {\n updateOffset('end', clientXPos)\n\n table.setColumnSizingInfo(old => ({\n ...old,\n isResizingColumn: false,\n startOffset: null,\n startSize: null,\n deltaOffset: null,\n deltaPercentage: null,\n columnSizingStart: [],\n }))\n }\n\n const contextDocument =\n _contextDocument || typeof document !== 'undefined' ? document : null\n\n const mouseEvents = {\n moveHandler: (e: MouseEvent) => onMove(e.clientX),\n upHandler: (e: MouseEvent) => {\n contextDocument?.removeEventListener(\n 'mousemove',\n mouseEvents.moveHandler\n )\n contextDocument?.removeEventListener(\n 'mouseup',\n mouseEvents.upHandler\n )\n onEnd(e.clientX)\n },\n }\n\n const touchEvents = {\n moveHandler: (e: TouchEvent) => {\n if (e.cancelable) {\n e.preventDefault()\n e.stopPropagation()\n }\n onMove(e.touches[0]!.clientX)\n return false\n },\n upHandler: (e: TouchEvent) => {\n contextDocument?.removeEventListener(\n 'touchmove',\n touchEvents.moveHandler\n )\n contextDocument?.removeEventListener(\n 'touchend',\n touchEvents.upHandler\n )\n if (e.cancelable) {\n e.preventDefault()\n e.stopPropagation()\n }\n onEnd(e.touches[0]?.clientX)\n },\n }\n\n const passiveIfSupported = passiveEventSupported()\n ? { passive: false }\n : false\n\n if (isTouchStartEvent(e)) {\n contextDocument?.addEventListener(\n 'touchmove',\n touchEvents.moveHandler,\n passiveIfSupported\n )\n contextDocument?.addEventListener(\n 'touchend',\n touchEvents.upHandler,\n passiveIfSupported\n )\n } else {\n contextDocument?.addEventListener(\n 'mousemove',\n mouseEvents.moveHandler,\n passiveIfSupported\n )\n contextDocument?.addEventListener(\n 'mouseup',\n mouseEvents.upHandler,\n passiveIfSupported\n )\n }\n\n table.setColumnSizingInfo(old => ({\n ...old,\n startOffset: clientX,\n startSize,\n deltaOffset: 0,\n deltaPercentage: 0,\n columnSizingStart,\n isResizingColumn: column.id,\n }))\n }\n }\n },\n\n createTable: (table: Table): void => {\n table.setColumnSizing = updater =>\n table.options.onColumnSizingChange?.(updater)\n table.setColumnSizingInfo = updater =>\n table.options.onColumnSizingInfoChange?.(updater)\n table.resetColumnSizing = defaultState => {\n table.setColumnSizing(\n defaultState ? {} : table.initialState.columnSizing ?? {}\n )\n }\n table.resetHeaderSizeInfo = defaultState => {\n table.setColumnSizingInfo(\n defaultState\n ? getDefaultColumnSizingInfoState()\n : table.initialState.columnSizingInfo ??\n getDefaultColumnSizingInfoState()\n )\n }\n table.getTotalSize = () =>\n table.getHeaderGroups()[0]?.headers.reduce((sum, header) => {\n return sum + header.getSize()\n }, 0) ?? 0\n table.getLeftTotalSize = () =>\n table.getLeftHeaderGroups()[0]?.headers.reduce((sum, header) => {\n return sum + header.getSize()\n }, 0) ?? 0\n table.getCenterTotalSize = () =>\n table.getCenterHeaderGroups()[0]?.headers.reduce((sum, header) => {\n return sum + header.getSize()\n }, 0) ?? 0\n table.getRightTotalSize = () =>\n table.getRightHeaderGroups()[0]?.headers.reduce((sum, header) => {\n return sum + header.getSize()\n }, 0) ?? 0\n },\n}\n\nlet passiveSupported: boolean | null = null\nexport function passiveEventSupported() {\n if (typeof passiveSupported === 'boolean') return passiveSupported\n\n let supported = false\n try {\n const options = {\n get passive() {\n supported = true\n return false\n },\n }\n\n const noop = () => {}\n\n window.addEventListener('test', noop, options)\n window.removeEventListener('test', noop)\n } catch (err) {\n supported = false\n }\n passiveSupported = supported\n return passiveSupported\n}\n\nfunction isTouchStartEvent(e: unknown): e is TouchEvent {\n return (e as TouchEvent).type === 'touchstart'\n}\n", "import { ColumnPinningPosition } from '..'\nimport {\n Cell,\n Column,\n OnChangeFn,\n Table,\n Updater,\n Row,\n RowData,\n TableFeature,\n} from '../types'\nimport { getMemoOptions, makeStateUpdater, memo } from '../utils'\n\nexport type VisibilityState = Record\n\nexport interface VisibilityTableState {\n columnVisibility: VisibilityState\n}\n\nexport interface VisibilityOptions {\n /**\n * Whether to enable column hiding. Defaults to `true`.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/column-visibility#enablehiding)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/column-visibility)\n */\n enableHiding?: boolean\n /**\n * If provided, this function will be called with an `updaterFn` when `state.columnVisibility` changes. This overrides the default internal state management, so you will need to persist the state change either fully or partially outside of the table.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/column-visibility#oncolumnvisibilitychange)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/column-visibility)\n */\n onColumnVisibilityChange?: OnChangeFn\n}\n\nexport type VisibilityDefaultOptions = Pick<\n VisibilityOptions,\n 'onColumnVisibilityChange'\n>\n\nexport interface VisibilityInstance {\n /**\n * If column pinning, returns a flat array of leaf-node columns that are visible in the unpinned/center portion of the table.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/column-visibility#getcentervisibleleafcolumns)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/column-visibility)\n */\n getCenterVisibleLeafColumns: () => Column[]\n /**\n * Returns whether all columns are visible\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/column-visibility#getisallcolumnsvisible)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/column-visibility)\n */\n getIsAllColumnsVisible: () => boolean\n /**\n * Returns whether any columns are visible\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/column-visibility#getissomecolumnsvisible)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/column-visibility)\n */\n getIsSomeColumnsVisible: () => boolean\n /**\n * If column pinning, returns a flat array of leaf-node columns that are visible in the left portion of the table.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/column-visibility#getleftvisibleleafcolumns)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/column-visibility)\n */\n getLeftVisibleLeafColumns: () => Column[]\n /**\n * If column pinning, returns a flat array of leaf-node columns that are visible in the right portion of the table.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/column-visibility#getrightvisibleleafcolumns)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/column-visibility)\n */\n getRightVisibleLeafColumns: () => Column[]\n /**\n * Returns a handler for toggling the visibility of all columns, meant to be bound to a `input[type=checkbox]` element.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/column-visibility#gettoggleallcolumnsvisibilityhandler)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/column-visibility)\n */\n getToggleAllColumnsVisibilityHandler: () => (event: unknown) => void\n /**\n * Returns a flat array of columns that are visible, including parent columns.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/column-visibility#getvisibleflatcolumns)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/column-visibility)\n */\n getVisibleFlatColumns: () => Column[]\n /**\n * Returns a flat array of leaf-node columns that are visible.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/column-visibility#getvisibleleafcolumns)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/column-visibility)\n */\n getVisibleLeafColumns: () => Column[]\n /**\n * Resets the column visibility state to the initial state. If `defaultState` is provided, the state will be reset to `{}`\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/column-visibility#resetcolumnvisibility)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/column-visibility)\n */\n resetColumnVisibility: (defaultState?: boolean) => void\n /**\n * Sets or updates the `state.columnVisibility` state.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/column-visibility#setcolumnvisibility)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/column-visibility)\n */\n setColumnVisibility: (updater: Updater) => void\n /**\n * Toggles the visibility of all columns.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/column-visibility#toggleallcolumnsvisible)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/column-visibility)\n */\n toggleAllColumnsVisible: (value?: boolean) => void\n}\n\nexport interface VisibilityColumnDef {\n enableHiding?: boolean\n}\n\nexport interface VisibilityRow {\n _getAllVisibleCells: () => Cell[]\n /**\n * Returns an array of cells that account for column visibility for the row.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/column-visibility#getvisiblecells)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/column-visibility)\n */\n getVisibleCells: () => Cell[]\n}\n\nexport interface VisibilityColumn {\n /**\n * Returns whether the column can be hidden\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/column-visibility#getcanhide)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/column-visibility)\n */\n getCanHide: () => boolean\n /**\n * Returns whether the column is visible\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/column-visibility#getisvisible)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/column-visibility)\n */\n getIsVisible: () => boolean\n /**\n * Returns a function that can be used to toggle the column visibility. This function can be used to bind to an event handler to a checkbox.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/column-visibility#gettogglevisibilityhandler)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/column-visibility)\n */\n getToggleVisibilityHandler: () => (event: unknown) => void\n /**\n * Toggles the visibility of the column.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/column-visibility#togglevisibility)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/column-visibility)\n */\n toggleVisibility: (value?: boolean) => void\n}\n\n//\n\nexport const ColumnVisibility: TableFeature = {\n getInitialState: (state): VisibilityTableState => {\n return {\n columnVisibility: {},\n ...state,\n }\n },\n\n getDefaultOptions: (\n table: Table\n ): VisibilityDefaultOptions => {\n return {\n onColumnVisibilityChange: makeStateUpdater('columnVisibility', table),\n }\n },\n\n createColumn: (\n column: Column,\n table: Table\n ): void => {\n column.toggleVisibility = value => {\n if (column.getCanHide()) {\n table.setColumnVisibility(old => ({\n ...old,\n [column.id]: value ?? !column.getIsVisible(),\n }))\n }\n }\n column.getIsVisible = () => {\n const childColumns = column.columns\n return (\n (childColumns.length\n ? childColumns.some(c => c.getIsVisible())\n : table.getState().columnVisibility?.[column.id]) ?? true\n )\n }\n\n column.getCanHide = () => {\n return (\n (column.columnDef.enableHiding ?? true) &&\n (table.options.enableHiding ?? true)\n )\n }\n column.getToggleVisibilityHandler = () => {\n return (e: unknown) => {\n column.toggleVisibility?.(\n ((e as MouseEvent).target as HTMLInputElement).checked\n )\n }\n }\n },\n\n createRow: (\n row: Row,\n table: Table\n ): void => {\n row._getAllVisibleCells = memo(\n () => [row.getAllCells(), table.getState().columnVisibility],\n cells => {\n return cells.filter(cell => cell.column.getIsVisible())\n },\n getMemoOptions(table.options, 'debugRows', '_getAllVisibleCells')\n )\n row.getVisibleCells = memo(\n () => [\n row.getLeftVisibleCells(),\n row.getCenterVisibleCells(),\n row.getRightVisibleCells(),\n ],\n (left, center, right) => [...left, ...center, ...right],\n getMemoOptions(table.options, 'debugRows', 'getVisibleCells')\n )\n },\n\n createTable: (table: Table): void => {\n const makeVisibleColumnsMethod = (\n key: string,\n getColumns: () => Column[]\n ): (() => Column[]) => {\n return memo(\n () => [\n getColumns(),\n getColumns()\n .filter(d => d.getIsVisible())\n .map(d => d.id)\n .join('_'),\n ],\n columns => {\n return columns.filter(d => d.getIsVisible?.())\n },\n getMemoOptions(table.options, 'debugColumns', key)\n )\n }\n\n table.getVisibleFlatColumns = makeVisibleColumnsMethod(\n 'getVisibleFlatColumns',\n () => table.getAllFlatColumns()\n )\n table.getVisibleLeafColumns = makeVisibleColumnsMethod(\n 'getVisibleLeafColumns',\n () => table.getAllLeafColumns()\n )\n table.getLeftVisibleLeafColumns = makeVisibleColumnsMethod(\n 'getLeftVisibleLeafColumns',\n () => table.getLeftLeafColumns()\n )\n table.getRightVisibleLeafColumns = makeVisibleColumnsMethod(\n 'getRightVisibleLeafColumns',\n () => table.getRightLeafColumns()\n )\n table.getCenterVisibleLeafColumns = makeVisibleColumnsMethod(\n 'getCenterVisibleLeafColumns',\n () => table.getCenterLeafColumns()\n )\n\n table.setColumnVisibility = updater =>\n table.options.onColumnVisibilityChange?.(updater)\n\n table.resetColumnVisibility = defaultState => {\n table.setColumnVisibility(\n defaultState ? {} : table.initialState.columnVisibility ?? {}\n )\n }\n\n table.toggleAllColumnsVisible = value => {\n value = value ?? !table.getIsAllColumnsVisible()\n\n table.setColumnVisibility(\n table.getAllLeafColumns().reduce(\n (obj, column) => ({\n ...obj,\n [column.id]: !value ? !column.getCanHide?.() : value,\n }),\n {}\n )\n )\n }\n\n table.getIsAllColumnsVisible = () =>\n !table.getAllLeafColumns().some(column => !column.getIsVisible?.())\n\n table.getIsSomeColumnsVisible = () =>\n table.getAllLeafColumns().some(column => column.getIsVisible?.())\n\n table.getToggleAllColumnsVisibilityHandler = () => {\n return (e: unknown) => {\n table.toggleAllColumnsVisible(\n ((e as MouseEvent).target as HTMLInputElement)?.checked\n )\n }\n }\n },\n}\n\nexport function _getVisibleLeafColumns(\n table: Table,\n position?: ColumnPinningPosition | 'center'\n) {\n return !position\n ? table.getVisibleLeafColumns()\n : position === 'center'\n ? table.getCenterVisibleLeafColumns()\n : position === 'left'\n ? table.getLeftVisibleLeafColumns()\n : table.getRightVisibleLeafColumns()\n}\n", "import { RowModel } from '..'\nimport { Table, RowData, TableFeature } from '../types'\n\nexport interface GlobalFacetingInstance {\n _getGlobalFacetedMinMaxValues?: () => undefined | [number, number]\n _getGlobalFacetedRowModel?: () => RowModel\n _getGlobalFacetedUniqueValues?: () => Map\n /**\n * Currently, this function returns the built-in `includesString` filter function. In future releases, it may return more dynamic filter functions based on the nature of the data provided.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/global-faceting#getglobalautofilterfn)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/global-faceting)\n */\n getGlobalFacetedMinMaxValues: () => undefined | [number, number]\n /**\n * Returns the row model for the table after **global** filtering has been applied.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/global-faceting#getglobalfacetedrowmodel)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/global-faceting)\n */\n getGlobalFacetedRowModel: () => RowModel\n /**\n * Returns the faceted unique values for the global filter.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/global-faceting#getglobalfaceteduniquevalues)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/global-faceting)\n */\n getGlobalFacetedUniqueValues: () => Map\n}\n\n//\n\nexport const GlobalFaceting: TableFeature = {\n createTable: (table: Table): void => {\n table._getGlobalFacetedRowModel =\n table.options.getFacetedRowModel &&\n table.options.getFacetedRowModel(table, '__global__')\n\n table.getGlobalFacetedRowModel = () => {\n if (table.options.manualFiltering || !table._getGlobalFacetedRowModel) {\n return table.getPreFilteredRowModel()\n }\n\n return table._getGlobalFacetedRowModel()\n }\n\n table._getGlobalFacetedUniqueValues =\n table.options.getFacetedUniqueValues &&\n table.options.getFacetedUniqueValues(table, '__global__')\n table.getGlobalFacetedUniqueValues = () => {\n if (!table._getGlobalFacetedUniqueValues) {\n return new Map()\n }\n\n return table._getGlobalFacetedUniqueValues()\n }\n\n table._getGlobalFacetedMinMaxValues =\n table.options.getFacetedMinMaxValues &&\n table.options.getFacetedMinMaxValues(table, '__global__')\n table.getGlobalFacetedMinMaxValues = () => {\n if (!table._getGlobalFacetedMinMaxValues) {\n return\n }\n\n return table._getGlobalFacetedMinMaxValues()\n }\n },\n}\n", "import { FilterFn, FilterFnOption } from '..'\nimport { BuiltInFilterFn, filterFns } from '../filterFns'\nimport {\n Column,\n OnChangeFn,\n Table,\n Updater,\n RowData,\n TableFeature,\n} from '../types'\nimport { isFunction, makeStateUpdater } from '../utils'\n\nexport interface GlobalFilterTableState {\n globalFilter: any\n}\n\nexport interface GlobalFilterColumnDef {\n /**\n * Enables/disables the **global** filter for this column.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/global-filtering#enableglobalfilter)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/global-filtering)\n */\n enableGlobalFilter?: boolean\n}\n\nexport interface GlobalFilterColumn {\n /**\n * Returns whether or not the column can be **globally** filtered. Set to `false` to disable a column from being scanned during global filtering.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/global-filtering#getcanglobalfilter)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/global-filtering)\n */\n getCanGlobalFilter: () => boolean\n}\n\nexport interface GlobalFilterOptions {\n /**\n * Enables/disables **global** filtering for all columns.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/global-filtering#enableglobalfilter)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/global-filtering)\n */\n enableGlobalFilter?: boolean\n /**\n * If provided, this function will be called with the column and should return `true` or `false` to indicate whether this column should be used for global filtering.\n *\n * This is useful if the column can contain data that is not `string` or `number` (i.e. `undefined`).\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/global-filtering#getcolumncanglobalfilter)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/global-filtering)\n */\n getColumnCanGlobalFilter?: (column: Column) => boolean\n /**\n * The filter function to use for global filtering.\n * - A `string` referencing a built-in filter function\n * - A `string` that references a custom filter functions provided via the `tableOptions.filterFns` option\n * - A custom filter function\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/global-filtering#globalfilterfn)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/global-filtering)\n */\n globalFilterFn?: FilterFnOption\n /**\n * If provided, this function will be called with an `updaterFn` when `state.globalFilter` changes. This overrides the default internal state management, so you will need to persist the state change either fully or partially outside of the table.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/global-filtering#onglobalfilterchange)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/global-filtering)\n */\n onGlobalFilterChange?: OnChangeFn\n}\n\nexport interface GlobalFilterInstance {\n /**\n * Currently, this function returns the built-in `includesString` filter function. In future releases, it may return more dynamic filter functions based on the nature of the data provided.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/global-filtering#getglobalautofilterfn)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/global-filtering)\n */\n getGlobalAutoFilterFn: () => FilterFn | undefined\n /**\n * Returns the filter function (either user-defined or automatic, depending on configuration) for the global filter.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/global-filtering#getglobalfilterfn)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/global-filtering)\n */\n getGlobalFilterFn: () => FilterFn | undefined\n /**\n * Resets the **globalFilter** state to `initialState.globalFilter`, or `true` can be passed to force a default blank state reset to `undefined`.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/global-filtering#resetglobalfilter)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/global-filtering)\n */\n resetGlobalFilter: (defaultState?: boolean) => void\n /**\n * Sets or updates the `state.globalFilter` state.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/global-filtering#setglobalfilter)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/global-filtering)\n */\n setGlobalFilter: (updater: Updater) => void\n}\n\n//\n\nexport const GlobalFiltering: TableFeature = {\n getInitialState: (state): GlobalFilterTableState => {\n return {\n globalFilter: undefined,\n ...state,\n }\n },\n\n getDefaultOptions: (\n table: Table\n ): GlobalFilterOptions => {\n return {\n onGlobalFilterChange: makeStateUpdater('globalFilter', table),\n globalFilterFn: 'auto',\n getColumnCanGlobalFilter: column => {\n const value = table\n .getCoreRowModel()\n .flatRows[0]?._getAllCellsByColumnId()\n [column.id]?.getValue()\n\n return typeof value === 'string' || typeof value === 'number'\n },\n } as GlobalFilterOptions\n },\n\n createColumn: (\n column: Column,\n table: Table\n ): void => {\n column.getCanGlobalFilter = () => {\n return (\n (column.columnDef.enableGlobalFilter ?? true) &&\n (table.options.enableGlobalFilter ?? true) &&\n (table.options.enableFilters ?? true) &&\n (table.options.getColumnCanGlobalFilter?.(column) ?? true) &&\n !!column.accessorFn\n )\n }\n },\n\n createTable: (table: Table): void => {\n table.getGlobalAutoFilterFn = () => {\n return filterFns.includesString\n }\n\n table.getGlobalFilterFn = () => {\n const { globalFilterFn: globalFilterFn } = table.options\n\n return isFunction(globalFilterFn)\n ? globalFilterFn\n : globalFilterFn === 'auto'\n ? table.getGlobalAutoFilterFn()\n : table.options.filterFns?.[globalFilterFn as string] ??\n filterFns[globalFilterFn as BuiltInFilterFn]\n }\n\n table.setGlobalFilter = updater => {\n table.options.onGlobalFilterChange?.(updater)\n }\n\n table.resetGlobalFilter = defaultState => {\n table.setGlobalFilter(\n defaultState ? undefined : table.initialState.globalFilter\n )\n }\n },\n}\n", "import { RowModel } from '..'\nimport {\n OnChangeFn,\n Table,\n Row,\n Updater,\n RowData,\n TableFeature,\n} from '../types'\nimport { makeStateUpdater } from '../utils'\n\nexport type ExpandedStateList = Record\nexport type ExpandedState = true | Record\nexport interface ExpandedTableState {\n expanded: ExpandedState\n}\n\nexport interface ExpandedRow {\n /**\n * Returns whether the row can be expanded.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/expanding#getcanexpand)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/expanding)\n */\n getCanExpand: () => boolean\n /**\n * Returns whether all parent rows of the row are expanded.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/expanding#getisallparentsexpanded)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/expanding)\n */\n getIsAllParentsExpanded: () => boolean\n /**\n * Returns whether the row is expanded.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/expanding#getisexpanded)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/expanding)\n */\n getIsExpanded: () => boolean\n /**\n * Returns a function that can be used to toggle the expanded state of the row. This function can be used to bind to an event handler to a button.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/expanding#gettoggleexpandedhandler)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/expanding)\n */\n getToggleExpandedHandler: () => () => void\n /**\n * Toggles the expanded state (or sets it if `expanded` is provided) for the row.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/expanding#toggleexpanded)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/expanding)\n */\n toggleExpanded: (expanded?: boolean) => void\n}\n\nexport interface ExpandedOptions {\n /**\n * Enable this setting to automatically reset the expanded state of the table when expanding state changes.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/expanding#autoresetexpanded)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/expanding)\n */\n autoResetExpanded?: boolean\n /**\n * Enable/disable expanding for all rows.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/expanding#enableexpanding)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/expanding)\n */\n enableExpanding?: boolean\n /**\n * This function is responsible for returning the expanded row model. If this function is not provided, the table will not expand rows. You can use the default exported `getExpandedRowModel` function to get the expanded row model or implement your own.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/expanding#getexpandedrowmodel)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/expanding)\n */\n getExpandedRowModel?: (table: Table) => () => RowModel\n /**\n * If provided, allows you to override the default behavior of determining whether a row is currently expanded.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/expanding#getisrowexpanded)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/expanding)\n */\n getIsRowExpanded?: (row: Row) => boolean\n /**\n * If provided, allows you to override the default behavior of determining whether a row can be expanded.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/expanding#getrowcanexpand)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/expanding)\n */\n getRowCanExpand?: (row: Row) => boolean\n /**\n * Enables manual row expansion. If this is set to `true`, `getExpandedRowModel` will not be used to expand rows and you would be expected to perform the expansion in your own data model. This is useful if you are doing server-side expansion.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/expanding#manualexpanding)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/expanding)\n */\n manualExpanding?: boolean\n /**\n * This function is called when the `expanded` table state changes. If a function is provided, you will be responsible for managing this state on your own. To pass the managed state back to the table, use the `tableOptions.state.expanded` option.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/expanding#onexpandedchange)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/expanding)\n */\n onExpandedChange?: OnChangeFn\n /**\n * If `true` expanded rows will be paginated along with the rest of the table (which means expanded rows may span multiple pages). If `false` expanded rows will not be considered for pagination (which means expanded rows will always render on their parents page. This also means more rows will be rendered than the set page size)\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/expanding#paginateexpandedrows)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/expanding)\n */\n paginateExpandedRows?: boolean\n}\n\nexport interface ExpandedInstance {\n _autoResetExpanded: () => void\n _getExpandedRowModel?: () => RowModel\n /**\n * Returns whether there are any rows that can be expanded.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/expanding#getcansomerowsexpand)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/expanding)\n */\n getCanSomeRowsExpand: () => boolean\n /**\n * Returns the maximum depth of the expanded rows.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/expanding#getexpandeddepth)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/expanding)\n */\n getExpandedDepth: () => number\n /**\n * Returns the row model after expansion has been applied.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/expanding#getexpandedrowmodel)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/expanding)\n */\n getExpandedRowModel: () => RowModel\n /**\n * Returns whether all rows are currently expanded.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/expanding#getisallrowsexpanded)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/expanding)\n */\n getIsAllRowsExpanded: () => boolean\n /**\n * Returns whether there are any rows that are currently expanded.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/expanding#getissomerowsexpanded)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/expanding)\n */\n getIsSomeRowsExpanded: () => boolean\n /**\n * Returns the row model before expansion has been applied.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/expanding#getpreexpandedrowmodel)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/expanding)\n */\n getPreExpandedRowModel: () => RowModel\n /**\n * Returns a handler that can be used to toggle the expanded state of all rows. This handler is meant to be used with an `input[type=checkbox]` element.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/expanding#gettoggleallrowsexpandedhandler)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/expanding)\n */\n getToggleAllRowsExpandedHandler: () => (event: unknown) => void\n /**\n * Resets the expanded state of the table to the initial state.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/expanding#resetexpanded)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/expanding)\n */\n resetExpanded: (defaultState?: boolean) => void\n /**\n * Updates the expanded state of the table via an update function or value.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/expanding#setexpanded)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/expanding)\n */\n setExpanded: (updater: Updater) => void\n /**\n * Toggles the expanded state for all rows.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/expanding#toggleallrowsexpanded)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/expanding)\n */\n toggleAllRowsExpanded: (expanded?: boolean) => void\n}\n\n//\n\nexport const RowExpanding: TableFeature = {\n getInitialState: (state): ExpandedTableState => {\n return {\n expanded: {},\n ...state,\n }\n },\n\n getDefaultOptions: (\n table: Table\n ): ExpandedOptions => {\n return {\n onExpandedChange: makeStateUpdater('expanded', table),\n paginateExpandedRows: true,\n }\n },\n\n createTable: (table: Table): void => {\n let registered = false\n let queued = false\n\n table._autoResetExpanded = () => {\n if (!registered) {\n table._queue(() => {\n registered = true\n })\n return\n }\n\n if (\n table.options.autoResetAll ??\n table.options.autoResetExpanded ??\n !table.options.manualExpanding\n ) {\n if (queued) return\n queued = true\n table._queue(() => {\n table.resetExpanded()\n queued = false\n })\n }\n }\n table.setExpanded = updater => table.options.onExpandedChange?.(updater)\n table.toggleAllRowsExpanded = expanded => {\n if (expanded ?? !table.getIsAllRowsExpanded()) {\n table.setExpanded(true)\n } else {\n table.setExpanded({})\n }\n }\n table.resetExpanded = defaultState => {\n table.setExpanded(defaultState ? {} : table.initialState?.expanded ?? {})\n }\n table.getCanSomeRowsExpand = () => {\n return table\n .getPrePaginationRowModel()\n .flatRows.some(row => row.getCanExpand())\n }\n table.getToggleAllRowsExpandedHandler = () => {\n return (e: unknown) => {\n ;(e as any).persist?.()\n table.toggleAllRowsExpanded()\n }\n }\n table.getIsSomeRowsExpanded = () => {\n const expanded = table.getState().expanded\n return expanded === true || Object.values(expanded).some(Boolean)\n }\n table.getIsAllRowsExpanded = () => {\n const expanded = table.getState().expanded\n\n // If expanded is true, save some cycles and return true\n if (typeof expanded === 'boolean') {\n return expanded === true\n }\n\n if (!Object.keys(expanded).length) {\n return false\n }\n\n // If any row is not expanded, return false\n if (table.getRowModel().flatRows.some(row => !row.getIsExpanded())) {\n return false\n }\n\n // They must all be expanded :shrug:\n return true\n }\n table.getExpandedDepth = () => {\n let maxDepth = 0\n\n const rowIds =\n table.getState().expanded === true\n ? Object.keys(table.getRowModel().rowsById)\n : Object.keys(table.getState().expanded)\n\n rowIds.forEach(id => {\n const splitId = id.split('.')\n maxDepth = Math.max(maxDepth, splitId.length)\n })\n\n return maxDepth\n }\n table.getPreExpandedRowModel = () => table.getSortedRowModel()\n table.getExpandedRowModel = () => {\n if (!table._getExpandedRowModel && table.options.getExpandedRowModel) {\n table._getExpandedRowModel = table.options.getExpandedRowModel(table)\n }\n\n if (table.options.manualExpanding || !table._getExpandedRowModel) {\n return table.getPreExpandedRowModel()\n }\n\n return table._getExpandedRowModel()\n }\n },\n\n createRow: (\n row: Row,\n table: Table\n ): void => {\n row.toggleExpanded = expanded => {\n table.setExpanded(old => {\n const exists = old === true ? true : !!old?.[row.id]\n\n let oldExpanded: ExpandedStateList = {}\n\n if (old === true) {\n Object.keys(table.getRowModel().rowsById).forEach(rowId => {\n oldExpanded[rowId] = true\n })\n } else {\n oldExpanded = old\n }\n\n expanded = expanded ?? !exists\n\n if (!exists && expanded) {\n return {\n ...oldExpanded,\n [row.id]: true,\n }\n }\n\n if (exists && !expanded) {\n const { [row.id]: _, ...rest } = oldExpanded\n return rest\n }\n\n return old\n })\n }\n row.getIsExpanded = () => {\n const expanded = table.getState().expanded\n\n return !!(\n table.options.getIsRowExpanded?.(row) ??\n (expanded === true || expanded?.[row.id])\n )\n }\n row.getCanExpand = () => {\n return (\n table.options.getRowCanExpand?.(row) ??\n ((table.options.enableExpanding ?? true) && !!row.subRows?.length)\n )\n }\n row.getIsAllParentsExpanded = () => {\n let isFullyExpanded = true\n let currentRow = row\n\n while (isFullyExpanded && currentRow.parentId) {\n currentRow = table.getRow(currentRow.parentId, true)\n isFullyExpanded = currentRow.getIsExpanded()\n }\n\n return isFullyExpanded\n }\n row.getToggleExpandedHandler = () => {\n const canExpand = row.getCanExpand()\n\n return () => {\n if (!canExpand) return\n row.toggleExpanded()\n }\n }\n },\n}\n", "import {\n OnChangeFn,\n Table,\n RowModel,\n Updater,\n RowData,\n TableFeature,\n} from '../types'\nimport {\n functionalUpdate,\n getMemoOptions,\n makeStateUpdater,\n memo,\n} from '../utils'\n\nexport interface PaginationState {\n pageIndex: number\n pageSize: number\n}\n\nexport interface PaginationTableState {\n pagination: PaginationState\n}\n\nexport interface PaginationInitialTableState {\n pagination?: Partial\n}\n\nexport interface PaginationOptions {\n /**\n * If set to `true`, pagination will be reset to the first page when page-altering state changes eg. `data` is updated, filters change, grouping changes, etc.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/pagination#autoresetpageindex)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/pagination)\n */\n autoResetPageIndex?: boolean\n /**\n * Returns the row model after pagination has taken place, but no further.\n *\n * Pagination columns are automatically reordered by default to the start of the columns list. If you would rather remove them or leave them as-is, set the appropriate mode here.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/pagination#getpaginationrowmodel)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/pagination)\n */\n getPaginationRowModel?: (table: Table) => () => RowModel\n /**\n * Enables manual pagination. If this option is set to `true`, the table will not automatically paginate rows using `getPaginationRowModel()` and instead will expect you to manually paginate the rows before passing them to the table. This is useful if you are doing server-side pagination and aggregation.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/pagination#manualpagination)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/pagination)\n */\n manualPagination?: boolean\n /**\n * If this function is provided, it will be called when the pagination state changes and you will be expected to manage the state yourself. You can pass the managed state back to the table via the `tableOptions.state.pagination` option.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/pagination#onpaginationchange)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/pagination)\n */\n onPaginationChange?: OnChangeFn\n /**\n * When manually controlling pagination, you can supply a total `pageCount` value to the table if you know it (Or supply a `rowCount` and `pageCount` will be calculated). If you do not know how many pages there are, you can set this to `-1`.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/pagination#pagecount)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/pagination)\n */\n pageCount?: number\n /**\n * When manually controlling pagination, you can supply a total `rowCount` value to the table if you know it. The `pageCount` can be calculated from this value and the `pageSize`.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/pagination#rowcount)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/pagination)\n */\n rowCount?: number\n}\n\nexport interface PaginationDefaultOptions {\n onPaginationChange: OnChangeFn\n}\n\nexport interface PaginationInstance {\n _autoResetPageIndex: () => void\n _getPaginationRowModel?: () => RowModel\n /**\n * Returns whether the table can go to the next page.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/pagination#getcannextpage)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/pagination)\n */\n getCanNextPage: () => boolean\n /**\n * Returns whether the table can go to the previous page.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/pagination#getcanpreviouspage)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/pagination)\n */\n getCanPreviousPage: () => boolean\n /**\n * Returns the page count. If manually paginating or controlling the pagination state, this will come directly from the `options.pageCount` table option, otherwise it will be calculated from the table data using the total row count and current page size.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/pagination#getpagecount)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/pagination)\n */\n getPageCount: () => number\n /**\n * Returns the row count. If manually paginating or controlling the pagination state, this will come directly from the `options.rowCount` table option, otherwise it will be calculated from the table data.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/pagination#getrowcount)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/pagination)\n */\n getRowCount: () => number\n /**\n * Returns an array of page options (zero-index-based) for the current page size.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/pagination#getpageoptions)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/pagination)\n */\n getPageOptions: () => number[]\n /**\n * Returns the row model for the table after pagination has been applied.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/pagination#getpaginationrowmodel)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/pagination)\n */\n getPaginationRowModel: () => RowModel\n /**\n * Returns the row model for the table before any pagination has been applied.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/pagination#getprepaginationrowmodel)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/pagination)\n */\n getPrePaginationRowModel: () => RowModel\n /**\n * Increments the page index by one, if possible.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/pagination#nextpage)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/pagination)\n */\n nextPage: () => void\n /**\n * Decrements the page index by one, if possible.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/pagination#previouspage)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/pagination)\n */\n previousPage: () => void\n /**\n * Sets the page index to `0`.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/pagination#firstpage)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/pagination)\n */\n firstPage: () => void\n /**\n * Sets the page index to the last page.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/pagination#lastpage)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/pagination)\n */\n lastPage: () => void\n /**\n * Resets the page index to its initial state. If `defaultState` is `true`, the page index will be reset to `0` regardless of initial state.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/pagination#resetpageindex)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/pagination)\n */\n resetPageIndex: (defaultState?: boolean) => void\n /**\n * Resets the page size to its initial state. If `defaultState` is `true`, the page size will be reset to `10` regardless of initial state.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/pagination#resetpagesize)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/pagination)\n */\n resetPageSize: (defaultState?: boolean) => void\n /**\n * Resets the **pagination** state to `initialState.pagination`, or `true` can be passed to force a default blank state reset to `[]`.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/pagination#resetpagination)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/pagination)\n */\n resetPagination: (defaultState?: boolean) => void\n /**\n * @deprecated The page count no longer exists in the pagination state. Just pass as a table option instead.\n */\n setPageCount: (updater: Updater) => void\n /**\n * Updates the page index using the provided function or value in the `state.pagination.pageIndex` state.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/pagination#setpageindex)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/pagination)\n */\n setPageIndex: (updater: Updater) => void\n /**\n * Updates the page size using the provided function or value in the `state.pagination.pageSize` state.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/pagination#setpagesize)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/pagination)\n */\n setPageSize: (updater: Updater) => void\n /**\n * Sets or updates the `state.pagination` state.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/pagination#setpagination)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/pagination)\n */\n setPagination: (updater: Updater) => void\n}\n\n//\n\nconst defaultPageIndex = 0\nconst defaultPageSize = 10\n\nconst getDefaultPaginationState = (): PaginationState => ({\n pageIndex: defaultPageIndex,\n pageSize: defaultPageSize,\n})\n\nexport const RowPagination: TableFeature = {\n getInitialState: (state): PaginationTableState => {\n return {\n ...state,\n pagination: {\n ...getDefaultPaginationState(),\n ...state?.pagination,\n },\n }\n },\n\n getDefaultOptions: (\n table: Table\n ): PaginationDefaultOptions => {\n return {\n onPaginationChange: makeStateUpdater('pagination', table),\n }\n },\n\n createTable: (table: Table): void => {\n let registered = false\n let queued = false\n\n table._autoResetPageIndex = () => {\n if (!registered) {\n table._queue(() => {\n registered = true\n })\n return\n }\n\n if (\n table.options.autoResetAll ??\n table.options.autoResetPageIndex ??\n !table.options.manualPagination\n ) {\n if (queued) return\n queued = true\n table._queue(() => {\n table.resetPageIndex()\n queued = false\n })\n }\n }\n table.setPagination = updater => {\n const safeUpdater: Updater = old => {\n let newState = functionalUpdate(updater, old)\n\n return newState\n }\n\n return table.options.onPaginationChange?.(safeUpdater)\n }\n table.resetPagination = defaultState => {\n table.setPagination(\n defaultState\n ? getDefaultPaginationState()\n : table.initialState.pagination ?? getDefaultPaginationState()\n )\n }\n table.setPageIndex = updater => {\n table.setPagination(old => {\n let pageIndex = functionalUpdate(updater, old.pageIndex)\n\n const maxPageIndex =\n typeof table.options.pageCount === 'undefined' ||\n table.options.pageCount === -1\n ? Number.MAX_SAFE_INTEGER\n : table.options.pageCount - 1\n\n pageIndex = Math.max(0, Math.min(pageIndex, maxPageIndex))\n\n return {\n ...old,\n pageIndex,\n }\n })\n }\n table.resetPageIndex = defaultState => {\n table.setPageIndex(\n defaultState\n ? defaultPageIndex\n : table.initialState?.pagination?.pageIndex ?? defaultPageIndex\n )\n }\n table.resetPageSize = defaultState => {\n table.setPageSize(\n defaultState\n ? defaultPageSize\n : table.initialState?.pagination?.pageSize ?? defaultPageSize\n )\n }\n table.setPageSize = updater => {\n table.setPagination(old => {\n const pageSize = Math.max(1, functionalUpdate(updater, old.pageSize))\n const topRowIndex = old.pageSize * old.pageIndex!\n const pageIndex = Math.floor(topRowIndex / pageSize)\n\n return {\n ...old,\n pageIndex,\n pageSize,\n }\n })\n }\n //deprecated\n table.setPageCount = updater =>\n table.setPagination(old => {\n let newPageCount = functionalUpdate(\n updater,\n table.options.pageCount ?? -1\n )\n\n if (typeof newPageCount === 'number') {\n newPageCount = Math.max(-1, newPageCount)\n }\n\n return {\n ...old,\n pageCount: newPageCount,\n }\n })\n\n table.getPageOptions = memo(\n () => [table.getPageCount()],\n pageCount => {\n let pageOptions: number[] = []\n if (pageCount && pageCount > 0) {\n pageOptions = [...new Array(pageCount)].fill(null).map((_, i) => i)\n }\n return pageOptions\n },\n getMemoOptions(table.options, 'debugTable', 'getPageOptions')\n )\n\n table.getCanPreviousPage = () => table.getState().pagination.pageIndex > 0\n\n table.getCanNextPage = () => {\n const { pageIndex } = table.getState().pagination\n\n const pageCount = table.getPageCount()\n\n if (pageCount === -1) {\n return true\n }\n\n if (pageCount === 0) {\n return false\n }\n\n return pageIndex < pageCount - 1\n }\n\n table.previousPage = () => {\n return table.setPageIndex(old => old - 1)\n }\n\n table.nextPage = () => {\n return table.setPageIndex(old => {\n return old + 1\n })\n }\n\n table.firstPage = () => {\n return table.setPageIndex(0)\n }\n\n table.lastPage = () => {\n return table.setPageIndex(table.getPageCount() - 1)\n }\n\n table.getPrePaginationRowModel = () => table.getExpandedRowModel()\n table.getPaginationRowModel = () => {\n if (\n !table._getPaginationRowModel &&\n table.options.getPaginationRowModel\n ) {\n table._getPaginationRowModel =\n table.options.getPaginationRowModel(table)\n }\n\n if (table.options.manualPagination || !table._getPaginationRowModel) {\n return table.getPrePaginationRowModel()\n }\n\n return table._getPaginationRowModel()\n }\n\n table.getPageCount = () => {\n return (\n table.options.pageCount ??\n Math.ceil(table.getRowCount() / table.getState().pagination.pageSize)\n )\n }\n\n table.getRowCount = () => {\n return (\n table.options.rowCount ?? table.getPrePaginationRowModel().rows.length\n )\n }\n },\n}\n", "import {\n OnChangeFn,\n Updater,\n Table,\n Row,\n RowData,\n TableFeature,\n} from '../types'\nimport { getMemoOptions, makeStateUpdater, memo } from '../utils'\n\nexport type RowPinningPosition = false | 'top' | 'bottom'\n\nexport interface RowPinningState {\n bottom?: string[]\n top?: string[]\n}\n\nexport interface RowPinningTableState {\n rowPinning: RowPinningState\n}\n\nexport interface RowPinningOptions {\n /**\n * Enables/disables row pinning for the table. Defaults to `true`.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/row-pinning#enablerowpinning)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/row-pinning)\n */\n enableRowPinning?: boolean | ((row: Row) => boolean)\n /**\n * When `false`, pinned rows will not be visible if they are filtered or paginated out of the table. When `true`, pinned rows will always be visible regardless of filtering or pagination. Defaults to `true`.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/row-pinning#keeppinnedrows)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/row-pinning)\n */\n keepPinnedRows?: boolean\n /**\n * If provided, this function will be called with an `updaterFn` when `state.rowPinning` changes. This overrides the default internal state management, so you will also need to supply `state.rowPinning` from your own managed state.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/row-pinning#onrowpinningchange)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/onrowpinningchange)\n */\n onRowPinningChange?: OnChangeFn\n}\n\nexport interface RowPinningDefaultOptions {\n onRowPinningChange: OnChangeFn\n}\n\nexport interface RowPinningRow {\n /**\n * Returns whether or not the row can be pinned.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/row-pinning#getcanpin-1)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/row-pinning)\n */\n getCanPin: () => boolean\n /**\n * Returns the pinned position of the row. (`'top'`, `'bottom'` or `false`)\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/row-pinning#getispinned-1)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/row-pinning)\n */\n getIsPinned: () => RowPinningPosition\n /**\n * Returns the numeric pinned index of the row within a pinned row group.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/row-pinning#getpinnedindex-1)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/row-pinning)\n */\n getPinnedIndex: () => number\n /**\n * Pins a row to the `'top'` or `'bottom'`, or unpins the row to the center if `false` is passed.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/row-pinning#pin-1)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/row-pinning)\n */\n pin: (\n position: RowPinningPosition,\n includeLeafRows?: boolean,\n includeParentRows?: boolean\n ) => void\n}\n\nexport interface RowPinningInstance {\n _getPinnedRows: (\n visiblePinnedRows: Array>,\n pinnedRowIds: Array | undefined,\n position: 'top' | 'bottom'\n ) => Row[]\n /**\n * Returns all bottom pinned rows.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/row-pinning#getbottomrows)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/row-pinning)\n */\n getBottomRows: () => Row[]\n /**\n * Returns all rows that are not pinned to the top or bottom.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/row-pinning#getcenterrows)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/row-pinning)\n */\n getCenterRows: () => Row[]\n /**\n * Returns whether or not any rows are pinned. Optionally specify to only check for pinned rows in either the `top` or `bottom` position.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/row-pinning#getissomerowspinned)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/row-pinning)\n */\n getIsSomeRowsPinned: (position?: RowPinningPosition) => boolean\n /**\n * Returns all top pinned rows.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/row-pinning#gettoprows)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/row-pinning)\n */\n getTopRows: () => Row[]\n /**\n * Resets the **rowPinning** state to `initialState.rowPinning`, or `true` can be passed to force a default blank state reset to `{ top: [], bottom: [], }`.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/row-pinning#resetrowpinning)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/row-pinning)\n */\n resetRowPinning: (defaultState?: boolean) => void\n /**\n * Sets or updates the `state.rowPinning` state.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/row-pinning#setrowpinning)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/row-pinning)\n */\n setRowPinning: (updater: Updater) => void\n}\n\n//\n\nconst getDefaultRowPinningState = (): RowPinningState => ({\n top: [],\n bottom: [],\n})\n\nexport const RowPinning: TableFeature = {\n getInitialState: (state): RowPinningTableState => {\n return {\n rowPinning: getDefaultRowPinningState(),\n ...state,\n }\n },\n\n getDefaultOptions: (\n table: Table\n ): RowPinningDefaultOptions => {\n return {\n onRowPinningChange: makeStateUpdater('rowPinning', table),\n }\n },\n\n createRow: (\n row: Row,\n table: Table\n ): void => {\n row.pin = (position, includeLeafRows, includeParentRows) => {\n const leafRowIds = includeLeafRows\n ? row.getLeafRows().map(({ id }) => id)\n : []\n const parentRowIds = includeParentRows\n ? row.getParentRows().map(({ id }) => id)\n : []\n const rowIds = new Set([...parentRowIds, row.id, ...leafRowIds])\n\n table.setRowPinning(old => {\n if (position === 'bottom') {\n return {\n top: (old?.top ?? []).filter(d => !rowIds?.has(d)),\n bottom: [\n ...(old?.bottom ?? []).filter(d => !rowIds?.has(d)),\n ...Array.from(rowIds),\n ],\n }\n }\n\n if (position === 'top') {\n return {\n top: [\n ...(old?.top ?? []).filter(d => !rowIds?.has(d)),\n ...Array.from(rowIds),\n ],\n bottom: (old?.bottom ?? []).filter(d => !rowIds?.has(d)),\n }\n }\n\n return {\n top: (old?.top ?? []).filter(d => !rowIds?.has(d)),\n bottom: (old?.bottom ?? []).filter(d => !rowIds?.has(d)),\n }\n })\n }\n row.getCanPin = () => {\n const { enableRowPinning, enablePinning } = table.options\n if (typeof enableRowPinning === 'function') {\n return enableRowPinning(row)\n }\n return enableRowPinning ?? enablePinning ?? true\n }\n row.getIsPinned = () => {\n const rowIds = [row.id]\n\n const { top, bottom } = table.getState().rowPinning\n\n const isTop = rowIds.some(d => top?.includes(d))\n const isBottom = rowIds.some(d => bottom?.includes(d))\n\n return isTop ? 'top' : isBottom ? 'bottom' : false\n }\n row.getPinnedIndex = () => {\n const position = row.getIsPinned()\n if (!position) return -1\n\n const visiblePinnedRowIds = (\n position === 'top' ? table.getTopRows() : table.getBottomRows()\n )?.map(({ id }) => id)\n\n return visiblePinnedRowIds?.indexOf(row.id) ?? -1\n }\n },\n\n createTable: (table: Table): void => {\n table.setRowPinning = updater => table.options.onRowPinningChange?.(updater)\n\n table.resetRowPinning = defaultState =>\n table.setRowPinning(\n defaultState\n ? getDefaultRowPinningState()\n : table.initialState?.rowPinning ?? getDefaultRowPinningState()\n )\n\n table.getIsSomeRowsPinned = position => {\n const pinningState = table.getState().rowPinning\n\n if (!position) {\n return Boolean(pinningState.top?.length || pinningState.bottom?.length)\n }\n return Boolean(pinningState[position]?.length)\n }\n\n table._getPinnedRows = (visibleRows, pinnedRowIds, position) => {\n const rows =\n table.options.keepPinnedRows ?? true\n ? //get all rows that are pinned even if they would not be otherwise visible\n //account for expanded parent rows, but not pagination or filtering\n (pinnedRowIds ?? []).map(rowId => {\n const row = table.getRow(rowId, true)\n return row.getIsAllParentsExpanded() ? row : null\n })\n : //else get only visible rows that are pinned\n (pinnedRowIds ?? []).map(\n rowId => visibleRows.find(row => row.id === rowId)!\n )\n\n return rows.filter(Boolean).map(d => ({ ...d, position })) as Row[]\n }\n\n table.getTopRows = memo(\n () => [table.getRowModel().rows, table.getState().rowPinning.top],\n (allRows, topPinnedRowIds) =>\n table._getPinnedRows(allRows, topPinnedRowIds, 'top'),\n getMemoOptions(table.options, 'debugRows', 'getTopRows')\n )\n\n table.getBottomRows = memo(\n () => [table.getRowModel().rows, table.getState().rowPinning.bottom],\n (allRows, bottomPinnedRowIds) =>\n table._getPinnedRows(allRows, bottomPinnedRowIds, 'bottom'),\n getMemoOptions(table.options, 'debugRows', 'getBottomRows')\n )\n\n table.getCenterRows = memo(\n () => [\n table.getRowModel().rows,\n table.getState().rowPinning.top,\n table.getState().rowPinning.bottom,\n ],\n (allRows, top, bottom) => {\n const topAndBottom = new Set([...(top ?? []), ...(bottom ?? [])])\n return allRows.filter(d => !topAndBottom.has(d.id))\n },\n getMemoOptions(table.options, 'debugRows', 'getCenterRows')\n )\n },\n}\n", "import {\n OnChangeFn,\n Table,\n Row,\n RowModel,\n Updater,\n RowData,\n TableFeature,\n} from '../types'\nimport { getMemoOptions, makeStateUpdater, memo } from '../utils'\n\nexport type RowSelectionState = Record\n\nexport interface RowSelectionTableState {\n rowSelection: RowSelectionState\n}\n\nexport interface RowSelectionOptions {\n /**\n * - Enables/disables multiple row selection for all rows in the table OR\n * - A function that given a row, returns whether to enable/disable multiple row selection for that row's children/grandchildren\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/row-selection#enablemultirowselection)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/row-selection)\n */\n enableMultiRowSelection?: boolean | ((row: Row) => boolean)\n /**\n * - Enables/disables row selection for all rows in the table OR\n * - A function that given a row, returns whether to enable/disable row selection for that row\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/row-selection#enablerowselection)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/row-selection)\n */\n enableRowSelection?: boolean | ((row: Row) => boolean)\n /**\n * Enables/disables automatic sub-row selection when a parent row is selected, or a function that enables/disables automatic sub-row selection for each row.\n * (Use in combination with expanding or grouping features)\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/row-selection#enablesubrowselection)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/row-selection)\n */\n enableSubRowSelection?: boolean | ((row: Row) => boolean)\n /**\n * If provided, this function will be called with an `updaterFn` when `state.rowSelection` changes. This overrides the default internal state management, so you will need to persist the state change either fully or partially outside of the table.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/row-selection#onrowselectionchange)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/row-selection)\n */\n onRowSelectionChange?: OnChangeFn\n // enableGroupingRowSelection?:\n // | boolean\n // | ((\n // row: Row\n // ) => boolean)\n // isAdditiveSelectEvent?: (e: unknown) => boolean\n // isInclusiveSelectEvent?: (e: unknown) => boolean\n // selectRowsFn?: (\n // table: Table,\n // rowModel: RowModel\n // ) => RowModel\n}\n\nexport interface RowSelectionRow {\n /**\n * Returns whether or not the row can multi-select.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/row-selection#getcanmultiselect)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/row-selection)\n */\n getCanMultiSelect: () => boolean\n /**\n * Returns whether or not the row can be selected.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/row-selection#getcanselect)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/row-selection)\n */\n getCanSelect: () => boolean\n /**\n * Returns whether or not the row can select sub rows automatically when the parent row is selected.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/row-selection#getcanselectsubrows)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/row-selection)\n */\n getCanSelectSubRows: () => boolean\n /**\n * Returns whether or not all of the row's sub rows are selected.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/row-selection#getisallsubrowsselected)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/row-selection)\n */\n getIsAllSubRowsSelected: () => boolean\n /**\n * Returns whether or not the row is selected.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/row-selection#getisselected)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/row-selection)\n */\n getIsSelected: () => boolean\n /**\n * Returns whether or not some of the row's sub rows are selected.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/row-selection#getissomeselected)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/row-selection)\n */\n getIsSomeSelected: () => boolean\n /**\n * Returns a handler that can be used to toggle the row.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/row-selection#gettoggleselectedhandler)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/row-selection)\n */\n getToggleSelectedHandler: () => (event: unknown) => void\n /**\n * Selects/deselects the row.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/row-selection#toggleselected)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/row-selection)\n */\n toggleSelected: (value?: boolean, opts?: { selectChildren?: boolean }) => void\n}\n\nexport interface RowSelectionInstance {\n /**\n * Returns the row model of all rows that are selected after filtering has been applied.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/row-selection#getfilteredselectedrowmodel)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/row-selection)\n */\n getFilteredSelectedRowModel: () => RowModel\n /**\n * Returns the row model of all rows that are selected after grouping has been applied.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/row-selection#getgroupedselectedrowmodel)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/row-selection)\n */\n getGroupedSelectedRowModel: () => RowModel\n /**\n * Returns whether or not all rows on the current page are selected.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/row-selection#getisallpagerowsselected)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/row-selection)\n */\n getIsAllPageRowsSelected: () => boolean\n /**\n * Returns whether or not all rows in the table are selected.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/row-selection#getisallrowsselected)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/row-selection)\n */\n getIsAllRowsSelected: () => boolean\n /**\n * Returns whether or not any rows on the current page are selected.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/row-selection#getissomepagerowsselected)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/row-selection)\n */\n getIsSomePageRowsSelected: () => boolean\n /**\n * Returns whether or not any rows in the table are selected.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/row-selection#getissomerowsselected)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/row-selection)\n */\n getIsSomeRowsSelected: () => boolean\n /**\n * Returns the core row model of all rows before row selection has been applied.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/row-selection#getpreselectedrowmodel)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/row-selection)\n */\n getPreSelectedRowModel: () => RowModel\n /**\n * Returns the row model of all rows that are selected.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/row-selection#getselectedrowmodel)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/row-selection)\n */\n getSelectedRowModel: () => RowModel\n /**\n * Returns a handler that can be used to toggle all rows on the current page.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/row-selection#gettoggleallpagerowsselectedhandler)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/row-selection)\n */\n getToggleAllPageRowsSelectedHandler: () => (event: unknown) => void\n /**\n * Returns a handler that can be used to toggle all rows in the table.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/row-selection#gettoggleallrowsselectedhandler)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/row-selection)\n */\n getToggleAllRowsSelectedHandler: () => (event: unknown) => void\n /**\n * Resets the **rowSelection** state to the `initialState.rowSelection`, or `true` can be passed to force a default blank state reset to `{}`.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/row-selection#resetrowselection)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/row-selection)\n */\n resetRowSelection: (defaultState?: boolean) => void\n /**\n * Sets or updates the `state.rowSelection` state.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/row-selection#setrowselection)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/row-selection)\n */\n setRowSelection: (updater: Updater) => void\n /**\n * Selects/deselects all rows on the current page.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/row-selection#toggleallpagerowsselected)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/row-selection)\n */\n toggleAllPageRowsSelected: (value?: boolean) => void\n /**\n * Selects/deselects all rows in the table.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/row-selection#toggleallrowsselected)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/row-selection)\n */\n toggleAllRowsSelected: (value?: boolean) => void\n}\n\n//\n\nexport const RowSelection: TableFeature = {\n getInitialState: (state): RowSelectionTableState => {\n return {\n rowSelection: {},\n ...state,\n }\n },\n\n getDefaultOptions: (\n table: Table\n ): RowSelectionOptions => {\n return {\n onRowSelectionChange: makeStateUpdater('rowSelection', table),\n enableRowSelection: true,\n enableMultiRowSelection: true,\n enableSubRowSelection: true,\n // enableGroupingRowSelection: false,\n // isAdditiveSelectEvent: (e: unknown) => !!e.metaKey,\n // isInclusiveSelectEvent: (e: unknown) => !!e.shiftKey,\n }\n },\n\n createTable: (table: Table): void => {\n table.setRowSelection = updater =>\n table.options.onRowSelectionChange?.(updater)\n table.resetRowSelection = defaultState =>\n table.setRowSelection(\n defaultState ? {} : table.initialState.rowSelection ?? {}\n )\n table.toggleAllRowsSelected = value => {\n table.setRowSelection(old => {\n value =\n typeof value !== 'undefined' ? value : !table.getIsAllRowsSelected()\n\n const rowSelection = { ...old }\n\n const preGroupedFlatRows = table.getPreGroupedRowModel().flatRows\n\n // We don't use `mutateRowIsSelected` here for performance reasons.\n // All of the rows are flat already, so it wouldn't be worth it\n if (value) {\n preGroupedFlatRows.forEach(row => {\n if (!row.getCanSelect()) {\n return\n }\n rowSelection[row.id] = true\n })\n } else {\n preGroupedFlatRows.forEach(row => {\n delete rowSelection[row.id]\n })\n }\n\n return rowSelection\n })\n }\n table.toggleAllPageRowsSelected = value =>\n table.setRowSelection(old => {\n const resolvedValue =\n typeof value !== 'undefined'\n ? value\n : !table.getIsAllPageRowsSelected()\n\n const rowSelection: RowSelectionState = { ...old }\n\n table.getRowModel().rows.forEach(row => {\n mutateRowIsSelected(rowSelection, row.id, resolvedValue, true, table)\n })\n\n return rowSelection\n })\n\n // addRowSelectionRange: rowId => {\n // const {\n // rows,\n // rowsById,\n // options: { selectGroupingRows, selectSubRows },\n // } = table\n\n // const findSelectedRow = (rows: Row[]) => {\n // let found\n // rows.find(d => {\n // if (d.getIsSelected()) {\n // found = d\n // return true\n // }\n // const subFound = findSelectedRow(d.subRows || [])\n // if (subFound) {\n // found = subFound\n // return true\n // }\n // return false\n // })\n // return found\n // }\n\n // const firstRow = findSelectedRow(rows) || rows[0]\n // const lastRow = rowsById[rowId]\n\n // let include = false\n // const selectedRowIds = {}\n\n // const addRow = (row: Row) => {\n // mutateRowIsSelected(selectedRowIds, row.id, true, {\n // rowsById,\n // selectGroupingRows: selectGroupingRows!,\n // selectSubRows: selectSubRows!,\n // })\n // }\n\n // table.rows.forEach(row => {\n // const isFirstRow = row.id === firstRow.id\n // const isLastRow = row.id === lastRow.id\n\n // if (isFirstRow || isLastRow) {\n // if (!include) {\n // include = true\n // } else if (include) {\n // addRow(row)\n // include = false\n // }\n // }\n\n // if (include) {\n // addRow(row)\n // }\n // })\n\n // table.setRowSelection(selectedRowIds)\n // },\n table.getPreSelectedRowModel = () => table.getCoreRowModel()\n table.getSelectedRowModel = memo(\n () => [table.getState().rowSelection, table.getCoreRowModel()],\n (rowSelection, rowModel) => {\n if (!Object.keys(rowSelection).length) {\n return {\n rows: [],\n flatRows: [],\n rowsById: {},\n }\n }\n\n return selectRowsFn(table, rowModel)\n },\n getMemoOptions(table.options, 'debugTable', 'getSelectedRowModel')\n )\n\n table.getFilteredSelectedRowModel = memo(\n () => [table.getState().rowSelection, table.getFilteredRowModel()],\n (rowSelection, rowModel) => {\n if (!Object.keys(rowSelection).length) {\n return {\n rows: [],\n flatRows: [],\n rowsById: {},\n }\n }\n\n return selectRowsFn(table, rowModel)\n },\n getMemoOptions(table.options, 'debugTable', 'getFilteredSelectedRowModel')\n )\n\n table.getGroupedSelectedRowModel = memo(\n () => [table.getState().rowSelection, table.getSortedRowModel()],\n (rowSelection, rowModel) => {\n if (!Object.keys(rowSelection).length) {\n return {\n rows: [],\n flatRows: [],\n rowsById: {},\n }\n }\n\n return selectRowsFn(table, rowModel)\n },\n getMemoOptions(table.options, 'debugTable', 'getGroupedSelectedRowModel')\n )\n\n ///\n\n // getGroupingRowCanSelect: rowId => {\n // const row = table.getRow(rowId)\n\n // if (!row) {\n // throw new Error()\n // }\n\n // if (typeof table.options.enableGroupingRowSelection === 'function') {\n // return table.options.enableGroupingRowSelection(row)\n // }\n\n // return table.options.enableGroupingRowSelection ?? false\n // },\n\n table.getIsAllRowsSelected = () => {\n const preGroupedFlatRows = table.getFilteredRowModel().flatRows\n const { rowSelection } = table.getState()\n\n let isAllRowsSelected = Boolean(\n preGroupedFlatRows.length && Object.keys(rowSelection).length\n )\n\n if (isAllRowsSelected) {\n if (\n preGroupedFlatRows.some(\n row => row.getCanSelect() && !rowSelection[row.id]\n )\n ) {\n isAllRowsSelected = false\n }\n }\n\n return isAllRowsSelected\n }\n\n table.getIsAllPageRowsSelected = () => {\n const paginationFlatRows = table\n .getPaginationRowModel()\n .flatRows.filter(row => row.getCanSelect())\n const { rowSelection } = table.getState()\n\n let isAllPageRowsSelected = !!paginationFlatRows.length\n\n if (\n isAllPageRowsSelected &&\n paginationFlatRows.some(row => !rowSelection[row.id])\n ) {\n isAllPageRowsSelected = false\n }\n\n return isAllPageRowsSelected\n }\n\n table.getIsSomeRowsSelected = () => {\n const totalSelected = Object.keys(\n table.getState().rowSelection ?? {}\n ).length\n return (\n totalSelected > 0 &&\n totalSelected < table.getFilteredRowModel().flatRows.length\n )\n }\n\n table.getIsSomePageRowsSelected = () => {\n const paginationFlatRows = table.getPaginationRowModel().flatRows\n return table.getIsAllPageRowsSelected()\n ? false\n : paginationFlatRows\n .filter(row => row.getCanSelect())\n .some(d => d.getIsSelected() || d.getIsSomeSelected())\n }\n\n table.getToggleAllRowsSelectedHandler = () => {\n return (e: unknown) => {\n table.toggleAllRowsSelected(\n ((e as MouseEvent).target as HTMLInputElement).checked\n )\n }\n }\n\n table.getToggleAllPageRowsSelectedHandler = () => {\n return (e: unknown) => {\n table.toggleAllPageRowsSelected(\n ((e as MouseEvent).target as HTMLInputElement).checked\n )\n }\n }\n },\n\n createRow: (\n row: Row,\n table: Table\n ): void => {\n row.toggleSelected = (value, opts) => {\n const isSelected = row.getIsSelected()\n\n table.setRowSelection(old => {\n value = typeof value !== 'undefined' ? value : !isSelected\n\n if (row.getCanSelect() && isSelected === value) {\n return old\n }\n\n const selectedRowIds = { ...old }\n\n mutateRowIsSelected(\n selectedRowIds,\n row.id,\n value,\n opts?.selectChildren ?? true,\n table\n )\n\n return selectedRowIds\n })\n }\n row.getIsSelected = () => {\n const { rowSelection } = table.getState()\n return isRowSelected(row, rowSelection)\n }\n\n row.getIsSomeSelected = () => {\n const { rowSelection } = table.getState()\n return isSubRowSelected(row, rowSelection, table) === 'some'\n }\n\n row.getIsAllSubRowsSelected = () => {\n const { rowSelection } = table.getState()\n return isSubRowSelected(row, rowSelection, table) === 'all'\n }\n\n row.getCanSelect = () => {\n if (typeof table.options.enableRowSelection === 'function') {\n return table.options.enableRowSelection(row)\n }\n\n return table.options.enableRowSelection ?? true\n }\n\n row.getCanSelectSubRows = () => {\n if (typeof table.options.enableSubRowSelection === 'function') {\n return table.options.enableSubRowSelection(row)\n }\n\n return table.options.enableSubRowSelection ?? true\n }\n\n row.getCanMultiSelect = () => {\n if (typeof table.options.enableMultiRowSelection === 'function') {\n return table.options.enableMultiRowSelection(row)\n }\n\n return table.options.enableMultiRowSelection ?? true\n }\n row.getToggleSelectedHandler = () => {\n const canSelect = row.getCanSelect()\n\n return (e: unknown) => {\n if (!canSelect) return\n row.toggleSelected(\n ((e as MouseEvent).target as HTMLInputElement)?.checked\n )\n }\n }\n },\n}\n\nconst mutateRowIsSelected = (\n selectedRowIds: Record,\n id: string,\n value: boolean,\n includeChildren: boolean,\n table: Table\n) => {\n const row = table.getRow(id, true)\n\n // const isGrouped = row.getIsGrouped()\n\n // if ( // TODO: enforce grouping row selection rules\n // !isGrouped ||\n // (isGrouped && table.options.enableGroupingRowSelection)\n // ) {\n if (value) {\n if (!row.getCanMultiSelect()) {\n Object.keys(selectedRowIds).forEach(key => delete selectedRowIds[key])\n }\n if (row.getCanSelect()) {\n selectedRowIds[id] = true\n }\n } else {\n delete selectedRowIds[id]\n }\n // }\n\n if (includeChildren && row.subRows?.length && row.getCanSelectSubRows()) {\n row.subRows.forEach(row =>\n mutateRowIsSelected(selectedRowIds, row.id, value, includeChildren, table)\n )\n }\n}\n\nexport function selectRowsFn(\n table: Table,\n rowModel: RowModel\n): RowModel {\n const rowSelection = table.getState().rowSelection\n\n const newSelectedFlatRows: Row[] = []\n const newSelectedRowsById: Record> = {}\n\n // Filters top level and nested rows\n const recurseRows = (rows: Row[], depth = 0): Row[] => {\n return rows\n .map(row => {\n const isSelected = isRowSelected(row, rowSelection)\n\n if (isSelected) {\n newSelectedFlatRows.push(row)\n newSelectedRowsById[row.id] = row\n }\n\n if (row.subRows?.length) {\n row = {\n ...row,\n subRows: recurseRows(row.subRows, depth + 1),\n }\n }\n\n if (isSelected) {\n return row\n }\n })\n .filter(Boolean) as Row[]\n }\n\n return {\n rows: recurseRows(rowModel.rows),\n flatRows: newSelectedFlatRows,\n rowsById: newSelectedRowsById,\n }\n}\n\nexport function isRowSelected(\n row: Row,\n selection: Record\n): boolean {\n return selection[row.id] ?? false\n}\n\nexport function isSubRowSelected(\n row: Row,\n selection: Record,\n table: Table\n): boolean | 'some' | 'all' {\n if (!row.subRows?.length) return false\n\n let allChildrenSelected = true\n let someSelected = false\n\n row.subRows.forEach(subRow => {\n // Bail out early if we know both of these\n if (someSelected && !allChildrenSelected) {\n return\n }\n\n if (subRow.getCanSelect()) {\n if (isRowSelected(subRow, selection)) {\n someSelected = true\n } else {\n allChildrenSelected = false\n }\n }\n\n // Check row selection of nested subrows\n if (subRow.subRows && subRow.subRows.length) {\n const subRowChildrenSelected = isSubRowSelected(subRow, selection, table)\n if (subRowChildrenSelected === 'all') {\n someSelected = true\n } else if (subRowChildrenSelected === 'some') {\n someSelected = true\n allChildrenSelected = false\n } else {\n allChildrenSelected = false\n }\n }\n })\n\n return allChildrenSelected ? 'all' : someSelected ? 'some' : false\n}\n", "import { SortingFn } from './features/RowSorting'\n\nexport const reSplitAlphaNumeric = /([0-9]+)/gm\n\nconst alphanumeric: SortingFn = (rowA, rowB, columnId) => {\n return compareAlphanumeric(\n toString(rowA.getValue(columnId)).toLowerCase(),\n toString(rowB.getValue(columnId)).toLowerCase()\n )\n}\n\nconst alphanumericCaseSensitive: SortingFn = (rowA, rowB, columnId) => {\n return compareAlphanumeric(\n toString(rowA.getValue(columnId)),\n toString(rowB.getValue(columnId))\n )\n}\n\n// The text filter is more basic (less numeric support)\n// but is much faster\nconst text: SortingFn = (rowA, rowB, columnId) => {\n return compareBasic(\n toString(rowA.getValue(columnId)).toLowerCase(),\n toString(rowB.getValue(columnId)).toLowerCase()\n )\n}\n\n// The text filter is more basic (less numeric support)\n// but is much faster\nconst textCaseSensitive: SortingFn = (rowA, rowB, columnId) => {\n return compareBasic(\n toString(rowA.getValue(columnId)),\n toString(rowB.getValue(columnId))\n )\n}\n\nconst datetime: SortingFn = (rowA, rowB, columnId) => {\n const a = rowA.getValue(columnId)\n const b = rowB.getValue(columnId)\n\n // Can handle nullish values\n // Use > and < because == (and ===) doesn't work with\n // Date objects (would require calling getTime()).\n return a > b ? 1 : a < b ? -1 : 0\n}\n\nconst basic: SortingFn = (rowA, rowB, columnId) => {\n return compareBasic(rowA.getValue(columnId), rowB.getValue(columnId))\n}\n\n// Utils\n\nfunction compareBasic(a: any, b: any) {\n return a === b ? 0 : a > b ? 1 : -1\n}\n\nfunction toString(a: any) {\n if (typeof a === 'number') {\n if (isNaN(a) || a === Infinity || a === -Infinity) {\n return ''\n }\n return String(a)\n }\n if (typeof a === 'string') {\n return a\n }\n return ''\n}\n\n// Mixed sorting is slow, but very inclusive of many edge cases.\n// It handles numbers, mixed alphanumeric combinations, and even\n// null, undefined, and Infinity\nfunction compareAlphanumeric(aStr: string, bStr: string) {\n // Split on number groups, but keep the delimiter\n // Then remove falsey split values\n const a = aStr.split(reSplitAlphaNumeric).filter(Boolean)\n const b = bStr.split(reSplitAlphaNumeric).filter(Boolean)\n\n // While\n while (a.length && b.length) {\n const aa = a.shift()!\n const bb = b.shift()!\n\n const an = parseInt(aa, 10)\n const bn = parseInt(bb, 10)\n\n const combo = [an, bn].sort()\n\n // Both are string\n if (isNaN(combo[0]!)) {\n if (aa > bb) {\n return 1\n }\n if (bb > aa) {\n return -1\n }\n continue\n }\n\n // One is a string, one is a number\n if (isNaN(combo[1]!)) {\n return isNaN(an) ? -1 : 1\n }\n\n // Both are numbers\n if (an > bn) {\n return 1\n }\n if (bn > an) {\n return -1\n }\n }\n\n return a.length - b.length\n}\n\n// Exports\n\nexport const sortingFns = {\n alphanumeric,\n alphanumericCaseSensitive,\n text,\n textCaseSensitive,\n datetime,\n basic,\n}\n\nexport type BuiltInSortingFn = keyof typeof sortingFns\n", "import { RowModel } from '..'\nimport {\n BuiltInSortingFn,\n reSplitAlphaNumeric,\n sortingFns,\n} from '../sortingFns'\n\nimport {\n Column,\n OnChangeFn,\n Table,\n Row,\n Updater,\n RowData,\n SortingFns,\n TableFeature,\n} from '../types'\n\nimport { isFunction, makeStateUpdater } from '../utils'\n\nexport type SortDirection = 'asc' | 'desc'\n\nexport interface ColumnSort {\n desc: boolean\n id: string\n}\n\nexport type SortingState = ColumnSort[]\n\nexport interface SortingTableState {\n sorting: SortingState\n}\n\nexport interface SortingFn {\n (rowA: Row, rowB: Row, columnId: string): number\n}\n\nexport type CustomSortingFns = Record<\n string,\n SortingFn\n>\n\nexport type SortingFnOption =\n | 'auto'\n | keyof SortingFns\n | BuiltInSortingFn\n | SortingFn\n\nexport interface SortingColumnDef {\n /**\n * Enables/Disables multi-sorting for this column.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/sorting#enablemultisort)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/sorting)\n */\n enableMultiSort?: boolean\n /**\n * Enables/Disables sorting for this column.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/sorting#enablesorting)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/sorting)\n */\n enableSorting?: boolean\n /**\n * Inverts the order of the sorting for this column. This is useful for values that have an inverted best/worst scale where lower numbers are better, eg. a ranking (1st, 2nd, 3rd) or golf-like scoring\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/sorting#invertsorting)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/sorting)\n */\n invertSorting?: boolean\n /**\n * Set to `true` for sorting toggles on this column to start in the descending direction.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/sorting#sortdescfirst)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/sorting)\n */\n sortDescFirst?: boolean\n /**\n * The sorting function to use with this column.\n * - A `string` referencing a built-in sorting function\n * - A custom sorting function\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/sorting#sortingfn)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/sorting)\n */\n sortingFn?: SortingFnOption\n /**\n * The priority of undefined values when sorting this column.\n * - `false`\n * - Undefined values will be considered tied and need to be sorted by the next column filter or original index (whichever applies)\n * - `-1`\n * - Undefined values will be sorted with higher priority (ascending) (if ascending, undefined will appear on the beginning of the list)\n * - `1`\n * - Undefined values will be sorted with lower priority (descending) (if ascending, undefined will appear on the end of the list)\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/sorting#sortundefined)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/sorting)\n */\n sortUndefined?: false | -1 | 1 | 'first' | 'last'\n}\n\nexport interface SortingColumn {\n /**\n * Removes this column from the table's sorting state\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/sorting#clearsorting)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/sorting)\n */\n clearSorting: () => void\n /**\n * Returns a sort direction automatically inferred based on the columns values.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/sorting#getautosortdir)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/sorting)\n */\n getAutoSortDir: () => SortDirection\n /**\n * Returns a sorting function automatically inferred based on the columns values.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/sorting#getautosortingfn)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/sorting)\n */\n getAutoSortingFn: () => SortingFn\n /**\n * Returns whether this column can be multi-sorted.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/sorting#getcanmultisort)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/sorting)\n */\n getCanMultiSort: () => boolean\n /**\n * Returns whether this column can be sorted.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/sorting#getcansort)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/sorting)\n */\n getCanSort: () => boolean\n /**\n * Returns the first direction that should be used when sorting this column.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/sorting#getfirstsortdir)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/sorting)\n */\n getFirstSortDir: () => SortDirection\n /**\n * Returns the current sort direction of this column.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/sorting#getissorted)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/sorting)\n */\n getIsSorted: () => false | SortDirection\n /**\n * Returns the next sorting order.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/sorting#getnextsortingorder)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/sorting)\n */\n getNextSortingOrder: () => SortDirection | false\n /**\n * Returns the index position of this column's sorting within the sorting state\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/sorting#getsortindex)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/sorting)\n */\n getSortIndex: () => number\n /**\n * Returns the resolved sorting function to be used for this column\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/sorting#getsortingfn)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/sorting)\n */\n getSortingFn: () => SortingFn\n /**\n * Returns a function that can be used to toggle this column's sorting state. This is useful for attaching a click handler to the column header.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/sorting#gettogglesortinghandler)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/sorting)\n */\n getToggleSortingHandler: () => undefined | ((event: unknown) => void)\n /**\n * Toggles this columns sorting state. If `desc` is provided, it will force the sort direction to that value. If `isMulti` is provided, it will additivity multi-sort the column (or toggle it if it is already sorted).\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/sorting#togglesorting)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/sorting)\n */\n toggleSorting: (desc?: boolean, isMulti?: boolean) => void\n}\n\ninterface SortingOptionsBase {\n /**\n * Enables/disables the ability to remove multi-sorts\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/sorting#enablemultiremove)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/sorting)\n */\n enableMultiRemove?: boolean\n /**\n * Enables/Disables multi-sorting for the table.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/sorting#enablemultisort)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/sorting)\n */\n enableMultiSort?: boolean\n /**\n * Enables/Disables sorting for the table.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/sorting#enablesorting)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/sorting)\n */\n enableSorting?: boolean\n /**\n * Enables/Disables the ability to remove sorting for the table.\n * - If `true` then changing sort order will circle like: 'none' -> 'desc' -> 'asc' -> 'none' -> ...\n * - If `false` then changing sort order will circle like: 'none' -> 'desc' -> 'asc' -> 'desc' -> 'asc' -> ...\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/sorting#enablesortingremoval)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/sorting)\n */\n enableSortingRemoval?: boolean\n /**\n * This function is used to retrieve the sorted row model. If using server-side sorting, this function is not required. To use client-side sorting, pass the exported `getSortedRowModel()` from your adapter to your table or implement your own.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/sorting#getsortedrowmodel)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/sorting)\n */\n getSortedRowModel?: (table: Table) => () => RowModel\n /**\n * Pass a custom function that will be used to determine if a multi-sort event should be triggered. It is passed the event from the sort toggle handler and should return `true` if the event should trigger a multi-sort.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/sorting#ismultisortevent)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/sorting)\n */\n isMultiSortEvent?: (e: unknown) => boolean\n /**\n * Enables manual sorting for the table. If this is `true`, you will be expected to sort your data before it is passed to the table. This is useful if you are doing server-side sorting.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/sorting#manualsorting)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/sorting)\n */\n manualSorting?: boolean\n /**\n * Set a maximum number of columns that can be multi-sorted.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/sorting#maxmultisortcolcount)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/sorting)\n */\n maxMultiSortColCount?: number\n /**\n * If provided, this function will be called with an `updaterFn` when `state.sorting` changes. This overrides the default internal state management, so you will need to persist the state change either fully or partially outside of the table.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/sorting#onsortingchange)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/sorting)\n */\n onSortingChange?: OnChangeFn\n /**\n * If `true`, all sorts will default to descending as their first toggle state.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/sorting#sortdescfirst)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/sorting)\n */\n sortDescFirst?: boolean\n}\n\ntype ResolvedSortingFns = keyof SortingFns extends never\n ? {\n sortingFns?: Record>\n }\n : {\n sortingFns: Record>\n }\n\nexport interface SortingOptions\n extends SortingOptionsBase,\n ResolvedSortingFns {}\n\nexport interface SortingInstance {\n _getSortedRowModel?: () => RowModel\n /**\n * Returns the row model for the table before any sorting has been applied.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/sorting#getpresortedrowmodel)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/sorting)\n */\n getPreSortedRowModel: () => RowModel\n /**\n * Returns the row model for the table after sorting has been applied.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/sorting#getsortedrowmodel)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/sorting)\n */\n getSortedRowModel: () => RowModel\n /**\n * Resets the **sorting** state to `initialState.sorting`, or `true` can be passed to force a default blank state reset to `[]`.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/sorting#resetsorting)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/sorting)\n */\n resetSorting: (defaultState?: boolean) => void\n /**\n * Sets or updates the `state.sorting` state.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/features/sorting#setsorting)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/sorting)\n */\n setSorting: (updater: Updater) => void\n}\n\n//\n\nexport const RowSorting: TableFeature = {\n getInitialState: (state): SortingTableState => {\n return {\n sorting: [],\n ...state,\n }\n },\n\n getDefaultColumnDef: (): SortingColumnDef => {\n return {\n sortingFn: 'auto',\n sortUndefined: 1,\n }\n },\n\n getDefaultOptions: (\n table: Table\n ): SortingOptions => {\n return {\n onSortingChange: makeStateUpdater('sorting', table),\n isMultiSortEvent: (e: unknown) => {\n return (e as MouseEvent).shiftKey\n },\n }\n },\n\n createColumn: (\n column: Column,\n table: Table\n ): void => {\n column.getAutoSortingFn = () => {\n const firstRows = table.getFilteredRowModel().flatRows.slice(10)\n\n let isString = false\n\n for (const row of firstRows) {\n const value = row?.getValue(column.id)\n\n if (Object.prototype.toString.call(value) === '[object Date]') {\n return sortingFns.datetime\n }\n\n if (typeof value === 'string') {\n isString = true\n\n if (value.split(reSplitAlphaNumeric).length > 1) {\n return sortingFns.alphanumeric\n }\n }\n }\n\n if (isString) {\n return sortingFns.text\n }\n\n return sortingFns.basic\n }\n column.getAutoSortDir = () => {\n const firstRow = table.getFilteredRowModel().flatRows[0]\n\n const value = firstRow?.getValue(column.id)\n\n if (typeof value === 'string') {\n return 'asc'\n }\n\n return 'desc'\n }\n column.getSortingFn = () => {\n if (!column) {\n throw new Error()\n }\n\n return isFunction(column.columnDef.sortingFn)\n ? column.columnDef.sortingFn\n : column.columnDef.sortingFn === 'auto'\n ? column.getAutoSortingFn()\n : table.options.sortingFns?.[column.columnDef.sortingFn as string] ??\n sortingFns[column.columnDef.sortingFn as BuiltInSortingFn]\n }\n column.toggleSorting = (desc, multi) => {\n // if (column.columns.length) {\n // column.columns.forEach((c, i) => {\n // if (c.id) {\n // table.toggleColumnSorting(c.id, undefined, multi || !!i)\n // }\n // })\n // return\n // }\n\n // this needs to be outside of table.setSorting to be in sync with rerender\n const nextSortingOrder = column.getNextSortingOrder()\n const hasManualValue = typeof desc !== 'undefined' && desc !== null\n\n table.setSorting(old => {\n // Find any existing sorting for this column\n const existingSorting = old?.find(d => d.id === column.id)\n const existingIndex = old?.findIndex(d => d.id === column.id)\n\n let newSorting: SortingState = []\n\n // What should we do with this sort action?\n let sortAction: 'add' | 'remove' | 'toggle' | 'replace'\n let nextDesc = hasManualValue ? desc : nextSortingOrder === 'desc'\n\n // Multi-mode\n if (old?.length && column.getCanMultiSort() && multi) {\n if (existingSorting) {\n sortAction = 'toggle'\n } else {\n sortAction = 'add'\n }\n } else {\n // Normal mode\n if (old?.length && existingIndex !== old.length - 1) {\n sortAction = 'replace'\n } else if (existingSorting) {\n sortAction = 'toggle'\n } else {\n sortAction = 'replace'\n }\n }\n\n // Handle toggle states that will remove the sorting\n if (sortAction === 'toggle') {\n // If we are \"actually\" toggling (not a manual set value), should we remove the sorting?\n if (!hasManualValue) {\n // Is our intention to remove?\n if (!nextSortingOrder) {\n sortAction = 'remove'\n }\n }\n }\n\n if (sortAction === 'add') {\n newSorting = [\n ...old,\n {\n id: column.id,\n desc: nextDesc,\n },\n ]\n // Take latest n columns\n newSorting.splice(\n 0,\n newSorting.length -\n (table.options.maxMultiSortColCount ?? Number.MAX_SAFE_INTEGER)\n )\n } else if (sortAction === 'toggle') {\n // This flips (or sets) the\n newSorting = old.map(d => {\n if (d.id === column.id) {\n return {\n ...d,\n desc: nextDesc,\n }\n }\n return d\n })\n } else if (sortAction === 'remove') {\n newSorting = old.filter(d => d.id !== column.id)\n } else {\n newSorting = [\n {\n id: column.id,\n desc: nextDesc,\n },\n ]\n }\n\n return newSorting\n })\n }\n\n column.getFirstSortDir = () => {\n const sortDescFirst =\n column.columnDef.sortDescFirst ??\n table.options.sortDescFirst ??\n column.getAutoSortDir() === 'desc'\n return sortDescFirst ? 'desc' : 'asc'\n }\n\n column.getNextSortingOrder = (multi?: boolean) => {\n const firstSortDirection = column.getFirstSortDir()\n const isSorted = column.getIsSorted()\n\n if (!isSorted) {\n return firstSortDirection\n }\n\n if (\n isSorted !== firstSortDirection &&\n (table.options.enableSortingRemoval ?? true) && // If enableSortRemove, enable in general\n (multi ? table.options.enableMultiRemove ?? true : true) // If multi, don't allow if enableMultiRemove))\n ) {\n return false\n }\n return isSorted === 'desc' ? 'asc' : 'desc'\n }\n\n column.getCanSort = () => {\n return (\n (column.columnDef.enableSorting ?? true) &&\n (table.options.enableSorting ?? true) &&\n !!column.accessorFn\n )\n }\n\n column.getCanMultiSort = () => {\n return (\n column.columnDef.enableMultiSort ??\n table.options.enableMultiSort ??\n !!column.accessorFn\n )\n }\n\n column.getIsSorted = () => {\n const columnSort = table.getState().sorting?.find(d => d.id === column.id)\n\n return !columnSort ? false : columnSort.desc ? 'desc' : 'asc'\n }\n\n column.getSortIndex = () =>\n table.getState().sorting?.findIndex(d => d.id === column.id) ?? -1\n\n column.clearSorting = () => {\n //clear sorting for just 1 column\n table.setSorting(old =>\n old?.length ? old.filter(d => d.id !== column.id) : []\n )\n }\n\n column.getToggleSortingHandler = () => {\n const canSort = column.getCanSort()\n\n return (e: unknown) => {\n if (!canSort) return\n ;(e as any).persist?.()\n column.toggleSorting?.(\n undefined,\n column.getCanMultiSort() ? table.options.isMultiSortEvent?.(e) : false\n )\n }\n }\n },\n\n createTable: (table: Table): void => {\n table.setSorting = updater => table.options.onSortingChange?.(updater)\n table.resetSorting = defaultState => {\n table.setSorting(defaultState ? [] : table.initialState?.sorting ?? [])\n }\n table.getPreSortedRowModel = () => table.getGroupedRowModel()\n table.getSortedRowModel = () => {\n if (!table._getSortedRowModel && table.options.getSortedRowModel) {\n table._getSortedRowModel = table.options.getSortedRowModel(table)\n }\n\n if (table.options.manualSorting || !table._getSortedRowModel) {\n return table.getPreSortedRowModel()\n }\n\n return table._getSortedRowModel()\n }\n },\n}\n", "import { functionalUpdate, getMemoOptions, memo, RequiredKeys } from '../utils'\n\nimport {\n Updater,\n TableOptionsResolved,\n TableState,\n Table,\n InitialTableState,\n Row,\n Column,\n RowModel,\n ColumnDef,\n TableOptions,\n RowData,\n TableMeta,\n ColumnDefResolved,\n GroupColumnDef,\n TableFeature,\n} from '../types'\n\n//\nimport { createColumn } from './column'\nimport { Headers } from './headers'\n//\n\nimport { ColumnFaceting } from '../features/ColumnFaceting'\nimport { ColumnFiltering } from '../features/ColumnFiltering'\nimport { ColumnGrouping } from '../features/ColumnGrouping'\nimport { ColumnOrdering } from '../features/ColumnOrdering'\nimport { ColumnPinning } from '../features/ColumnPinning'\nimport { ColumnSizing } from '../features/ColumnSizing'\nimport { ColumnVisibility } from '../features/ColumnVisibility'\nimport { GlobalFaceting } from '../features/GlobalFaceting'\nimport { GlobalFiltering } from '../features/GlobalFiltering'\nimport { RowExpanding } from '../features/RowExpanding'\nimport { RowPagination } from '../features/RowPagination'\nimport { RowPinning } from '../features/RowPinning'\nimport { RowSelection } from '../features/RowSelection'\nimport { RowSorting } from '../features/RowSorting'\n\nconst builtInFeatures = [\n Headers,\n ColumnVisibility,\n ColumnOrdering,\n ColumnPinning,\n ColumnFaceting,\n ColumnFiltering,\n GlobalFaceting, //depends on ColumnFaceting\n GlobalFiltering, //depends on ColumnFiltering\n RowSorting,\n ColumnGrouping, //depends on RowSorting\n RowExpanding,\n RowPagination,\n RowPinning,\n RowSelection,\n ColumnSizing,\n] as const\n\n//\n\nexport interface CoreTableState {}\n\nexport interface CoreOptions {\n /**\n * An array of extra features that you can add to the table instance.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/core/table#_features)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/tables)\n */\n _features?: TableFeature[]\n /**\n * Set this option to override any of the `autoReset...` feature options.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/core/table#autoresetall)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/tables)\n */\n autoResetAll?: boolean\n /**\n * The array of column defs to use for the table.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/core/table#columns)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/tables)\n */\n columns: ColumnDef[]\n /**\n * The data for the table to display. This array should match the type you provided to `table.setRowType<...>`. Columns can access this data via string/index or a functional accessor. When the `data` option changes reference, the table will reprocess the data.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/core/table#data)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/tables)\n */\n data: TData[]\n /**\n * Set this option to `true` to output all debugging information to the console.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/core/table#debugall)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/tables)\n */\n debugAll?: boolean\n /**\n * Set this option to `true` to output cell debugging information to the console.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/core/table#debugcells]\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/tables)\n */\n debugCells?: boolean\n /**\n * Set this option to `true` to output column debugging information to the console.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/core/table#debugcolumns)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/tables)\n */\n debugColumns?: boolean\n /**\n * Set this option to `true` to output header debugging information to the console.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/core/table#debugheaders)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/tables)\n */\n debugHeaders?: boolean\n /**\n * Set this option to `true` to output row debugging information to the console.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/core/table#debugrows)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/tables)\n */\n debugRows?: boolean\n /**\n * Set this option to `true` to output table debugging information to the console.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/core/table#debugtable)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/tables)\n */\n debugTable?: boolean\n /**\n * Default column options to use for all column defs supplied to the table.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/core/table#defaultcolumn)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/tables)\n */\n defaultColumn?: Partial>\n /**\n * This required option is a factory for a function that computes and returns the core row model for the table.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/core/table#getcorerowmodel)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/tables)\n */\n getCoreRowModel: (table: Table) => () => RowModel\n /**\n * This optional function is used to derive a unique ID for any given row. If not provided the rows index is used (nested rows join together with `.` using their grandparents' index eg. `index.index.index`). If you need to identify individual rows that are originating from any server-side operations, it's suggested you use this function to return an ID that makes sense regardless of network IO/ambiguity eg. a userId, taskId, database ID field, etc.\n * @example getRowId: row => row.userId\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/core/table#getrowid)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/tables)\n */\n getRowId?: (originalRow: TData, index: number, parent?: Row) => string\n /**\n * This optional function is used to access the sub rows for any given row. If you are using nested rows, you will need to use this function to return the sub rows object (or undefined) from the row.\n * @example getSubRows: row => row.subRows\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/core/table#getsubrows)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/tables)\n */\n getSubRows?: (originalRow: TData, index: number) => undefined | TData[]\n /**\n * Use this option to optionally pass initial state to the table. This state will be used when resetting various table states either automatically by the table (eg. `options.autoResetPageIndex`) or via functions like `table.resetRowSelection()`. Most reset function allow you optionally pass a flag to reset to a blank/default state instead of the initial state.\n *\n * Table state will not be reset when this object changes, which also means that the initial state object does not need to be stable.\n *\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/core/table#initialstate)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/tables)\n */\n initialState?: InitialTableState\n /**\n * This option is used to optionally implement the merging of table options.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/core/table#mergeoptions)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/tables)\n */\n mergeOptions?: (\n defaultOptions: TableOptions,\n options: Partial>\n ) => TableOptions\n /**\n * You can pass any object to `options.meta` and access it anywhere the `table` is available via `table.options.meta`.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/core/table#meta)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/tables)\n */\n meta?: TableMeta\n /**\n * The `onStateChange` option can be used to optionally listen to state changes within the table.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/core/table#onstatechange)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/tables)\n */\n onStateChange: (updater: Updater) => void\n /**\n * Value used when the desired value is not found in the data.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/core/table#renderfallbackvalue)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/tables)\n */\n renderFallbackValue: any\n /**\n * The `state` option can be used to optionally _control_ part or all of the table state. The state you pass here will merge with and overwrite the internal automatically-managed state to produce the final state for the table. You can also listen to state changes via the `onStateChange` option.\n * > Note: Any state passed in here will override both the internal state and any other `initialState` you provide.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/core/table#state)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/tables)\n */\n state: Partial\n}\n\nexport interface CoreInstance {\n _features: readonly TableFeature[]\n _getAllFlatColumnsById: () => Record>\n _getColumnDefs: () => ColumnDef[]\n _getCoreRowModel?: () => RowModel\n _getDefaultColumnDef: () => Partial>\n _getRowId: (_: TData, index: number, parent?: Row) => string\n _queue: (cb: () => void) => void\n /**\n * Returns all columns in the table in their normalized and nested hierarchy.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/core/table#getallcolumns)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/tables)\n */\n getAllColumns: () => Column[]\n /**\n * Returns all columns in the table flattened to a single level.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/core/table#getallflatcolumns)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/tables)\n */\n getAllFlatColumns: () => Column[]\n /**\n * Returns all leaf-node columns in the table flattened to a single level. This does not include parent columns.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/core/table#getallleafcolumns)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/tables)\n */\n getAllLeafColumns: () => Column[]\n /**\n * Returns a single column by its ID.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/core/table#getcolumn)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/tables)\n */\n getColumn: (columnId: string) => Column | undefined\n /**\n * Returns the core row model before any processing has been applied.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/core/table#getcorerowmodel)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/tables)\n */\n getCoreRowModel: () => RowModel\n /**\n * Returns the row with the given ID.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/core/table#getrow)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/tables)\n */\n getRow: (id: string, searchAll?: boolean) => Row\n /**\n * Returns the final model after all processing from other used features has been applied. This is the row model that is most commonly used for rendering.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/core/table#getrowmodel)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/tables)\n */\n getRowModel: () => RowModel\n /**\n * Call this function to get the table's current state. It's recommended to use this function and its state, especially when managing the table state manually. It is the exact same state used internally by the table for every feature and function it provides.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/core/table#getstate)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/tables)\n */\n getState: () => TableState\n /**\n * This is the resolved initial state of the table.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/core/table#initialstate)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/tables)\n */\n initialState: TableState\n /**\n * A read-only reference to the table's current options.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/core/table#options)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/tables)\n */\n options: RequiredKeys, 'state'>\n /**\n * Call this function to reset the table state to the initial state.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/core/table#reset)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/tables)\n */\n reset: () => void\n /**\n * This function can be used to update the table options.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/core/table#setoptions)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/tables)\n */\n setOptions: (newOptions: Updater>) => void\n /**\n * Call this function to update the table state.\n * @link [API Docs](https://tanstack.com/table/v8/docs/api/core/table#setstate)\n * @link [Guide](https://tanstack.com/table/v8/docs/guide/tables)\n */\n setState: (updater: Updater) => void\n}\n\nexport function createTable(\n options: TableOptionsResolved\n): Table {\n if (\n process.env.NODE_ENV !== 'production' &&\n (options.debugAll || options.debugTable)\n ) {\n console.info('Creating Table Instance...')\n }\n\n const _features = [...builtInFeatures, ...(options._features ?? [])]\n\n let table = { _features } as unknown as Table\n\n const defaultOptions = table._features.reduce((obj, feature) => {\n return Object.assign(obj, feature.getDefaultOptions?.(table))\n }, {}) as TableOptionsResolved\n\n const mergeOptions = (options: TableOptionsResolved) => {\n if (table.options.mergeOptions) {\n return table.options.mergeOptions(defaultOptions, options)\n }\n\n return {\n ...defaultOptions,\n ...options,\n }\n }\n\n const coreInitialState: CoreTableState = {}\n\n let initialState = {\n ...coreInitialState,\n ...(options.initialState ?? {}),\n } as TableState\n\n table._features.forEach(feature => {\n initialState = (feature.getInitialState?.(initialState) ??\n initialState) as TableState\n })\n\n const queued: (() => void)[] = []\n let queuedTimeout = false\n\n const coreInstance: CoreInstance = {\n _features,\n options: {\n ...defaultOptions,\n ...options,\n },\n initialState,\n _queue: cb => {\n queued.push(cb)\n\n if (!queuedTimeout) {\n queuedTimeout = true\n\n // Schedule a microtask to run the queued callbacks after\n // the current call stack (render, etc) has finished.\n Promise.resolve()\n .then(() => {\n while (queued.length) {\n queued.shift()!()\n }\n queuedTimeout = false\n })\n .catch(error =>\n setTimeout(() => {\n throw error\n })\n )\n }\n },\n reset: () => {\n table.setState(table.initialState)\n },\n setOptions: updater => {\n const newOptions = functionalUpdate(updater, table.options)\n table.options = mergeOptions(newOptions) as RequiredKeys<\n TableOptionsResolved,\n 'state'\n >\n },\n\n getState: () => {\n return table.options.state as TableState\n },\n\n setState: (updater: Updater) => {\n table.options.onStateChange?.(updater)\n },\n\n _getRowId: (row: TData, index: number, parent?: Row) =>\n table.options.getRowId?.(row, index, parent) ??\n `${parent ? [parent.id, index].join('.') : index}`,\n\n getCoreRowModel: () => {\n if (!table._getCoreRowModel) {\n table._getCoreRowModel = table.options.getCoreRowModel(table)\n }\n\n return table._getCoreRowModel!()\n },\n\n // The final calls start at the bottom of the model,\n // expanded rows, which then work their way up\n\n getRowModel: () => {\n return table.getPaginationRowModel()\n },\n //in next version, we should just pass in the row model as the optional 2nd arg\n getRow: (id: string, searchAll?: boolean) => {\n let row = (\n searchAll ? table.getPrePaginationRowModel() : table.getRowModel()\n ).rowsById[id]\n\n if (!row) {\n row = table.getCoreRowModel().rowsById[id]\n if (!row) {\n if (process.env.NODE_ENV !== 'production') {\n throw new Error(`getRow could not find row with ID: ${id}`)\n }\n throw new Error()\n }\n }\n\n return row\n },\n _getDefaultColumnDef: memo(\n () => [table.options.defaultColumn],\n defaultColumn => {\n defaultColumn = (defaultColumn ?? {}) as Partial<\n ColumnDef\n >\n\n return {\n header: props => {\n const resolvedColumnDef = props.header.column\n .columnDef as ColumnDefResolved\n\n if (resolvedColumnDef.accessorKey) {\n return resolvedColumnDef.accessorKey\n }\n\n if (resolvedColumnDef.accessorFn) {\n return resolvedColumnDef.id\n }\n\n return null\n },\n // footer: props => props.header.column.id,\n cell: props => props.renderValue()?.toString?.() ?? null,\n ...table._features.reduce((obj, feature) => {\n return Object.assign(obj, feature.getDefaultColumnDef?.())\n }, {}),\n ...defaultColumn,\n } as Partial>\n },\n getMemoOptions(options, 'debugColumns', '_getDefaultColumnDef')\n ),\n\n _getColumnDefs: () => table.options.columns,\n\n getAllColumns: memo(\n () => [table._getColumnDefs()],\n columnDefs => {\n const recurseColumns = (\n columnDefs: ColumnDef[],\n parent?: Column,\n depth = 0\n ): Column[] => {\n return columnDefs.map(columnDef => {\n const column = createColumn(table, columnDef, depth, parent)\n\n const groupingColumnDef = columnDef as GroupColumnDef<\n TData,\n unknown\n >\n\n column.columns = groupingColumnDef.columns\n ? recurseColumns(groupingColumnDef.columns, column, depth + 1)\n : []\n\n return column\n })\n }\n\n return recurseColumns(columnDefs)\n },\n getMemoOptions(options, 'debugColumns', 'getAllColumns')\n ),\n\n getAllFlatColumns: memo(\n () => [table.getAllColumns()],\n allColumns => {\n return allColumns.flatMap(column => {\n return column.getFlatColumns()\n })\n },\n getMemoOptions(options, 'debugColumns', 'getAllFlatColumns')\n ),\n\n _getAllFlatColumnsById: memo(\n () => [table.getAllFlatColumns()],\n flatColumns => {\n return flatColumns.reduce(\n (acc, column) => {\n acc[column.id] = column\n return acc\n },\n {} as Record>\n )\n },\n getMemoOptions(options, 'debugColumns', 'getAllFlatColumnsById')\n ),\n\n getAllLeafColumns: memo(\n () => [table.getAllColumns(), table._getOrderColumnsFn()],\n (allColumns, orderColumns) => {\n let leafColumns = allColumns.flatMap(column => column.getLeafColumns())\n return orderColumns(leafColumns)\n },\n getMemoOptions(options, 'debugColumns', 'getAllLeafColumns')\n ),\n\n getColumn: columnId => {\n const column = table._getAllFlatColumnsById()[columnId]\n\n if (process.env.NODE_ENV !== 'production' && !column) {\n console.error(`[Table] Column with id '${columnId}' does not exist.`)\n }\n\n return column\n },\n }\n\n Object.assign(table, coreInstance)\n\n for (let index = 0; index < table._features.length; index++) {\n const feature = table._features[index]\n feature?.createTable?.(table)\n }\n\n return table\n}\n", "import { createRow } from '../core/row'\nimport { Table, Row, RowModel, RowData } from '../types'\nimport { getMemoOptions, memo } from '../utils'\n\nexport function getCoreRowModel(): (\n table: Table\n) => () => RowModel {\n return table =>\n memo(\n () => [table.options.data],\n (\n data\n ): {\n rows: Row[]\n flatRows: Row[]\n rowsById: Record>\n } => {\n const rowModel: RowModel = {\n rows: [],\n flatRows: [],\n rowsById: {},\n }\n\n const accessRows = (\n originalRows: TData[],\n depth = 0,\n parentRow?: Row\n ): Row[] => {\n const rows = [] as Row[]\n\n for (let i = 0; i < originalRows.length; i++) {\n // This could be an expensive check at scale, so we should move it somewhere else, but where?\n // if (!id) {\n // if (process.env.NODE_ENV !== 'production') {\n // throw new Error(`getRowId expected an ID, but got ${id}`)\n // }\n // }\n\n // Make the row\n const row = createRow(\n table,\n table._getRowId(originalRows[i]!, i, parentRow),\n originalRows[i]!,\n i,\n depth,\n undefined,\n parentRow?.id\n )\n\n // Keep track of every row in a flat array\n rowModel.flatRows.push(row)\n // Also keep track of every row by its ID\n rowModel.rowsById[row.id] = row\n // Push table row into parent\n rows.push(row)\n\n // Get the original subrows\n if (table.options.getSubRows) {\n row.originalSubRows = table.options.getSubRows(\n originalRows[i]!,\n i\n )\n\n // Then recursively access them\n if (row.originalSubRows?.length) {\n row.subRows = accessRows(row.originalSubRows, depth + 1, row)\n }\n }\n }\n\n return rows\n }\n\n rowModel.rows = accessRows(data)\n\n return rowModel\n },\n getMemoOptions(table.options, 'debugTable', 'getRowModel', () =>\n table._autoResetPageIndex()\n )\n )\n}\n", "import { Table, Row, RowModel, RowData } from '../types'\nimport { getMemoOptions, memo } from '../utils'\n\nexport function getExpandedRowModel(): (\n table: Table\n) => () => RowModel {\n return table =>\n memo(\n () => [\n table.getState().expanded,\n table.getPreExpandedRowModel(),\n table.options.paginateExpandedRows,\n ],\n (expanded, rowModel, paginateExpandedRows) => {\n if (\n !rowModel.rows.length ||\n (expanded !== true && !Object.keys(expanded ?? {}).length)\n ) {\n return rowModel\n }\n\n if (!paginateExpandedRows) {\n // Only expand rows at this point if they are being paginated\n return rowModel\n }\n\n return expandRows(rowModel)\n },\n getMemoOptions(table.options, 'debugTable', 'getExpandedRowModel')\n )\n}\n\nexport function expandRows(rowModel: RowModel) {\n const expandedRows: Row[] = []\n\n const handleRow = (row: Row) => {\n expandedRows.push(row)\n\n if (row.subRows?.length && row.getIsExpanded()) {\n row.subRows.forEach(handleRow)\n }\n }\n\n rowModel.rows.forEach(handleRow)\n\n return {\n rows: expandedRows,\n flatRows: rowModel.flatRows,\n rowsById: rowModel.rowsById,\n }\n}\n", "import { Table, RowData } from '../types'\nimport { getMemoOptions, memo } from '../utils'\n\nexport function getFacetedMinMaxValues(): (\n table: Table,\n columnId: string\n) => () => undefined | [number, number] {\n return (table, columnId) =>\n memo(\n () => [table.getColumn(columnId)?.getFacetedRowModel()],\n facetedRowModel => {\n if (!facetedRowModel) return undefined\n\n const firstValue =\n facetedRowModel.flatRows[0]?.getUniqueValues(columnId)\n\n if (typeof firstValue === 'undefined') {\n return undefined\n }\n\n let facetedMinMaxValues: [any, any] = [firstValue, firstValue]\n\n for (let i = 0; i < facetedRowModel.flatRows.length; i++) {\n const values =\n facetedRowModel.flatRows[i]!.getUniqueValues(columnId)\n\n for (let j = 0; j < values.length; j++) {\n const value = values[j]!\n\n if (value < facetedMinMaxValues[0]) {\n facetedMinMaxValues[0] = value\n } else if (value > facetedMinMaxValues[1]) {\n facetedMinMaxValues[1] = value\n }\n }\n }\n\n return facetedMinMaxValues\n },\n getMemoOptions(table.options, 'debugTable', 'getFacetedMinMaxValues')\n )\n}\n", "import { createRow } from '../core/row'\nimport { Row, RowModel, Table, RowData } from '../types'\n\nexport function filterRows(\n rows: Row[],\n filterRowImpl: (row: Row) => any,\n table: Table\n) {\n if (table.options.filterFromLeafRows) {\n return filterRowModelFromLeafs(rows, filterRowImpl, table)\n }\n\n return filterRowModelFromRoot(rows, filterRowImpl, table)\n}\n\nfunction filterRowModelFromLeafs(\n rowsToFilter: Row[],\n filterRow: (row: Row) => Row[],\n table: Table\n): RowModel {\n const newFilteredFlatRows: Row[] = []\n const newFilteredRowsById: Record> = {}\n const maxDepth = table.options.maxLeafRowFilterDepth ?? 100\n\n const recurseFilterRows = (rowsToFilter: Row[], depth = 0) => {\n const rows: Row[] = []\n\n // Filter from children up first\n for (let i = 0; i < rowsToFilter.length; i++) {\n let row = rowsToFilter[i]!\n\n const newRow = createRow(\n table,\n row.id,\n row.original,\n row.index,\n row.depth,\n undefined,\n row.parentId\n )\n newRow.columnFilters = row.columnFilters\n\n if (row.subRows?.length && depth < maxDepth) {\n newRow.subRows = recurseFilterRows(row.subRows, depth + 1)\n row = newRow\n\n if (filterRow(row) && !newRow.subRows.length) {\n rows.push(row)\n newFilteredRowsById[row.id] = row\n newFilteredFlatRows.push(row)\n continue\n }\n\n if (filterRow(row) || newRow.subRows.length) {\n rows.push(row)\n newFilteredRowsById[row.id] = row\n newFilteredFlatRows.push(row)\n continue\n }\n } else {\n row = newRow\n if (filterRow(row)) {\n rows.push(row)\n newFilteredRowsById[row.id] = row\n newFilteredFlatRows.push(row)\n }\n }\n }\n\n return rows\n }\n\n return {\n rows: recurseFilterRows(rowsToFilter),\n flatRows: newFilteredFlatRows,\n rowsById: newFilteredRowsById,\n }\n}\n\nfunction filterRowModelFromRoot(\n rowsToFilter: Row[],\n filterRow: (row: Row) => any,\n table: Table\n): RowModel {\n const newFilteredFlatRows: Row[] = []\n const newFilteredRowsById: Record> = {}\n const maxDepth = table.options.maxLeafRowFilterDepth ?? 100\n\n // Filters top level and nested rows\n const recurseFilterRows = (rowsToFilter: Row[], depth = 0) => {\n // Filter from parents downward first\n\n const rows: Row[] = []\n\n // Apply the filter to any subRows\n for (let i = 0; i < rowsToFilter.length; i++) {\n let row = rowsToFilter[i]!\n\n const pass = filterRow(row)\n\n if (pass) {\n if (row.subRows?.length && depth < maxDepth) {\n const newRow = createRow(\n table,\n row.id,\n row.original,\n row.index,\n row.depth,\n undefined,\n row.parentId\n )\n newRow.subRows = recurseFilterRows(row.subRows, depth + 1)\n row = newRow\n }\n\n rows.push(row)\n newFilteredFlatRows.push(row)\n newFilteredRowsById[row.id] = row\n }\n }\n\n return rows\n }\n\n return {\n rows: recurseFilterRows(rowsToFilter),\n flatRows: newFilteredFlatRows,\n rowsById: newFilteredRowsById,\n }\n}\n", "import { Table, RowModel, Row, RowData } from '../types'\nimport { getMemoOptions, memo } from '../utils'\nimport { filterRows } from './filterRowsUtils'\n\nexport function getFacetedRowModel(): (\n table: Table,\n columnId: string\n) => () => RowModel {\n return (table, columnId) =>\n memo(\n () => [\n table.getPreFilteredRowModel(),\n table.getState().columnFilters,\n table.getState().globalFilter,\n table.getFilteredRowModel(),\n ],\n (preRowModel, columnFilters, globalFilter) => {\n if (\n !preRowModel.rows.length ||\n (!columnFilters?.length && !globalFilter)\n ) {\n return preRowModel\n }\n\n const filterableIds = [\n ...columnFilters.map(d => d.id).filter(d => d !== columnId),\n globalFilter ? '__global__' : undefined,\n ].filter(Boolean) as string[]\n\n const filterRowsImpl = (row: Row) => {\n // Horizontally filter rows through each column\n for (let i = 0; i < filterableIds.length; i++) {\n if (row.columnFilters[filterableIds[i]!] === false) {\n return false\n }\n }\n return true\n }\n\n return filterRows(preRowModel.rows, filterRowsImpl, table)\n },\n getMemoOptions(table.options, 'debugTable', 'getFacetedRowModel')\n )\n}\n", "import { Table, RowData } from '../types'\nimport { getMemoOptions, memo } from '../utils'\n\nexport function getFacetedUniqueValues(): (\n table: Table,\n columnId: string\n) => () => Map {\n return (table, columnId) =>\n memo(\n () => [table.getColumn(columnId)?.getFacetedRowModel()],\n facetedRowModel => {\n if (!facetedRowModel) return new Map()\n\n let facetedUniqueValues = new Map()\n\n for (let i = 0; i < facetedRowModel.flatRows.length; i++) {\n const values =\n facetedRowModel.flatRows[i]!.getUniqueValues(columnId)\n\n for (let j = 0; j < values.length; j++) {\n const value = values[j]!\n\n if (facetedUniqueValues.has(value)) {\n facetedUniqueValues.set(\n value,\n (facetedUniqueValues.get(value) ?? 0) + 1\n )\n } else {\n facetedUniqueValues.set(value, 1)\n }\n }\n }\n\n return facetedUniqueValues\n },\n getMemoOptions(\n table.options,\n 'debugTable',\n `getFacetedUniqueValues_${columnId}`\n )\n )\n}\n", "import { ResolvedColumnFilter } from '../features/ColumnFiltering'\nimport { Table, RowModel, Row, RowData } from '../types'\nimport { getMemoOptions, memo } from '../utils'\nimport { filterRows } from './filterRowsUtils'\n\nexport function getFilteredRowModel(): (\n table: Table\n) => () => RowModel {\n return table =>\n memo(\n () => [\n table.getPreFilteredRowModel(),\n table.getState().columnFilters,\n table.getState().globalFilter,\n ],\n (rowModel, columnFilters, globalFilter) => {\n if (\n !rowModel.rows.length ||\n (!columnFilters?.length && !globalFilter)\n ) {\n for (let i = 0; i < rowModel.flatRows.length; i++) {\n rowModel.flatRows[i]!.columnFilters = {}\n rowModel.flatRows[i]!.columnFiltersMeta = {}\n }\n return rowModel\n }\n\n const resolvedColumnFilters: ResolvedColumnFilter[] = []\n const resolvedGlobalFilters: ResolvedColumnFilter[] = []\n\n ;(columnFilters ?? []).forEach(d => {\n const column = table.getColumn(d.id)\n\n if (!column) {\n return\n }\n\n const filterFn = column.getFilterFn()\n\n if (!filterFn) {\n if (process.env.NODE_ENV !== 'production') {\n console.warn(\n `Could not find a valid 'column.filterFn' for column with the ID: ${column.id}.`\n )\n }\n return\n }\n\n resolvedColumnFilters.push({\n id: d.id,\n filterFn,\n resolvedValue: filterFn.resolveFilterValue?.(d.value) ?? d.value,\n })\n })\n\n const filterableIds = (columnFilters ?? []).map(d => d.id)\n\n const globalFilterFn = table.getGlobalFilterFn()\n\n const globallyFilterableColumns = table\n .getAllLeafColumns()\n .filter(column => column.getCanGlobalFilter())\n\n if (\n globalFilter &&\n globalFilterFn &&\n globallyFilterableColumns.length\n ) {\n filterableIds.push('__global__')\n\n globallyFilterableColumns.forEach(column => {\n resolvedGlobalFilters.push({\n id: column.id,\n filterFn: globalFilterFn,\n resolvedValue:\n globalFilterFn.resolveFilterValue?.(globalFilter) ??\n globalFilter,\n })\n })\n }\n\n let currentColumnFilter\n let currentGlobalFilter\n\n // Flag the prefiltered row model with each filter state\n for (let j = 0; j < rowModel.flatRows.length; j++) {\n const row = rowModel.flatRows[j]!\n\n row.columnFilters = {}\n\n if (resolvedColumnFilters.length) {\n for (let i = 0; i < resolvedColumnFilters.length; i++) {\n currentColumnFilter = resolvedColumnFilters[i]!\n const id = currentColumnFilter.id\n\n // Tag the row with the column filter state\n row.columnFilters[id] = currentColumnFilter.filterFn(\n row,\n id,\n currentColumnFilter.resolvedValue,\n filterMeta => {\n row.columnFiltersMeta[id] = filterMeta\n }\n )\n }\n }\n\n if (resolvedGlobalFilters.length) {\n for (let i = 0; i < resolvedGlobalFilters.length; i++) {\n currentGlobalFilter = resolvedGlobalFilters[i]!\n const id = currentGlobalFilter.id\n // Tag the row with the first truthy global filter state\n if (\n currentGlobalFilter.filterFn(\n row,\n id,\n currentGlobalFilter.resolvedValue,\n filterMeta => {\n row.columnFiltersMeta[id] = filterMeta\n }\n )\n ) {\n row.columnFilters.__global__ = true\n break\n }\n }\n\n if (row.columnFilters.__global__ !== true) {\n row.columnFilters.__global__ = false\n }\n }\n }\n\n const filterRowsImpl = (row: Row) => {\n // Horizontally filter rows through each column\n for (let i = 0; i < filterableIds.length; i++) {\n if (row.columnFilters[filterableIds[i]!] === false) {\n return false\n }\n }\n return true\n }\n\n // Filter final rows using all of the active filters\n return filterRows(rowModel.rows, filterRowsImpl, table)\n },\n getMemoOptions(table.options, 'debugTable', 'getFilteredRowModel', () =>\n table._autoResetPageIndex()\n )\n )\n}\n", "import { createRow } from '../core/row'\nimport { Table, Row, RowModel, RowData } from '../types'\nimport { flattenBy, getMemoOptions, memo } from '../utils'\n\nexport function getGroupedRowModel(): (\n table: Table\n) => () => RowModel {\n return table =>\n memo(\n () => [table.getState().grouping, table.getPreGroupedRowModel()],\n (grouping, rowModel) => {\n if (!rowModel.rows.length || !grouping.length) {\n return rowModel\n }\n\n // Filter the grouping list down to columns that exist\n const existingGrouping = grouping.filter(columnId =>\n table.getColumn(columnId)\n )\n\n const groupedFlatRows: Row[] = []\n const groupedRowsById: Record> = {}\n // const onlyGroupedFlatRows: Row[] = [];\n // const onlyGroupedRowsById: Record = {};\n // const nonGroupedFlatRows: Row[] = [];\n // const nonGroupedRowsById: Record = {};\n\n // Recursively group the data\n const groupUpRecursively = (\n rows: Row[],\n depth = 0,\n parentId?: string\n ) => {\n // Grouping depth has been been met\n // Stop grouping and simply rewrite thd depth and row relationships\n if (depth >= existingGrouping.length) {\n return rows.map(row => {\n row.depth = depth\n\n groupedFlatRows.push(row)\n groupedRowsById[row.id] = row\n\n if (row.subRows) {\n row.subRows = groupUpRecursively(row.subRows, depth + 1, row.id)\n }\n\n return row\n })\n }\n\n const columnId: string = existingGrouping[depth]!\n\n // Group the rows together for this level\n const rowGroupsMap = groupBy(rows, columnId)\n\n // Peform aggregations for each group\n const aggregatedGroupedRows = Array.from(rowGroupsMap.entries()).map(\n ([groupingValue, groupedRows], index) => {\n let id = `${columnId}:${groupingValue}`\n id = parentId ? `${parentId}>${id}` : id\n\n // First, Recurse to group sub rows before aggregation\n const subRows = groupUpRecursively(groupedRows, depth + 1, id)\n\n // Flatten the leaf rows of the rows in this group\n const leafRows = depth\n ? flattenBy(groupedRows, row => row.subRows)\n : groupedRows\n\n const row = createRow(\n table,\n id,\n leafRows[0]!.original,\n index,\n depth,\n undefined,\n parentId\n )\n\n Object.assign(row, {\n groupingColumnId: columnId,\n groupingValue,\n subRows,\n leafRows,\n getValue: (columnId: string) => {\n // Don't aggregate columns that are in the grouping\n if (existingGrouping.includes(columnId)) {\n if (row._valuesCache.hasOwnProperty(columnId)) {\n return row._valuesCache[columnId]\n }\n\n if (groupedRows[0]) {\n row._valuesCache[columnId] =\n groupedRows[0].getValue(columnId) ?? undefined\n }\n\n return row._valuesCache[columnId]\n }\n\n if (row._groupingValuesCache.hasOwnProperty(columnId)) {\n return row._groupingValuesCache[columnId]\n }\n\n // Aggregate the values\n const column = table.getColumn(columnId)\n const aggregateFn = column?.getAggregationFn()\n\n if (aggregateFn) {\n row._groupingValuesCache[columnId] = aggregateFn(\n columnId,\n leafRows,\n groupedRows\n )\n\n return row._groupingValuesCache[columnId]\n }\n },\n })\n\n subRows.forEach(subRow => {\n groupedFlatRows.push(subRow)\n groupedRowsById[subRow.id] = subRow\n // if (subRow.getIsGrouped?.()) {\n // onlyGroupedFlatRows.push(subRow);\n // onlyGroupedRowsById[subRow.id] = subRow;\n // } else {\n // nonGroupedFlatRows.push(subRow);\n // nonGroupedRowsById[subRow.id] = subRow;\n // }\n })\n\n return row\n }\n )\n\n return aggregatedGroupedRows\n }\n\n const groupedRows = groupUpRecursively(rowModel.rows, 0)\n\n groupedRows.forEach(subRow => {\n groupedFlatRows.push(subRow)\n groupedRowsById[subRow.id] = subRow\n // if (subRow.getIsGrouped?.()) {\n // onlyGroupedFlatRows.push(subRow);\n // onlyGroupedRowsById[subRow.id] = subRow;\n // } else {\n // nonGroupedFlatRows.push(subRow);\n // nonGroupedRowsById[subRow.id] = subRow;\n // }\n })\n\n return {\n rows: groupedRows,\n flatRows: groupedFlatRows,\n rowsById: groupedRowsById,\n }\n },\n getMemoOptions(table.options, 'debugTable', 'getGroupedRowModel', () => {\n table._queue(() => {\n table._autoResetExpanded()\n table._autoResetPageIndex()\n })\n })\n )\n}\n\nfunction groupBy(rows: Row[], columnId: string) {\n const groupMap = new Map[]>()\n\n return rows.reduce((map, row) => {\n const resKey = `${row.getGroupingValue(columnId)}`\n const previous = map.get(resKey)\n if (!previous) {\n map.set(resKey, [row])\n } else {\n previous.push(row)\n }\n return map\n }, groupMap)\n}\n", "import { Table, RowModel, Row, RowData } from '../types'\nimport { getMemoOptions, memo } from '../utils'\nimport { expandRows } from './getExpandedRowModel'\n\nexport function getPaginationRowModel(opts?: {\n initialSync: boolean\n}): (table: Table) => () => RowModel {\n return table =>\n memo(\n () => [\n table.getState().pagination,\n table.getPrePaginationRowModel(),\n table.options.paginateExpandedRows\n ? undefined\n : table.getState().expanded,\n ],\n (pagination, rowModel) => {\n if (!rowModel.rows.length) {\n return rowModel\n }\n\n const { pageSize, pageIndex } = pagination\n let { rows, flatRows, rowsById } = rowModel\n const pageStart = pageSize * pageIndex\n const pageEnd = pageStart + pageSize\n\n rows = rows.slice(pageStart, pageEnd)\n\n let paginatedRowModel: RowModel\n\n if (!table.options.paginateExpandedRows) {\n paginatedRowModel = expandRows({\n rows,\n flatRows,\n rowsById,\n })\n } else {\n paginatedRowModel = {\n rows,\n flatRows,\n rowsById,\n }\n }\n\n paginatedRowModel.flatRows = []\n\n const handleRow = (row: Row) => {\n paginatedRowModel.flatRows.push(row)\n if (row.subRows.length) {\n row.subRows.forEach(handleRow)\n }\n }\n\n paginatedRowModel.rows.forEach(handleRow)\n\n return paginatedRowModel\n },\n getMemoOptions(table.options, 'debugTable', 'getPaginationRowModel')\n )\n}\n", "import { Table, Row, RowModel, RowData } from '../types'\nimport { SortingFn } from '../features/RowSorting'\nimport { getMemoOptions, memo } from '../utils'\n\nexport function getSortedRowModel(): (\n table: Table\n) => () => RowModel {\n return table =>\n memo(\n () => [table.getState().sorting, table.getPreSortedRowModel()],\n (sorting, rowModel) => {\n if (!rowModel.rows.length || !sorting?.length) {\n return rowModel\n }\n\n const sortingState = table.getState().sorting\n\n const sortedFlatRows: Row[] = []\n\n // Filter out sortings that correspond to non existing columns\n const availableSorting = sortingState.filter(sort =>\n table.getColumn(sort.id)?.getCanSort()\n )\n\n const columnInfoById: Record<\n string,\n {\n sortUndefined?: false | -1 | 1 | 'first' | 'last'\n invertSorting?: boolean\n sortingFn: SortingFn\n }\n > = {}\n\n availableSorting.forEach(sortEntry => {\n const column = table.getColumn(sortEntry.id)\n if (!column) return\n\n columnInfoById[sortEntry.id] = {\n sortUndefined: column.columnDef.sortUndefined,\n invertSorting: column.columnDef.invertSorting,\n sortingFn: column.getSortingFn(),\n }\n })\n\n const sortData = (rows: Row[]) => {\n // This will also perform a stable sorting using the row index\n // if needed.\n const sortedData = rows.map(row => ({ ...row }))\n\n sortedData.sort((rowA, rowB) => {\n for (let i = 0; i < availableSorting.length; i += 1) {\n const sortEntry = availableSorting[i]!\n const columnInfo = columnInfoById[sortEntry.id]!\n const sortUndefined = columnInfo.sortUndefined\n const isDesc = sortEntry?.desc ?? false\n\n let sortInt = 0\n\n // All sorting ints should always return in ascending order\n if (sortUndefined) {\n const aValue = rowA.getValue(sortEntry.id)\n const bValue = rowB.getValue(sortEntry.id)\n\n const aUndefined = aValue === undefined\n const bUndefined = bValue === undefined\n\n if (aUndefined || bUndefined) {\n if (sortUndefined === 'first') return aUndefined ? -1 : 1\n if (sortUndefined === 'last') return aUndefined ? 1 : -1\n sortInt =\n aUndefined && bUndefined\n ? 0\n : aUndefined\n ? sortUndefined\n : -sortUndefined\n }\n }\n\n if (sortInt === 0) {\n sortInt = columnInfo.sortingFn(rowA, rowB, sortEntry.id)\n }\n\n // If sorting is non-zero, take care of desc and inversion\n if (sortInt !== 0) {\n if (isDesc) {\n sortInt *= -1\n }\n\n if (columnInfo.invertSorting) {\n sortInt *= -1\n }\n\n return sortInt\n }\n }\n\n return rowA.index - rowB.index\n })\n\n // If there are sub-rows, sort them\n sortedData.forEach(row => {\n sortedFlatRows.push(row)\n if (row.subRows?.length) {\n row.subRows = sortData(row.subRows)\n }\n })\n\n return sortedData\n }\n\n return {\n rows: sortData(rowModel.rows),\n flatRows: sortedFlatRows,\n rowsById: rowModel.rowsById,\n }\n },\n getMemoOptions(table.options, 'debugTable', 'getSortedRowModel', () =>\n table._autoResetPageIndex()\n )\n )\n}\n", "import * as React from 'react'\nexport * from '@tanstack/table-core'\n\nimport {\n TableOptions,\n TableOptionsResolved,\n RowData,\n createTable,\n} from '@tanstack/table-core'\n\nexport type Renderable = React.ReactNode | React.ComponentType\n\n//\n\n/**\n * If rendering headers, cells, or footers with custom markup, use flexRender instead of `cell.getValue()` or `cell.renderValue()`.\n */\nexport function flexRender(\n Comp: Renderable,\n props: TProps\n): React.ReactNode | JSX.Element {\n return !Comp ? null : isReactComponent(Comp) ? (\n \n ) : (\n Comp\n )\n}\n\nfunction isReactComponent(\n component: unknown\n): component is React.ComponentType {\n return (\n isClassComponent(component) ||\n typeof component === 'function' ||\n isExoticComponent(component)\n )\n}\n\nfunction isClassComponent(component: any) {\n return (\n typeof component === 'function' &&\n (() => {\n const proto = Object.getPrototypeOf(component)\n return proto.prototype && proto.prototype.isReactComponent\n })()\n )\n}\n\nfunction isExoticComponent(component: any) {\n return (\n typeof component === 'object' &&\n typeof component.$$typeof === 'symbol' &&\n ['react.memo', 'react.forward_ref'].includes(component.$$typeof.description)\n )\n}\n\nexport function useReactTable(\n options: TableOptions\n) {\n // Compose in the generic options to the user options\n const resolvedOptions: TableOptionsResolved = {\n state: {}, // Dummy state\n onStateChange: () => {}, // noop\n renderFallbackValue: null,\n ...options,\n }\n\n // Create a new table and store it in state\n const [tableRef] = React.useState(() => ({\n current: createTable(resolvedOptions),\n }))\n\n // By default, manage table state here using the table's initial state\n const [state, setState] = React.useState(() => tableRef.current.initialState)\n\n // Compose the default state above with any user state. This will allow the user\n // to only control a subset of the state if desired.\n tableRef.current.setOptions(prev => ({\n ...prev,\n ...options,\n state: {\n ...state,\n ...options.state,\n },\n // Similarly, we'll maintain both our internal state and any user-provided\n // state.\n onStateChange: updater => {\n setState(updater)\n options.onStateChange?.(updater)\n },\n }))\n\n return tableRef.current\n}\n", "export type NoInfer = [A][A extends any ? 0 : never]\n\nexport type PartialKeys = Omit & Partial>\n\nexport function memo, TResult>(\n getDeps: () => [...TDeps],\n fn: (...args: NoInfer<[...TDeps]>) => TResult,\n opts: {\n key: false | string\n debug?: () => any\n onChange?: (result: TResult) => void\n initialDeps?: TDeps\n },\n) {\n let deps = opts.initialDeps ?? []\n let result: TResult | undefined\n\n return (): TResult => {\n let depTime: number\n if (opts.key && opts.debug?.()) depTime = Date.now()\n\n const newDeps = getDeps()\n\n const depsChanged =\n newDeps.length !== deps.length ||\n newDeps.some((dep: any, index: number) => deps[index] !== dep)\n\n if (!depsChanged) {\n return result!\n }\n\n deps = newDeps\n\n let resultTime: number\n if (opts.key && opts.debug?.()) resultTime = Date.now()\n\n result = fn(...newDeps)\n\n if (opts.key && opts.debug?.()) {\n const depEndTime = Math.round((Date.now() - depTime!) * 100) / 100\n const resultEndTime = Math.round((Date.now() - resultTime!) * 100) / 100\n const resultFpsPercentage = resultEndTime / 16\n\n const pad = (str: number | string, num: number) => {\n str = String(str)\n while (str.length < num) {\n str = ' ' + str\n }\n return str\n }\n\n console.info(\n `%c⏱ ${pad(resultEndTime, 5)} /${pad(depEndTime, 5)} ms`,\n `\n font-size: .6rem;\n font-weight: bold;\n color: hsl(${Math.max(\n 0,\n Math.min(120 - 120 * resultFpsPercentage, 120),\n )}deg 100% 31%);`,\n opts?.key,\n )\n }\n\n opts?.onChange?.(result)\n\n return result\n }\n}\n\nexport function notUndefined(value: T | undefined, msg?: string): T {\n if (value === undefined) {\n throw new Error(`Unexpected undefined${msg ? `: ${msg}` : ''}`)\n } else {\n return value\n }\n}\n\nexport const approxEqual = (a: number, b: number) => Math.abs(a - b) < 1\n\nexport const debounce = (\n targetWindow: Window & typeof globalThis,\n fn: Function,\n ms: number,\n) => {\n let timeoutId: number\n return function (this: any, ...args: Array) {\n targetWindow.clearTimeout(timeoutId)\n timeoutId = targetWindow.setTimeout(() => fn.apply(this, args), ms)\n }\n}\n", "import { approxEqual, debounce, memo, notUndefined } from './utils'\n\nexport * from './utils'\n\n//\n\ntype ScrollDirection = 'forward' | 'backward'\n\ntype ScrollAlignment = 'start' | 'center' | 'end' | 'auto'\n\ntype ScrollBehavior = 'auto' | 'smooth'\n\nexport interface ScrollToOptions {\n align?: ScrollAlignment\n behavior?: ScrollBehavior\n}\n\ntype ScrollToOffsetOptions = ScrollToOptions\n\ntype ScrollToIndexOptions = ScrollToOptions\n\nexport interface Range {\n startIndex: number\n endIndex: number\n overscan: number\n count: number\n}\n\ntype Key = number | string\n\nexport interface VirtualItem {\n key: Key\n index: number\n start: number\n end: number\n size: number\n lane: number\n measureElement: (node: TItemElement | null | undefined) => void\n}\n\nexport interface Rect {\n width: number\n height: number\n}\n\n//\n\nexport const defaultKeyExtractor = (index: number) => index\n\nexport const defaultRangeExtractor = (range: Range) => {\n const start = Math.max(range.startIndex - range.overscan, 0)\n const end = Math.min(range.endIndex + range.overscan, range.count - 1)\n\n const arr = []\n\n for (let i = start; i <= end; i++) {\n arr.push(i)\n }\n\n return arr\n}\n\nexport const observeElementRect = (\n instance: Virtualizer,\n cb: (rect: Rect) => void,\n) => {\n const element = instance.scrollElement\n if (!element) {\n return\n }\n const targetWindow = instance.targetWindow\n if (!targetWindow) {\n return\n }\n\n const handler = (rect: Rect) => {\n const { width, height } = rect\n cb({ width: Math.round(width), height: Math.round(height) })\n }\n\n handler(element.getBoundingClientRect())\n\n if (!targetWindow.ResizeObserver) {\n return () => {}\n }\n\n const observer = new targetWindow.ResizeObserver((entries) => {\n const entry = entries[0]\n if (entry?.borderBoxSize) {\n const box = entry.borderBoxSize[0]\n if (box) {\n handler({ width: box.inlineSize, height: box.blockSize })\n return\n }\n }\n handler(element.getBoundingClientRect())\n })\n\n observer.observe(element, { box: 'border-box' })\n\n return () => {\n observer.unobserve(element)\n }\n}\n\nconst addEventListenerOptions = {\n passive: true,\n}\n\nexport const observeWindowRect = (\n instance: Virtualizer,\n cb: (rect: Rect) => void,\n) => {\n const element = instance.scrollElement\n if (!element) {\n return\n }\n\n const handler = () => {\n cb({ width: element.innerWidth, height: element.innerHeight })\n }\n handler()\n\n element.addEventListener('resize', handler, addEventListenerOptions)\n\n return () => {\n element.removeEventListener('resize', handler)\n }\n}\n\nconst supportsScrollend =\n typeof window == 'undefined' ? true : 'onscrollend' in window\n\nexport const observeElementOffset = (\n instance: Virtualizer,\n cb: (offset: number, isScrolling: boolean) => void,\n) => {\n const element = instance.scrollElement\n if (!element) {\n return\n }\n const targetWindow = instance.targetWindow\n if (!targetWindow) {\n return\n }\n\n let offset = 0\n const fallback = supportsScrollend\n ? () => undefined\n : debounce(\n targetWindow,\n () => {\n cb(offset, false)\n },\n instance.options.isScrollingResetDelay,\n )\n\n const createHandler = (isScrolling: boolean) => () => {\n offset = element[instance.options.horizontal ? 'scrollLeft' : 'scrollTop']\n fallback()\n cb(offset, isScrolling)\n }\n const handler = createHandler(true)\n const endHandler = createHandler(false)\n endHandler()\n\n element.addEventListener('scroll', handler, addEventListenerOptions)\n element.addEventListener('scrollend', endHandler, addEventListenerOptions)\n\n return () => {\n element.removeEventListener('scroll', handler)\n element.removeEventListener('scrollend', endHandler)\n }\n}\n\nexport const observeWindowOffset = (\n instance: Virtualizer,\n cb: (offset: number, isScrolling: boolean) => void,\n) => {\n const element = instance.scrollElement\n if (!element) {\n return\n }\n const targetWindow = instance.targetWindow\n if (!targetWindow) {\n return\n }\n\n let offset = 0\n const fallback = supportsScrollend\n ? () => undefined\n : debounce(\n targetWindow,\n () => {\n cb(offset, false)\n },\n instance.options.isScrollingResetDelay,\n )\n\n const createHandler = (isScrolling: boolean) => () => {\n offset = element[instance.options.horizontal ? 'scrollX' : 'scrollY']\n fallback()\n cb(offset, isScrolling)\n }\n const handler = createHandler(true)\n const endHandler = createHandler(false)\n endHandler()\n\n element.addEventListener('scroll', handler, addEventListenerOptions)\n element.addEventListener('scrollend', endHandler, addEventListenerOptions)\n\n return () => {\n element.removeEventListener('scroll', handler)\n element.removeEventListener('scrollend', endHandler)\n }\n}\n\nexport const measureElement = (\n element: TItemElement,\n entry: ResizeObserverEntry | undefined,\n instance: Virtualizer,\n) => {\n if (entry?.borderBoxSize) {\n const box = entry.borderBoxSize[0]\n if (box) {\n const size = Math.round(\n box[instance.options.horizontal ? 'inlineSize' : 'blockSize'],\n )\n return size\n }\n }\n return Math.round(\n element.getBoundingClientRect()[\n instance.options.horizontal ? 'width' : 'height'\n ],\n )\n}\n\nexport const windowScroll = (\n offset: number,\n {\n adjustments = 0,\n behavior,\n }: { adjustments?: number; behavior?: ScrollBehavior },\n instance: Virtualizer,\n) => {\n const toOffset = offset + adjustments\n\n instance.scrollElement?.scrollTo?.({\n [instance.options.horizontal ? 'left' : 'top']: toOffset,\n behavior,\n })\n}\n\nexport const elementScroll = (\n offset: number,\n {\n adjustments = 0,\n behavior,\n }: { adjustments?: number; behavior?: ScrollBehavior },\n instance: Virtualizer,\n) => {\n const toOffset = offset + adjustments\n\n instance.scrollElement?.scrollTo?.({\n [instance.options.horizontal ? 'left' : 'top']: toOffset,\n behavior,\n })\n}\n\nexport interface VirtualizerOptions<\n TScrollElement extends Element | Window,\n TItemElement extends Element,\n> {\n // Required from the user\n count: number\n getScrollElement: () => TScrollElement | null\n estimateSize: (index: number) => number\n\n // Required from the framework adapter (but can be overridden)\n scrollToFn: (\n offset: number,\n options: { adjustments?: number; behavior?: ScrollBehavior },\n instance: Virtualizer,\n ) => void\n observeElementRect: (\n instance: Virtualizer,\n cb: (rect: Rect) => void,\n ) => void | (() => void)\n observeElementOffset: (\n instance: Virtualizer,\n cb: (offset: number, isScrolling: boolean) => void,\n ) => void | (() => void)\n\n // Optional\n debug?: any\n initialRect?: Rect\n onChange?: (\n instance: Virtualizer,\n sync: boolean,\n ) => void\n measureElement?: (\n element: TItemElement,\n entry: ResizeObserverEntry | undefined,\n instance: Virtualizer,\n ) => number\n overscan?: number\n horizontal?: boolean\n paddingStart?: number\n paddingEnd?: number\n scrollPaddingStart?: number\n scrollPaddingEnd?: number\n initialOffset?: number | (() => number)\n getItemKey?: (index: number) => Key\n rangeExtractor?: (range: Range) => Array\n scrollMargin?: number\n gap?: number\n indexAttribute?: string\n initialMeasurementsCache?: Array>\n lanes?: number\n isScrollingResetDelay?: number\n enabled?: boolean\n}\n\nexport class Virtualizer<\n TScrollElement extends Element | Window,\n TItemElement extends Element,\n> {\n private unsubs: Array void)> = []\n options!: Required>\n scrollElement: TScrollElement | null = null\n targetWindow: (Window & typeof globalThis) | null = null\n isScrolling = false\n private scrollToIndexTimeoutId: number | null = null\n measurementsCache: Array> = []\n private itemSizeCache = new Map()\n private pendingMeasuredCacheIndexes: Array = []\n scrollRect: Rect | null = null\n scrollOffset: number | null = null\n scrollDirection: ScrollDirection | null = null\n private scrollAdjustments = 0\n shouldAdjustScrollPositionOnItemSizeChange:\n | undefined\n | ((\n item: VirtualItem,\n delta: number,\n instance: Virtualizer,\n ) => boolean)\n elementsCache = new Map()\n private observer = (() => {\n let _ro: ResizeObserver | null = null\n\n const get = () => {\n if (_ro) {\n return _ro\n }\n\n if (!this.targetWindow || !this.targetWindow.ResizeObserver) {\n return null\n }\n\n return (_ro = new this.targetWindow.ResizeObserver((entries) => {\n entries.forEach((entry) => {\n this._measureElement(entry.target as TItemElement, entry)\n })\n }))\n }\n\n return {\n disconnect: () => get()?.disconnect(),\n observe: (target: Element) =>\n get()?.observe(target, { box: 'border-box' }),\n unobserve: (target: Element) => get()?.unobserve(target),\n }\n })()\n range: { startIndex: number; endIndex: number } | null = null\n\n constructor(opts: VirtualizerOptions) {\n this.setOptions(opts)\n }\n\n setOptions = (opts: VirtualizerOptions) => {\n Object.entries(opts).forEach(([key, value]) => {\n if (typeof value === 'undefined') delete (opts as any)[key]\n })\n\n this.options = {\n debug: false,\n initialOffset: 0,\n overscan: 1,\n paddingStart: 0,\n paddingEnd: 0,\n scrollPaddingStart: 0,\n scrollPaddingEnd: 0,\n horizontal: false,\n getItemKey: defaultKeyExtractor,\n rangeExtractor: defaultRangeExtractor,\n onChange: () => {},\n measureElement,\n initialRect: { width: 0, height: 0 },\n scrollMargin: 0,\n gap: 0,\n indexAttribute: 'data-index',\n initialMeasurementsCache: [],\n lanes: 1,\n isScrollingResetDelay: 150,\n enabled: true,\n ...opts,\n }\n }\n\n private notify = (force: boolean, sync: boolean) => {\n const { startIndex, endIndex } = this.range ?? {\n startIndex: undefined,\n endIndex: undefined,\n }\n const range = this.calculateRange()\n\n if (\n force ||\n startIndex !== range?.startIndex ||\n endIndex !== range?.endIndex\n ) {\n this.options.onChange?.(this, sync)\n }\n }\n\n private cleanup = () => {\n this.unsubs.filter(Boolean).forEach((d) => d!())\n this.unsubs = []\n this.scrollElement = null\n this.targetWindow = null\n this.observer.disconnect()\n this.elementsCache.clear()\n }\n\n _didMount = () => {\n return () => {\n this.cleanup()\n }\n }\n\n _willUpdate = () => {\n const scrollElement = this.options.enabled\n ? this.options.getScrollElement()\n : null\n\n if (this.scrollElement !== scrollElement) {\n this.cleanup()\n\n if (!scrollElement) {\n this.notify(false, false)\n return\n }\n\n this.scrollElement = scrollElement\n\n if (this.scrollElement && 'ownerDocument' in this.scrollElement) {\n this.targetWindow = this.scrollElement.ownerDocument.defaultView\n } else {\n this.targetWindow = this.scrollElement?.window ?? null\n }\n\n this._scrollToOffset(this.getScrollOffset(), {\n adjustments: undefined,\n behavior: undefined,\n })\n\n this.unsubs.push(\n this.options.observeElementRect(this, (rect) => {\n this.scrollRect = rect\n this.notify(false, false)\n }),\n )\n\n this.unsubs.push(\n this.options.observeElementOffset(this, (offset, isScrolling) => {\n this.scrollAdjustments = 0\n this.scrollDirection = isScrolling\n ? this.getScrollOffset() < offset\n ? 'forward'\n : 'backward'\n : null\n this.scrollOffset = offset\n\n const prevIsScrolling = this.isScrolling\n this.isScrolling = isScrolling\n\n this.notify(prevIsScrolling !== isScrolling, isScrolling)\n }),\n )\n }\n }\n\n private getSize = () => {\n if (!this.options.enabled) {\n this.scrollRect = null\n return 0\n }\n\n this.scrollRect = this.scrollRect ?? this.options.initialRect\n\n return this.scrollRect[this.options.horizontal ? 'width' : 'height']\n }\n\n private getScrollOffset = () => {\n if (!this.options.enabled) {\n this.scrollOffset = null\n return 0\n }\n\n this.scrollOffset =\n this.scrollOffset ??\n (typeof this.options.initialOffset === 'function'\n ? this.options.initialOffset()\n : this.options.initialOffset)\n\n return this.scrollOffset\n }\n\n private getFurthestMeasurement = (\n measurements: Array>,\n index: number,\n ) => {\n const furthestMeasurementsFound = new Map()\n const furthestMeasurements = new Map>()\n for (let m = index - 1; m >= 0; m--) {\n const measurement = measurements[m]!\n\n if (furthestMeasurementsFound.has(measurement.lane)) {\n continue\n }\n\n const previousFurthestMeasurement = furthestMeasurements.get(\n measurement.lane,\n )\n if (\n previousFurthestMeasurement == null ||\n measurement.end > previousFurthestMeasurement.end\n ) {\n furthestMeasurements.set(measurement.lane, measurement)\n } else if (measurement.end < previousFurthestMeasurement.end) {\n furthestMeasurementsFound.set(measurement.lane, true)\n }\n\n if (furthestMeasurementsFound.size === this.options.lanes) {\n break\n }\n }\n\n return furthestMeasurements.size === this.options.lanes\n ? Array.from(furthestMeasurements.values()).sort((a, b) => {\n if (a.end === b.end) {\n return a.index - b.index\n }\n\n return a.end - b.end\n })[0]\n : undefined\n }\n\n private getMeasurementOptions = memo(\n () => [\n this.options.count,\n this.options.paddingStart,\n this.options.scrollMargin,\n this.options.getItemKey,\n this.options.enabled,\n ],\n (count, paddingStart, scrollMargin, getItemKey, enabled) => {\n this.pendingMeasuredCacheIndexes = []\n return {\n count,\n paddingStart,\n scrollMargin,\n getItemKey,\n enabled,\n }\n },\n {\n key: false,\n },\n )\n\n private getMeasurements = memo(\n () => [this.getMeasurementOptions(), this.itemSizeCache],\n (\n { count, paddingStart, scrollMargin, getItemKey, enabled },\n itemSizeCache,\n ) => {\n if (!enabled) {\n this.measurementsCache = []\n this.itemSizeCache.clear()\n return []\n }\n\n if (this.measurementsCache.length === 0) {\n this.measurementsCache = this.options.initialMeasurementsCache\n this.measurementsCache.forEach((item) => {\n this.itemSizeCache.set(item.key, item.size)\n })\n }\n\n const min =\n this.pendingMeasuredCacheIndexes.length > 0\n ? Math.min(...this.pendingMeasuredCacheIndexes)\n : 0\n this.pendingMeasuredCacheIndexes = []\n\n const measurements = this.measurementsCache.slice(0, min)\n\n for (let i = min; i < count; i++) {\n let measureElement = this.measurementsCache[i]?.measureElement\n\n if (!measureElement) {\n measureElement = (node: TItemElement | null | undefined) => {\n const key = getItemKey(i)\n const prevNode = this.elementsCache.get(key)\n\n if (!node) {\n if (prevNode) {\n this.observer.unobserve(prevNode)\n this.elementsCache.delete(key)\n }\n return\n }\n\n if (prevNode !== node) {\n if (prevNode) {\n this.observer.unobserve(prevNode)\n }\n this.observer.observe(node)\n this.elementsCache.set(key, node)\n }\n\n if (node.isConnected) {\n this.resizeItem(\n i,\n this.options.measureElement(node, undefined, this),\n )\n }\n }\n }\n\n const key = getItemKey(i)\n\n const furthestMeasurement =\n this.options.lanes === 1\n ? measurements[i - 1]\n : this.getFurthestMeasurement(measurements, i)\n\n const start = furthestMeasurement\n ? furthestMeasurement.end + this.options.gap\n : paddingStart + scrollMargin\n\n const measuredSize = itemSizeCache.get(key)\n const size =\n typeof measuredSize === 'number'\n ? measuredSize\n : this.options.estimateSize(i)\n\n const end = start + size\n\n const lane = furthestMeasurement\n ? furthestMeasurement.lane\n : i % this.options.lanes\n\n measurements[i] = {\n index: i,\n start,\n size,\n end,\n key,\n lane,\n measureElement,\n }\n }\n\n this.measurementsCache = measurements\n\n return measurements\n },\n {\n key: process.env.NODE_ENV !== 'production' && 'getMeasurements',\n debug: () => this.options.debug,\n },\n )\n\n calculateRange = memo(\n () => [this.getMeasurements(), this.getSize(), this.getScrollOffset()],\n (measurements, outerSize, scrollOffset) => {\n return (this.range =\n measurements.length > 0 && outerSize > 0\n ? calculateRange({\n measurements,\n outerSize,\n scrollOffset,\n })\n : null)\n },\n {\n key: process.env.NODE_ENV !== 'production' && 'calculateRange',\n debug: () => this.options.debug,\n },\n )\n\n private getIndexes = memo(\n () => [\n this.options.rangeExtractor,\n this.calculateRange(),\n this.options.overscan,\n this.options.count,\n ],\n (rangeExtractor, range, overscan, count) => {\n return range === null\n ? []\n : rangeExtractor({\n startIndex: range.startIndex,\n endIndex: range.endIndex,\n overscan,\n count,\n })\n },\n {\n key: process.env.NODE_ENV !== 'production' && 'getIndexes',\n debug: () => this.options.debug,\n },\n )\n\n indexFromElement = (node: TItemElement) => {\n const attributeName = this.options.indexAttribute\n const indexStr = node.getAttribute(attributeName)\n\n if (!indexStr) {\n console.warn(\n `Missing attribute name '${attributeName}={index}' on measured element.`,\n )\n return -1\n }\n\n return parseInt(indexStr, 10)\n }\n\n private _measureElement = (\n node: TItemElement,\n entry: ResizeObserverEntry | undefined,\n ) => {\n const i = this.indexFromElement(node)\n const item = this.getMeasurements()[i]\n\n if (!item || !node.isConnected) {\n this.elementsCache.forEach((cached, key) => {\n if (cached === node) {\n this.observer.unobserve(node)\n this.elementsCache.delete(key)\n }\n })\n return\n }\n\n const prevNode = this.elementsCache.get(item.key)\n\n if (prevNode !== node) {\n if (prevNode) {\n this.observer.unobserve(prevNode)\n }\n this.observer.observe(node)\n this.elementsCache.set(item.key, node)\n }\n\n this.resizeItem(i, this.options.measureElement(node, entry, this))\n }\n\n resizeItem = (index: number, size: number) => {\n const item = this.getMeasurements()[index]\n if (!item) {\n return\n }\n const itemSize = this.itemSizeCache.get(item.key) ?? item.size\n const delta = size - itemSize\n\n if (delta !== 0) {\n if (\n this.shouldAdjustScrollPositionOnItemSizeChange !== undefined\n ? this.shouldAdjustScrollPositionOnItemSizeChange(item, delta, this)\n : item.start < this.getScrollOffset() + this.scrollAdjustments\n ) {\n if (process.env.NODE_ENV !== 'production' && this.options.debug) {\n console.info('correction', delta)\n }\n\n this._scrollToOffset(this.getScrollOffset(), {\n adjustments: (this.scrollAdjustments += delta),\n behavior: undefined,\n })\n }\n\n this.pendingMeasuredCacheIndexes.push(item.index)\n this.itemSizeCache = new Map(this.itemSizeCache.set(item.key, size))\n\n this.notify(true, false)\n }\n }\n\n measureElement = (node: TItemElement | null | undefined) => {\n if (!node) {\n return\n }\n\n this._measureElement(node, undefined)\n }\n\n getVirtualItems = memo(\n () => [this.getIndexes(), this.getMeasurements()],\n (indexes, measurements) => {\n const virtualItems: Array> = []\n\n for (let k = 0, len = indexes.length; k < len; k++) {\n const i = indexes[k]!\n const measurement = measurements[i]!\n\n virtualItems.push(measurement)\n }\n\n return virtualItems\n },\n {\n key: process.env.NODE_ENV !== 'production' && 'getIndexes',\n debug: () => this.options.debug,\n },\n )\n\n getVirtualItemForOffset = (offset: number) => {\n const measurements = this.getMeasurements()\n if (measurements.length === 0) {\n return undefined\n }\n return notUndefined(\n measurements[\n findNearestBinarySearch(\n 0,\n measurements.length - 1,\n (index: number) => notUndefined(measurements[index]).start,\n offset,\n )\n ],\n )\n }\n\n getOffsetForAlignment = (toOffset: number, align: ScrollAlignment) => {\n const size = this.getSize()\n const scrollOffset = this.getScrollOffset()\n\n if (align === 'auto') {\n if (toOffset <= scrollOffset) {\n align = 'start'\n } else if (toOffset >= scrollOffset + size) {\n align = 'end'\n } else {\n align = 'start'\n }\n }\n\n if (align === 'start') {\n toOffset = toOffset\n } else if (align === 'end') {\n toOffset = toOffset - size\n } else if (align === 'center') {\n toOffset = toOffset - size / 2\n }\n\n const scrollSizeProp = this.options.horizontal\n ? 'scrollWidth'\n : 'scrollHeight'\n const scrollSize = this.scrollElement\n ? 'document' in this.scrollElement\n ? this.scrollElement.document.documentElement[scrollSizeProp]\n : this.scrollElement[scrollSizeProp]\n : 0\n\n const maxOffset = scrollSize - size\n\n return Math.max(Math.min(maxOffset, toOffset), 0)\n }\n\n getOffsetForIndex = (index: number, align: ScrollAlignment = 'auto') => {\n index = Math.max(0, Math.min(index, this.options.count - 1))\n\n const item = this.getMeasurements()[index]\n if (!item) {\n return undefined\n }\n\n const size = this.getSize()\n const scrollOffset = this.getScrollOffset()\n\n if (align === 'auto') {\n if (item.end >= scrollOffset + size - this.options.scrollPaddingEnd) {\n align = 'end'\n } else if (item.start <= scrollOffset + this.options.scrollPaddingStart) {\n align = 'start'\n } else {\n return [scrollOffset, align] as const\n }\n }\n\n const toOffset =\n align === 'end'\n ? item.end + this.options.scrollPaddingEnd\n : item.start - this.options.scrollPaddingStart\n\n return [this.getOffsetForAlignment(toOffset, align), align] as const\n }\n\n private isDynamicMode = () => this.elementsCache.size > 0\n\n private cancelScrollToIndex = () => {\n if (this.scrollToIndexTimeoutId !== null && this.targetWindow) {\n this.targetWindow.clearTimeout(this.scrollToIndexTimeoutId)\n this.scrollToIndexTimeoutId = null\n }\n }\n\n scrollToOffset = (\n toOffset: number,\n { align = 'start', behavior }: ScrollToOffsetOptions = {},\n ) => {\n this.cancelScrollToIndex()\n\n if (behavior === 'smooth' && this.isDynamicMode()) {\n console.warn(\n 'The `smooth` scroll behavior is not fully supported with dynamic size.',\n )\n }\n\n this._scrollToOffset(this.getOffsetForAlignment(toOffset, align), {\n adjustments: undefined,\n behavior,\n })\n }\n\n scrollToIndex = (\n index: number,\n { align: initialAlign = 'auto', behavior }: ScrollToIndexOptions = {},\n ) => {\n index = Math.max(0, Math.min(index, this.options.count - 1))\n\n this.cancelScrollToIndex()\n\n if (behavior === 'smooth' && this.isDynamicMode()) {\n console.warn(\n 'The `smooth` scroll behavior is not fully supported with dynamic size.',\n )\n }\n\n const offsetAndAlign = this.getOffsetForIndex(index, initialAlign)\n if (!offsetAndAlign) return\n\n const [offset, align] = offsetAndAlign\n\n this._scrollToOffset(offset, { adjustments: undefined, behavior })\n\n if (behavior !== 'smooth' && this.isDynamicMode() && this.targetWindow) {\n this.scrollToIndexTimeoutId = this.targetWindow.setTimeout(() => {\n this.scrollToIndexTimeoutId = null\n\n const elementInDOM = this.elementsCache.has(\n this.options.getItemKey(index),\n )\n\n if (elementInDOM) {\n const [latestOffset] = notUndefined(\n this.getOffsetForIndex(index, align),\n )\n\n if (!approxEqual(latestOffset, this.getScrollOffset())) {\n this.scrollToIndex(index, { align, behavior })\n }\n } else {\n this.scrollToIndex(index, { align, behavior })\n }\n })\n }\n }\n\n scrollBy = (delta: number, { behavior }: ScrollToOffsetOptions = {}) => {\n this.cancelScrollToIndex()\n\n if (behavior === 'smooth' && this.isDynamicMode()) {\n console.warn(\n 'The `smooth` scroll behavior is not fully supported with dynamic size.',\n )\n }\n\n this._scrollToOffset(this.getScrollOffset() + delta, {\n adjustments: undefined,\n behavior,\n })\n }\n\n getTotalSize = () => {\n const measurements = this.getMeasurements()\n\n let end: number\n // If there are no measurements, set the end to paddingStart\n if (measurements.length === 0) {\n end = this.options.paddingStart\n } else {\n // If lanes is 1, use the last measurement's end, otherwise find the maximum end value among all measurements\n end =\n this.options.lanes === 1\n ? measurements[measurements.length - 1]?.end ?? 0\n : Math.max(\n ...measurements.slice(-this.options.lanes).map((m) => m.end),\n )\n }\n\n return end - this.options.scrollMargin + this.options.paddingEnd\n }\n\n private _scrollToOffset = (\n offset: number,\n {\n adjustments,\n behavior,\n }: {\n adjustments: number | undefined\n behavior: ScrollBehavior | undefined\n },\n ) => {\n this.options.scrollToFn(offset, { behavior, adjustments }, this)\n }\n\n measure = () => {\n this.itemSizeCache = new Map()\n this.options.onChange?.(this, false)\n }\n}\n\nconst findNearestBinarySearch = (\n low: number,\n high: number,\n getCurrentValue: (i: number) => number,\n value: number,\n) => {\n while (low <= high) {\n const middle = ((low + high) / 2) | 0\n const currentValue = getCurrentValue(middle)\n\n if (currentValue < value) {\n low = middle + 1\n } else if (currentValue > value) {\n high = middle - 1\n } else {\n return middle\n }\n }\n\n if (low > 0) {\n return low - 1\n } else {\n return 0\n }\n}\n\nfunction calculateRange({\n measurements,\n outerSize,\n scrollOffset,\n}: {\n measurements: Array>\n outerSize: number\n scrollOffset: number\n}) {\n const count = measurements.length - 1\n const getOffset = (index: number) => measurements[index]!.start\n\n const startIndex = findNearestBinarySearch(0, count, getOffset, scrollOffset)\n let endIndex = startIndex\n\n while (\n endIndex < count &&\n measurements[endIndex]!.end < scrollOffset + outerSize\n ) {\n endIndex++\n }\n\n return { startIndex, endIndex }\n}\n", "import * as React from 'react'\nimport { flushSync } from 'react-dom'\nimport {\n Virtualizer,\n elementScroll,\n observeElementOffset,\n observeElementRect,\n observeWindowOffset,\n observeWindowRect,\n windowScroll,\n} from '@tanstack/virtual-core'\nimport type { PartialKeys, VirtualizerOptions } from '@tanstack/virtual-core'\n\nexport * from '@tanstack/virtual-core'\n\nconst useIsomorphicLayoutEffect =\n typeof document !== 'undefined' ? React.useLayoutEffect : React.useEffect\n\nfunction useVirtualizerBase<\n TScrollElement extends Element | Window,\n TItemElement extends Element,\n>(\n options: VirtualizerOptions,\n): Virtualizer {\n const rerender = React.useReducer(() => ({}), {})[1]\n\n const resolvedOptions: VirtualizerOptions = {\n ...options,\n onChange: (instance, sync) => {\n if (sync) {\n flushSync(rerender)\n } else {\n rerender()\n }\n options.onChange?.(instance, sync)\n },\n }\n\n const [instance] = React.useState(\n () => new Virtualizer(resolvedOptions),\n )\n\n instance.setOptions(resolvedOptions)\n\n React.useEffect(() => {\n return instance._didMount()\n }, [])\n\n useIsomorphicLayoutEffect(() => {\n return instance._willUpdate()\n })\n\n return instance\n}\n\nexport function useVirtualizer<\n TScrollElement extends Element,\n TItemElement extends Element,\n>(\n options: PartialKeys<\n VirtualizerOptions,\n 'observeElementRect' | 'observeElementOffset' | 'scrollToFn'\n >,\n): Virtualizer {\n return useVirtualizerBase({\n observeElementRect: observeElementRect,\n observeElementOffset: observeElementOffset,\n scrollToFn: elementScroll,\n ...options,\n })\n}\n\nexport function useWindowVirtualizer(\n options: PartialKeys<\n VirtualizerOptions,\n | 'getScrollElement'\n | 'observeElementRect'\n | 'observeElementOffset'\n | 'scrollToFn'\n >,\n): Virtualizer {\n return useVirtualizerBase({\n getScrollElement: () => (typeof document !== 'undefined' ? window : null),\n observeElementRect: observeWindowRect,\n observeElementOffset: observeWindowOffset,\n scrollToFn: windowScroll,\n initialOffset: () => (typeof document !== 'undefined' ? window.scrollY : 0),\n ...options,\n })\n}\n", "import { render, hydrate, unmountComponentAtNode } from 'preact/compat';\n\nexport function createRoot(container) {\n\treturn {\n\t\t// eslint-disable-next-line\n\t\trender: function (children) {\n\t\t\trender(children, container);\n\t\t},\n\t\t// eslint-disable-next-line\n\t\tunmount: function () {\n\t\t\tunmountComponentAtNode(container);\n\t\t}\n\t};\n}\n\nexport function hydrateRoot(container, children) {\n\thydrate(children, container);\n\treturn createRoot(container);\n}\n\nexport default {\n\tcreateRoot,\n\thydrateRoot\n};\n", "// Should be no imports here!\n\n/**\n * The sentinel value returned by producers to replace the draft with undefined.\n */\nexport const NOTHING: unique symbol = Symbol.for(\"immer-nothing\")\n\n/**\n * To let Immer treat your class instances as plain immutable objects\n * (albeit with a custom prototype), you must define either an instance property\n * or a static property on each of your custom classes.\n *\n * Otherwise, your class instance will never be drafted, which means it won't be\n * safe to mutate in a produce callback.\n */\nexport const DRAFTABLE: unique symbol = Symbol.for(\"immer-draftable\")\n\nexport const DRAFT_STATE: unique symbol = Symbol.for(\"immer-state\")\n", "export const errors =\n\tprocess.env.NODE_ENV !== \"production\"\n\t\t? [\n\t\t\t\t// All error codes, starting by 0:\n\t\t\t\tfunction(plugin: string) {\n\t\t\t\t\treturn `The plugin for '${plugin}' has not been loaded into Immer. To enable the plugin, import and call \\`enable${plugin}()\\` when initializing your application.`\n\t\t\t\t},\n\t\t\t\tfunction(thing: string) {\n\t\t\t\t\treturn `produce can only be called on things that are draftable: plain objects, arrays, Map, Set or classes that are marked with '[immerable]: true'. Got '${thing}'`\n\t\t\t\t},\n\t\t\t\t\"This object has been frozen and should not be mutated\",\n\t\t\t\tfunction(data: any) {\n\t\t\t\t\treturn (\n\t\t\t\t\t\t\"Cannot use a proxy that has been revoked. Did you pass an object from inside an immer function to an async process? \" +\n\t\t\t\t\t\tdata\n\t\t\t\t\t)\n\t\t\t\t},\n\t\t\t\t\"An immer producer returned a new value *and* modified its draft. Either return a new value *or* modify the draft.\",\n\t\t\t\t\"Immer forbids circular references\",\n\t\t\t\t\"The first or second argument to `produce` must be a function\",\n\t\t\t\t\"The third argument to `produce` must be a function or undefined\",\n\t\t\t\t\"First argument to `createDraft` must be a plain object, an array, or an immerable object\",\n\t\t\t\t\"First argument to `finishDraft` must be a draft returned by `createDraft`\",\n\t\t\t\tfunction(thing: string) {\n\t\t\t\t\treturn `'current' expects a draft, got: ${thing}`\n\t\t\t\t},\n\t\t\t\t\"Object.defineProperty() cannot be used on an Immer draft\",\n\t\t\t\t\"Object.setPrototypeOf() cannot be used on an Immer draft\",\n\t\t\t\t\"Immer only supports deleting array indices\",\n\t\t\t\t\"Immer only supports setting array indices and the 'length' property\",\n\t\t\t\tfunction(thing: string) {\n\t\t\t\t\treturn `'original' expects a draft, got: ${thing}`\n\t\t\t\t}\n\t\t\t\t// Note: if more errors are added, the errorOffset in Patches.ts should be increased\n\t\t\t\t// See Patches.ts for additional errors\n\t\t ]\n\t\t: []\n\nexport function die(error: number, ...args: any[]): never {\n\tif (process.env.NODE_ENV !== \"production\") {\n\t\tconst e = errors[error]\n\t\tconst msg = typeof e === \"function\" ? e.apply(null, args as any) : e\n\t\tthrow new Error(`[Immer] ${msg}`)\n\t}\n\tthrow new Error(\n\t\t`[Immer] minified error nr: ${error}. Full error at: https://bit.ly/3cXEKWf`\n\t)\n}\n", "import {\n\tDRAFT_STATE,\n\tDRAFTABLE,\n\tObjectish,\n\tDrafted,\n\tAnyObject,\n\tAnyMap,\n\tAnySet,\n\tImmerState,\n\tArchType,\n\tdie\n} from \"../internal\"\n\nexport const getPrototypeOf = Object.getPrototypeOf\n\n/** Returns true if the given value is an Immer draft */\n/*#__PURE__*/\nexport function isDraft(value: any): boolean {\n\treturn !!value && !!value[DRAFT_STATE]\n}\n\n/** Returns true if the given value can be drafted by Immer */\n/*#__PURE__*/\nexport function isDraftable(value: any): boolean {\n\tif (!value) return false\n\treturn (\n\t\tisPlainObject(value) ||\n\t\tArray.isArray(value) ||\n\t\t!!value[DRAFTABLE] ||\n\t\t!!value.constructor?.[DRAFTABLE] ||\n\t\tisMap(value) ||\n\t\tisSet(value)\n\t)\n}\n\nconst objectCtorString = Object.prototype.constructor.toString()\n/*#__PURE__*/\nexport function isPlainObject(value: any): boolean {\n\tif (!value || typeof value !== \"object\") return false\n\tconst proto = getPrototypeOf(value)\n\tif (proto === null) {\n\t\treturn true\n\t}\n\tconst Ctor =\n\t\tObject.hasOwnProperty.call(proto, \"constructor\") && proto.constructor\n\n\tif (Ctor === Object) return true\n\n\treturn (\n\t\ttypeof Ctor == \"function\" &&\n\t\tFunction.toString.call(Ctor) === objectCtorString\n\t)\n}\n\n/** Get the underlying object that is represented by the given draft */\n/*#__PURE__*/\nexport function original(value: T): T | undefined\nexport function original(value: Drafted): any {\n\tif (!isDraft(value)) die(15, value)\n\treturn value[DRAFT_STATE].base_\n}\n\nexport function each(\n\tobj: T,\n\titer: (key: string | number, value: any, source: T) => void,\n\tenumerableOnly?: boolean\n): void\nexport function each(obj: any, iter: any) {\n\tif (getArchtype(obj) === ArchType.Object) {\n\t\tObject.entries(obj).forEach(([key, value]) => {\n\t\t\titer(key, value, obj)\n\t\t})\n\t} else {\n\t\tobj.forEach((entry: any, index: any) => iter(index, entry, obj))\n\t}\n}\n\n/*#__PURE__*/\nexport function getArchtype(thing: any): ArchType {\n\tconst state: undefined | ImmerState = thing[DRAFT_STATE]\n\treturn state\n\t\t? state.type_\n\t\t: Array.isArray(thing)\n\t\t? ArchType.Array\n\t\t: isMap(thing)\n\t\t? ArchType.Map\n\t\t: isSet(thing)\n\t\t? ArchType.Set\n\t\t: ArchType.Object\n}\n\n/*#__PURE__*/\nexport function has(thing: any, prop: PropertyKey): boolean {\n\treturn getArchtype(thing) === ArchType.Map\n\t\t? thing.has(prop)\n\t\t: Object.prototype.hasOwnProperty.call(thing, prop)\n}\n\n/*#__PURE__*/\nexport function get(thing: AnyMap | AnyObject, prop: PropertyKey): any {\n\t// @ts-ignore\n\treturn getArchtype(thing) === ArchType.Map ? thing.get(prop) : thing[prop]\n}\n\n/*#__PURE__*/\nexport function set(thing: any, propOrOldValue: PropertyKey, value: any) {\n\tconst t = getArchtype(thing)\n\tif (t === ArchType.Map) thing.set(propOrOldValue, value)\n\telse if (t === ArchType.Set) {\n\t\tthing.add(value)\n\t} else thing[propOrOldValue] = value\n}\n\n/*#__PURE__*/\nexport function is(x: any, y: any): boolean {\n\t// From: https://github.com/facebook/fbjs/blob/c69904a511b900266935168223063dd8772dfc40/packages/fbjs/src/core/shallowEqual.js\n\tif (x === y) {\n\t\treturn x !== 0 || 1 / x === 1 / y\n\t} else {\n\t\treturn x !== x && y !== y\n\t}\n}\n\n/*#__PURE__*/\nexport function isMap(target: any): target is AnyMap {\n\treturn target instanceof Map\n}\n\n/*#__PURE__*/\nexport function isSet(target: any): target is AnySet {\n\treturn target instanceof Set\n}\n/*#__PURE__*/\nexport function latest(state: ImmerState): any {\n\treturn state.copy_ || state.base_\n}\n\n/*#__PURE__*/\nexport function shallowCopy(base: any, strict: boolean) {\n\tif (isMap(base)) {\n\t\treturn new Map(base)\n\t}\n\tif (isSet(base)) {\n\t\treturn new Set(base)\n\t}\n\tif (Array.isArray(base)) return Array.prototype.slice.call(base)\n\n\tif (!strict && isPlainObject(base)) {\n\t\tif (!getPrototypeOf(base)) {\n\t\t\tconst obj = Object.create(null)\n\t\t\treturn Object.assign(obj, base)\n\t\t}\n\t\treturn {...base}\n\t}\n\n\tconst descriptors = Object.getOwnPropertyDescriptors(base)\n\tdelete descriptors[DRAFT_STATE as any]\n\tlet keys = Reflect.ownKeys(descriptors)\n\tfor (let i = 0; i < keys.length; i++) {\n\t\tconst key: any = keys[i]\n\t\tconst desc = descriptors[key]\n\t\tif (desc.writable === false) {\n\t\t\tdesc.writable = true\n\t\t\tdesc.configurable = true\n\t\t}\n\t\t// like object.assign, we will read any _own_, get/set accessors. This helps in dealing\n\t\t// with libraries that trap values, like mobx or vue\n\t\t// unlike object.assign, non-enumerables will be copied as well\n\t\tif (desc.get || desc.set)\n\t\t\tdescriptors[key] = {\n\t\t\t\tconfigurable: true,\n\t\t\t\twritable: true, // could live with !!desc.set as well here...\n\t\t\t\tenumerable: desc.enumerable,\n\t\t\t\tvalue: base[key]\n\t\t\t}\n\t}\n\treturn Object.create(getPrototypeOf(base), descriptors)\n}\n\n/**\n * Freezes draftable objects. Returns the original object.\n * By default freezes shallowly, but if the second argument is `true` it will freeze recursively.\n *\n * @param obj\n * @param deep\n */\nexport function freeze(obj: T, deep?: boolean): T\nexport function freeze(obj: any, deep: boolean = false): T {\n\tif (isFrozen(obj) || isDraft(obj) || !isDraftable(obj)) return obj\n\tif (getArchtype(obj) > 1 /* Map or Set */) {\n\t\tobj.set = obj.add = obj.clear = obj.delete = dontMutateFrozenCollections as any\n\t}\n\tObject.freeze(obj)\n\tif (deep) each(obj, (_key, value) => freeze(value, true), true)\n\treturn obj\n}\n\nfunction dontMutateFrozenCollections() {\n\tdie(2)\n}\n\nexport function isFrozen(obj: any): boolean {\n\treturn Object.isFrozen(obj)\n}\n", "import {\n\tImmerState,\n\tPatch,\n\tDrafted,\n\tImmerBaseState,\n\tAnyMap,\n\tAnySet,\n\tArchType,\n\tdie\n} from \"../internal\"\n\n/** Plugin utilities */\nconst plugins: {\n\tPatches?: {\n\t\tgeneratePatches_(\n\t\t\tstate: ImmerState,\n\t\t\tbasePath: PatchPath,\n\t\t\tpatches: Patch[],\n\t\t\tinversePatches: Patch[]\n\t\t): void\n\t\tgenerateReplacementPatches_(\n\t\t\tbase: any,\n\t\t\treplacement: any,\n\t\t\tpatches: Patch[],\n\t\t\tinversePatches: Patch[]\n\t\t): void\n\t\tapplyPatches_(draft: T, patches: Patch[]): T\n\t}\n\tMapSet?: {\n\t\tproxyMap_(target: T, parent?: ImmerState): T\n\t\tproxySet_(target: T, parent?: ImmerState): T\n\t}\n} = {}\n\ntype Plugins = typeof plugins\n\nexport function getPlugin(\n\tpluginKey: K\n): Exclude {\n\tconst plugin = plugins[pluginKey]\n\tif (!plugin) {\n\t\tdie(0, pluginKey)\n\t}\n\t// @ts-ignore\n\treturn plugin\n}\n\nexport function loadPlugin(\n\tpluginKey: K,\n\timplementation: Plugins[K]\n): void {\n\tif (!plugins[pluginKey]) plugins[pluginKey] = implementation\n}\n/** Map / Set plugin */\n\nexport interface MapState extends ImmerBaseState {\n\ttype_: ArchType.Map\n\tcopy_: AnyMap | undefined\n\tassigned_: Map | undefined\n\tbase_: AnyMap\n\trevoked_: boolean\n\tdraft_: Drafted\n}\n\nexport interface SetState extends ImmerBaseState {\n\ttype_: ArchType.Set\n\tcopy_: AnySet | undefined\n\tbase_: AnySet\n\tdrafts_: Map // maps the original value to the draft value in the new set\n\trevoked_: boolean\n\tdraft_: Drafted\n}\n\n/** Patches plugin */\n\nexport type PatchPath = (string | number)[]\n", "import {\n\tPatch,\n\tPatchListener,\n\tDrafted,\n\tImmer,\n\tDRAFT_STATE,\n\tImmerState,\n\tArchType,\n\tgetPlugin\n} from \"../internal\"\n\n/** Each scope represents a `produce` call. */\n\nexport interface ImmerScope {\n\tpatches_?: Patch[]\n\tinversePatches_?: Patch[]\n\tcanAutoFreeze_: boolean\n\tdrafts_: any[]\n\tparent_?: ImmerScope\n\tpatchListener_?: PatchListener\n\timmer_: Immer\n\tunfinalizedDrafts_: number\n}\n\nlet currentScope: ImmerScope | undefined\n\nexport function getCurrentScope() {\n\treturn currentScope!\n}\n\nfunction createScope(\n\tparent_: ImmerScope | undefined,\n\timmer_: Immer\n): ImmerScope {\n\treturn {\n\t\tdrafts_: [],\n\t\tparent_,\n\t\timmer_,\n\t\t// Whenever the modified draft contains a draft from another scope, we\n\t\t// need to prevent auto-freezing so the unowned draft can be finalized.\n\t\tcanAutoFreeze_: true,\n\t\tunfinalizedDrafts_: 0\n\t}\n}\n\nexport function usePatchesInScope(\n\tscope: ImmerScope,\n\tpatchListener?: PatchListener\n) {\n\tif (patchListener) {\n\t\tgetPlugin(\"Patches\") // assert we have the plugin\n\t\tscope.patches_ = []\n\t\tscope.inversePatches_ = []\n\t\tscope.patchListener_ = patchListener\n\t}\n}\n\nexport function revokeScope(scope: ImmerScope) {\n\tleaveScope(scope)\n\tscope.drafts_.forEach(revokeDraft)\n\t// @ts-ignore\n\tscope.drafts_ = null\n}\n\nexport function leaveScope(scope: ImmerScope) {\n\tif (scope === currentScope) {\n\t\tcurrentScope = scope.parent_\n\t}\n}\n\nexport function enterScope(immer: Immer) {\n\treturn (currentScope = createScope(currentScope, immer))\n}\n\nfunction revokeDraft(draft: Drafted) {\n\tconst state: ImmerState = draft[DRAFT_STATE]\n\tif (state.type_ === ArchType.Object || state.type_ === ArchType.Array)\n\t\tstate.revoke_()\n\telse state.revoked_ = true\n}\n", "import {\n\tImmerScope,\n\tDRAFT_STATE,\n\tisDraftable,\n\tNOTHING,\n\tPatchPath,\n\teach,\n\thas,\n\tfreeze,\n\tImmerState,\n\tisDraft,\n\tSetState,\n\tset,\n\tArchType,\n\tgetPlugin,\n\tdie,\n\trevokeScope,\n\tisFrozen\n} from \"../internal\"\n\nexport function processResult(result: any, scope: ImmerScope) {\n\tscope.unfinalizedDrafts_ = scope.drafts_.length\n\tconst baseDraft = scope.drafts_![0]\n\tconst isReplaced = result !== undefined && result !== baseDraft\n\tif (isReplaced) {\n\t\tif (baseDraft[DRAFT_STATE].modified_) {\n\t\t\trevokeScope(scope)\n\t\t\tdie(4)\n\t\t}\n\t\tif (isDraftable(result)) {\n\t\t\t// Finalize the result in case it contains (or is) a subset of the draft.\n\t\t\tresult = finalize(scope, result)\n\t\t\tif (!scope.parent_) maybeFreeze(scope, result)\n\t\t}\n\t\tif (scope.patches_) {\n\t\t\tgetPlugin(\"Patches\").generateReplacementPatches_(\n\t\t\t\tbaseDraft[DRAFT_STATE].base_,\n\t\t\t\tresult,\n\t\t\t\tscope.patches_,\n\t\t\t\tscope.inversePatches_!\n\t\t\t)\n\t\t}\n\t} else {\n\t\t// Finalize the base draft.\n\t\tresult = finalize(scope, baseDraft, [])\n\t}\n\trevokeScope(scope)\n\tif (scope.patches_) {\n\t\tscope.patchListener_!(scope.patches_, scope.inversePatches_!)\n\t}\n\treturn result !== NOTHING ? result : undefined\n}\n\nfunction finalize(rootScope: ImmerScope, value: any, path?: PatchPath) {\n\t// Don't recurse in tho recursive data structures\n\tif (isFrozen(value)) return value\n\n\tconst state: ImmerState = value[DRAFT_STATE]\n\t// A plain object, might need freezing, might contain drafts\n\tif (!state) {\n\t\teach(\n\t\t\tvalue,\n\t\t\t(key, childValue) =>\n\t\t\t\tfinalizeProperty(rootScope, state, value, key, childValue, path),\n\t\t\ttrue // See #590, don't recurse into non-enumerable of non drafted objects\n\t\t)\n\t\treturn value\n\t}\n\t// Never finalize drafts owned by another scope.\n\tif (state.scope_ !== rootScope) return value\n\t// Unmodified draft, return the (frozen) original\n\tif (!state.modified_) {\n\t\tmaybeFreeze(rootScope, state.base_, true)\n\t\treturn state.base_\n\t}\n\t// Not finalized yet, let's do that now\n\tif (!state.finalized_) {\n\t\tstate.finalized_ = true\n\t\tstate.scope_.unfinalizedDrafts_--\n\t\tconst result = state.copy_\n\t\t// Finalize all children of the copy\n\t\t// For sets we clone before iterating, otherwise we can get in endless loop due to modifying during iteration, see #628\n\t\t// To preserve insertion order in all cases we then clear the set\n\t\t// And we let finalizeProperty know it needs to re-add non-draft children back to the target\n\t\tlet resultEach = result\n\t\tlet isSet = false\n\t\tif (state.type_ === ArchType.Set) {\n\t\t\tresultEach = new Set(result)\n\t\t\tresult.clear()\n\t\t\tisSet = true\n\t\t}\n\t\teach(resultEach, (key, childValue) =>\n\t\t\tfinalizeProperty(rootScope, state, result, key, childValue, path, isSet)\n\t\t)\n\t\t// everything inside is frozen, we can freeze here\n\t\tmaybeFreeze(rootScope, result, false)\n\t\t// first time finalizing, let's create those patches\n\t\tif (path && rootScope.patches_) {\n\t\t\tgetPlugin(\"Patches\").generatePatches_(\n\t\t\t\tstate,\n\t\t\t\tpath,\n\t\t\t\trootScope.patches_,\n\t\t\t\trootScope.inversePatches_!\n\t\t\t)\n\t\t}\n\t}\n\treturn state.copy_\n}\n\nfunction finalizeProperty(\n\trootScope: ImmerScope,\n\tparentState: undefined | ImmerState,\n\ttargetObject: any,\n\tprop: string | number,\n\tchildValue: any,\n\trootPath?: PatchPath,\n\ttargetIsSet?: boolean\n) {\n\tif (process.env.NODE_ENV !== \"production\" && childValue === targetObject)\n\t\tdie(5)\n\tif (isDraft(childValue)) {\n\t\tconst path =\n\t\t\trootPath &&\n\t\t\tparentState &&\n\t\t\tparentState!.type_ !== ArchType.Set && // Set objects are atomic since they have no keys.\n\t\t\t!has((parentState as Exclude).assigned_!, prop) // Skip deep patches for assigned keys.\n\t\t\t\t? rootPath!.concat(prop)\n\t\t\t\t: undefined\n\t\t// Drafts owned by `scope` are finalized here.\n\t\tconst res = finalize(rootScope, childValue, path)\n\t\tset(targetObject, prop, res)\n\t\t// Drafts from another scope must prevented to be frozen\n\t\t// if we got a draft back from finalize, we're in a nested produce and shouldn't freeze\n\t\tif (isDraft(res)) {\n\t\t\trootScope.canAutoFreeze_ = false\n\t\t} else return\n\t} else if (targetIsSet) {\n\t\ttargetObject.add(childValue)\n\t}\n\t// Search new objects for unfinalized drafts. Frozen objects should never contain drafts.\n\tif (isDraftable(childValue) && !isFrozen(childValue)) {\n\t\tif (!rootScope.immer_.autoFreeze_ && rootScope.unfinalizedDrafts_ < 1) {\n\t\t\t// optimization: if an object is not a draft, and we don't have to\n\t\t\t// deepfreeze everything, and we are sure that no drafts are left in the remaining object\n\t\t\t// cause we saw and finalized all drafts already; we can stop visiting the rest of the tree.\n\t\t\t// This benefits especially adding large data tree's without further processing.\n\t\t\t// See add-data.js perf test\n\t\t\treturn\n\t\t}\n\t\tfinalize(rootScope, childValue)\n\t\t// immer deep freezes plain objects, so if there is no parent state, we freeze as well\n\t\tif (!parentState || !parentState.scope_.parent_)\n\t\t\tmaybeFreeze(rootScope, childValue)\n\t}\n}\n\nfunction maybeFreeze(scope: ImmerScope, value: any, deep = false) {\n\t// we never freeze for a non-root scope; as it would prevent pruning for drafts inside wrapping objects\n\tif (!scope.parent_ && scope.immer_.autoFreeze_ && scope.canAutoFreeze_) {\n\t\tfreeze(value, deep)\n\t}\n}\n", "import {\n\teach,\n\thas,\n\tis,\n\tisDraftable,\n\tshallowCopy,\n\tlatest,\n\tImmerBaseState,\n\tImmerState,\n\tDrafted,\n\tAnyObject,\n\tAnyArray,\n\tObjectish,\n\tgetCurrentScope,\n\tgetPrototypeOf,\n\tDRAFT_STATE,\n\tdie,\n\tcreateProxy,\n\tArchType,\n\tImmerScope\n} from \"../internal\"\n\ninterface ProxyBaseState extends ImmerBaseState {\n\tassigned_: {\n\t\t[property: string]: boolean\n\t}\n\tparent_?: ImmerState\n\trevoke_(): void\n}\n\nexport interface ProxyObjectState extends ProxyBaseState {\n\ttype_: ArchType.Object\n\tbase_: any\n\tcopy_: any\n\tdraft_: Drafted\n}\n\nexport interface ProxyArrayState extends ProxyBaseState {\n\ttype_: ArchType.Array\n\tbase_: AnyArray\n\tcopy_: AnyArray | null\n\tdraft_: Drafted\n}\n\ntype ProxyState = ProxyObjectState | ProxyArrayState\n\n/**\n * Returns a new draft of the `base` object.\n *\n * The second argument is the parent draft-state (used internally).\n */\nexport function createProxyProxy(\n\tbase: T,\n\tparent?: ImmerState\n): Drafted {\n\tconst isArray = Array.isArray(base)\n\tconst state: ProxyState = {\n\t\ttype_: isArray ? ArchType.Array : (ArchType.Object as any),\n\t\t// Track which produce call this is associated with.\n\t\tscope_: parent ? parent.scope_ : getCurrentScope()!,\n\t\t// True for both shallow and deep changes.\n\t\tmodified_: false,\n\t\t// Used during finalization.\n\t\tfinalized_: false,\n\t\t// Track which properties have been assigned (true) or deleted (false).\n\t\tassigned_: {},\n\t\t// The parent draft state.\n\t\tparent_: parent,\n\t\t// The base state.\n\t\tbase_: base,\n\t\t// The base proxy.\n\t\tdraft_: null as any, // set below\n\t\t// The base copy with any updated values.\n\t\tcopy_: null,\n\t\t// Called by the `produce` function.\n\t\trevoke_: null as any,\n\t\tisManual_: false\n\t}\n\n\t// the traps must target something, a bit like the 'real' base.\n\t// but also, we need to be able to determine from the target what the relevant state is\n\t// (to avoid creating traps per instance to capture the state in closure,\n\t// and to avoid creating weird hidden properties as well)\n\t// So the trick is to use 'state' as the actual 'target'! (and make sure we intercept everything)\n\t// Note that in the case of an array, we put the state in an array to have better Reflect defaults ootb\n\tlet target: T = state as any\n\tlet traps: ProxyHandler> = objectTraps\n\tif (isArray) {\n\t\ttarget = [state] as any\n\t\ttraps = arrayTraps\n\t}\n\n\tconst {revoke, proxy} = Proxy.revocable(target, traps)\n\tstate.draft_ = proxy as any\n\tstate.revoke_ = revoke\n\treturn proxy as any\n}\n\n/**\n * Object drafts\n */\nexport const objectTraps: ProxyHandler = {\n\tget(state, prop) {\n\t\tif (prop === DRAFT_STATE) return state\n\n\t\tconst source = latest(state)\n\t\tif (!has(source, prop)) {\n\t\t\t// non-existing or non-own property...\n\t\t\treturn readPropFromProto(state, source, prop)\n\t\t}\n\t\tconst value = source[prop]\n\t\tif (state.finalized_ || !isDraftable(value)) {\n\t\t\treturn value\n\t\t}\n\t\t// Check for existing draft in modified state.\n\t\t// Assigned values are never drafted. This catches any drafts we created, too.\n\t\tif (value === peek(state.base_, prop)) {\n\t\t\tprepareCopy(state)\n\t\t\treturn (state.copy_![prop as any] = createProxy(value, state))\n\t\t}\n\t\treturn value\n\t},\n\thas(state, prop) {\n\t\treturn prop in latest(state)\n\t},\n\townKeys(state) {\n\t\treturn Reflect.ownKeys(latest(state))\n\t},\n\tset(\n\t\tstate: ProxyObjectState,\n\t\tprop: string /* strictly not, but helps TS */,\n\t\tvalue\n\t) {\n\t\tconst desc = getDescriptorFromProto(latest(state), prop)\n\t\tif (desc?.set) {\n\t\t\t// special case: if this write is captured by a setter, we have\n\t\t\t// to trigger it with the correct context\n\t\t\tdesc.set.call(state.draft_, value)\n\t\t\treturn true\n\t\t}\n\t\tif (!state.modified_) {\n\t\t\t// the last check is because we need to be able to distinguish setting a non-existing to undefined (which is a change)\n\t\t\t// from setting an existing property with value undefined to undefined (which is not a change)\n\t\t\tconst current = peek(latest(state), prop)\n\t\t\t// special case, if we assigning the original value to a draft, we can ignore the assignment\n\t\t\tconst currentState: ProxyObjectState = current?.[DRAFT_STATE]\n\t\t\tif (currentState && currentState.base_ === value) {\n\t\t\t\tstate.copy_![prop] = value\n\t\t\t\tstate.assigned_[prop] = false\n\t\t\t\treturn true\n\t\t\t}\n\t\t\tif (is(value, current) && (value !== undefined || has(state.base_, prop)))\n\t\t\t\treturn true\n\t\t\tprepareCopy(state)\n\t\t\tmarkChanged(state)\n\t\t}\n\n\t\tif (\n\t\t\t(state.copy_![prop] === value &&\n\t\t\t\t// special case: handle new props with value 'undefined'\n\t\t\t\t(value !== undefined || prop in state.copy_)) ||\n\t\t\t// special case: NaN\n\t\t\t(Number.isNaN(value) && Number.isNaN(state.copy_![prop]))\n\t\t)\n\t\t\treturn true\n\n\t\t// @ts-ignore\n\t\tstate.copy_![prop] = value\n\t\tstate.assigned_[prop] = true\n\t\treturn true\n\t},\n\tdeleteProperty(state, prop: string) {\n\t\t// The `undefined` check is a fast path for pre-existing keys.\n\t\tif (peek(state.base_, prop) !== undefined || prop in state.base_) {\n\t\t\tstate.assigned_[prop] = false\n\t\t\tprepareCopy(state)\n\t\t\tmarkChanged(state)\n\t\t} else {\n\t\t\t// if an originally not assigned property was deleted\n\t\t\tdelete state.assigned_[prop]\n\t\t}\n\t\tif (state.copy_) {\n\t\t\tdelete state.copy_[prop]\n\t\t}\n\t\treturn true\n\t},\n\t// Note: We never coerce `desc.value` into an Immer draft, because we can't make\n\t// the same guarantee in ES5 mode.\n\tgetOwnPropertyDescriptor(state, prop) {\n\t\tconst owner = latest(state)\n\t\tconst desc = Reflect.getOwnPropertyDescriptor(owner, prop)\n\t\tif (!desc) return desc\n\t\treturn {\n\t\t\twritable: true,\n\t\t\tconfigurable: state.type_ !== ArchType.Array || prop !== \"length\",\n\t\t\tenumerable: desc.enumerable,\n\t\t\tvalue: owner[prop]\n\t\t}\n\t},\n\tdefineProperty() {\n\t\tdie(11)\n\t},\n\tgetPrototypeOf(state) {\n\t\treturn getPrototypeOf(state.base_)\n\t},\n\tsetPrototypeOf() {\n\t\tdie(12)\n\t}\n}\n\n/**\n * Array drafts\n */\n\nconst arrayTraps: ProxyHandler<[ProxyArrayState]> = {}\neach(objectTraps, (key, fn) => {\n\t// @ts-ignore\n\tarrayTraps[key] = function() {\n\t\targuments[0] = arguments[0][0]\n\t\treturn fn.apply(this, arguments)\n\t}\n})\narrayTraps.deleteProperty = function(state, prop) {\n\tif (process.env.NODE_ENV !== \"production\" && isNaN(parseInt(prop as any)))\n\t\tdie(13)\n\t// @ts-ignore\n\treturn arrayTraps.set!.call(this, state, prop, undefined)\n}\narrayTraps.set = function(state, prop, value) {\n\tif (\n\t\tprocess.env.NODE_ENV !== \"production\" &&\n\t\tprop !== \"length\" &&\n\t\tisNaN(parseInt(prop as any))\n\t)\n\t\tdie(14)\n\treturn objectTraps.set!.call(this, state[0], prop, value, state[0])\n}\n\n// Access a property without creating an Immer draft.\nfunction peek(draft: Drafted, prop: PropertyKey) {\n\tconst state = draft[DRAFT_STATE]\n\tconst source = state ? latest(state) : draft\n\treturn source[prop]\n}\n\nfunction readPropFromProto(state: ImmerState, source: any, prop: PropertyKey) {\n\tconst desc = getDescriptorFromProto(source, prop)\n\treturn desc\n\t\t? `value` in desc\n\t\t\t? desc.value\n\t\t\t: // This is a very special case, if the prop is a getter defined by the\n\t\t\t // prototype, we should invoke it with the draft as context!\n\t\t\t desc.get?.call(state.draft_)\n\t\t: undefined\n}\n\nfunction getDescriptorFromProto(\n\tsource: any,\n\tprop: PropertyKey\n): PropertyDescriptor | undefined {\n\t// 'in' checks proto!\n\tif (!(prop in source)) return undefined\n\tlet proto = getPrototypeOf(source)\n\twhile (proto) {\n\t\tconst desc = Object.getOwnPropertyDescriptor(proto, prop)\n\t\tif (desc) return desc\n\t\tproto = getPrototypeOf(proto)\n\t}\n\treturn undefined\n}\n\nexport function markChanged(state: ImmerState) {\n\tif (!state.modified_) {\n\t\tstate.modified_ = true\n\t\tif (state.parent_) {\n\t\t\tmarkChanged(state.parent_)\n\t\t}\n\t}\n}\n\nexport function prepareCopy(state: {\n\tbase_: any\n\tcopy_: any\n\tscope_: ImmerScope\n}) {\n\tif (!state.copy_) {\n\t\tstate.copy_ = shallowCopy(\n\t\t\tstate.base_,\n\t\t\tstate.scope_.immer_.useStrictShallowCopy_\n\t\t)\n\t}\n}\n", "import {\n\tIProduceWithPatches,\n\tIProduce,\n\tImmerState,\n\tDrafted,\n\tisDraftable,\n\tprocessResult,\n\tPatch,\n\tObjectish,\n\tDRAFT_STATE,\n\tDraft,\n\tPatchListener,\n\tisDraft,\n\tisMap,\n\tisSet,\n\tcreateProxyProxy,\n\tgetPlugin,\n\tdie,\n\tenterScope,\n\trevokeScope,\n\tleaveScope,\n\tusePatchesInScope,\n\tgetCurrentScope,\n\tNOTHING,\n\tfreeze,\n\tcurrent\n} from \"../internal\"\n\ninterface ProducersFns {\n\tproduce: IProduce\n\tproduceWithPatches: IProduceWithPatches\n}\n\nexport class Immer implements ProducersFns {\n\tautoFreeze_: boolean = true\n\tuseStrictShallowCopy_: boolean = false\n\n\tconstructor(config?: {autoFreeze?: boolean; useStrictShallowCopy?: boolean}) {\n\t\tif (typeof config?.autoFreeze === \"boolean\")\n\t\t\tthis.setAutoFreeze(config!.autoFreeze)\n\t\tif (typeof config?.useStrictShallowCopy === \"boolean\")\n\t\t\tthis.setUseStrictShallowCopy(config!.useStrictShallowCopy)\n\t}\n\n\t/**\n\t * The `produce` function takes a value and a \"recipe function\" (whose\n\t * return value often depends on the base state). The recipe function is\n\t * free to mutate its first argument however it wants. All mutations are\n\t * only ever applied to a __copy__ of the base state.\n\t *\n\t * Pass only a function to create a \"curried producer\" which relieves you\n\t * from passing the recipe function every time.\n\t *\n\t * Only plain objects and arrays are made mutable. All other objects are\n\t * considered uncopyable.\n\t *\n\t * Note: This function is __bound__ to its `Immer` instance.\n\t *\n\t * @param {any} base - the initial state\n\t * @param {Function} recipe - function that receives a proxy of the base state as first argument and which can be freely modified\n\t * @param {Function} patchListener - optional function that will be called with all the patches produced here\n\t * @returns {any} a new state, or the initial state if nothing was modified\n\t */\n\tproduce: IProduce = (base: any, recipe?: any, patchListener?: any) => {\n\t\t// curried invocation\n\t\tif (typeof base === \"function\" && typeof recipe !== \"function\") {\n\t\t\tconst defaultBase = recipe\n\t\t\trecipe = base\n\n\t\t\tconst self = this\n\t\t\treturn function curriedProduce(\n\t\t\t\tthis: any,\n\t\t\t\tbase = defaultBase,\n\t\t\t\t...args: any[]\n\t\t\t) {\n\t\t\t\treturn self.produce(base, (draft: Drafted) => recipe.call(this, draft, ...args)) // prettier-ignore\n\t\t\t}\n\t\t}\n\n\t\tif (typeof recipe !== \"function\") die(6)\n\t\tif (patchListener !== undefined && typeof patchListener !== \"function\")\n\t\t\tdie(7)\n\n\t\tlet result\n\n\t\t// Only plain objects, arrays, and \"immerable classes\" are drafted.\n\t\tif (isDraftable(base)) {\n\t\t\tconst scope = enterScope(this)\n\t\t\tconst proxy = createProxy(base, undefined)\n\t\t\tlet hasError = true\n\t\t\ttry {\n\t\t\t\tresult = recipe(proxy)\n\t\t\t\thasError = false\n\t\t\t} finally {\n\t\t\t\t// finally instead of catch + rethrow better preserves original stack\n\t\t\t\tif (hasError) revokeScope(scope)\n\t\t\t\telse leaveScope(scope)\n\t\t\t}\n\t\t\tusePatchesInScope(scope, patchListener)\n\t\t\treturn processResult(result, scope)\n\t\t} else if (!base || typeof base !== \"object\") {\n\t\t\tresult = recipe(base)\n\t\t\tif (result === undefined) result = base\n\t\t\tif (result === NOTHING) result = undefined\n\t\t\tif (this.autoFreeze_) freeze(result, true)\n\t\t\tif (patchListener) {\n\t\t\t\tconst p: Patch[] = []\n\t\t\t\tconst ip: Patch[] = []\n\t\t\t\tgetPlugin(\"Patches\").generateReplacementPatches_(base, result, p, ip)\n\t\t\t\tpatchListener(p, ip)\n\t\t\t}\n\t\t\treturn result\n\t\t} else die(1, base)\n\t}\n\n\tproduceWithPatches: IProduceWithPatches = (base: any, recipe?: any): any => {\n\t\t// curried invocation\n\t\tif (typeof base === \"function\") {\n\t\t\treturn (state: any, ...args: any[]) =>\n\t\t\t\tthis.produceWithPatches(state, (draft: any) => base(draft, ...args))\n\t\t}\n\n\t\tlet patches: Patch[], inversePatches: Patch[]\n\t\tconst result = this.produce(base, recipe, (p: Patch[], ip: Patch[]) => {\n\t\t\tpatches = p\n\t\t\tinversePatches = ip\n\t\t})\n\t\treturn [result, patches!, inversePatches!]\n\t}\n\n\tcreateDraft(base: T): Draft {\n\t\tif (!isDraftable(base)) die(8)\n\t\tif (isDraft(base)) base = current(base)\n\t\tconst scope = enterScope(this)\n\t\tconst proxy = createProxy(base, undefined)\n\t\tproxy[DRAFT_STATE].isManual_ = true\n\t\tleaveScope(scope)\n\t\treturn proxy as any\n\t}\n\n\tfinishDraft>(\n\t\tdraft: D,\n\t\tpatchListener?: PatchListener\n\t): D extends Draft ? T : never {\n\t\tconst state: ImmerState = draft && (draft as any)[DRAFT_STATE]\n\t\tif (!state || !state.isManual_) die(9)\n\t\tconst {scope_: scope} = state\n\t\tusePatchesInScope(scope, patchListener)\n\t\treturn processResult(undefined, scope)\n\t}\n\n\t/**\n\t * Pass true to automatically freeze all copies created by Immer.\n\t *\n\t * By default, auto-freezing is enabled.\n\t */\n\tsetAutoFreeze(value: boolean) {\n\t\tthis.autoFreeze_ = value\n\t}\n\n\t/**\n\t * Pass true to enable strict shallow copy.\n\t *\n\t * By default, immer does not copy the object descriptors such as getter, setter and non-enumrable properties.\n\t */\n\tsetUseStrictShallowCopy(value: boolean) {\n\t\tthis.useStrictShallowCopy_ = value\n\t}\n\n\tapplyPatches(base: T, patches: Patch[]): T {\n\t\t// If a patch replaces the entire state, take that replacement as base\n\t\t// before applying patches\n\t\tlet i: number\n\t\tfor (i = patches.length - 1; i >= 0; i--) {\n\t\t\tconst patch = patches[i]\n\t\t\tif (patch.path.length === 0 && patch.op === \"replace\") {\n\t\t\t\tbase = patch.value\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\t// If there was a patch that replaced the entire state, start from the\n\t\t// patch after that.\n\t\tif (i > -1) {\n\t\t\tpatches = patches.slice(i + 1)\n\t\t}\n\n\t\tconst applyPatchesImpl = getPlugin(\"Patches\").applyPatches_\n\t\tif (isDraft(base)) {\n\t\t\t// N.B: never hits if some patch a replacement, patches are never drafts\n\t\t\treturn applyPatchesImpl(base, patches)\n\t\t}\n\t\t// Otherwise, produce a copy of the base state.\n\t\treturn this.produce(base, (draft: Drafted) =>\n\t\t\tapplyPatchesImpl(draft, patches)\n\t\t)\n\t}\n}\n\nexport function createProxy(\n\tvalue: T,\n\tparent?: ImmerState\n): Drafted {\n\t// precondition: createProxy should be guarded by isDraftable, so we know we can safely draft\n\tconst draft: Drafted = isMap(value)\n\t\t? getPlugin(\"MapSet\").proxyMap_(value, parent)\n\t\t: isSet(value)\n\t\t? getPlugin(\"MapSet\").proxySet_(value, parent)\n\t\t: createProxyProxy(value, parent)\n\n\tconst scope = parent ? parent.scope_ : getCurrentScope()\n\tscope.drafts_.push(draft)\n\treturn draft\n}\n", "import {\n\tdie,\n\tisDraft,\n\tshallowCopy,\n\teach,\n\tDRAFT_STATE,\n\tset,\n\tImmerState,\n\tisDraftable,\n\tisFrozen\n} from \"../internal\"\n\n/** Takes a snapshot of the current state of a draft and finalizes it (but without freezing). This is a great utility to print the current state during debugging (no Proxies in the way). The output of current can also be safely leaked outside the producer. */\nexport function current(value: T): T\nexport function current(value: any): any {\n\tif (!isDraft(value)) die(10, value)\n\treturn currentImpl(value)\n}\n\nfunction currentImpl(value: any): any {\n\tif (!isDraftable(value) || isFrozen(value)) return value\n\tconst state: ImmerState | undefined = value[DRAFT_STATE]\n\tlet copy: any\n\tif (state) {\n\t\tif (!state.modified_) return state.base_\n\t\t// Optimization: avoid generating new drafts during copying\n\t\tstate.finalized_ = true\n\t\tcopy = shallowCopy(value, state.scope_.immer_.useStrictShallowCopy_)\n\t} else {\n\t\tcopy = shallowCopy(value, true)\n\t}\n\t// recurse\n\teach(copy, (key, childValue) => {\n\t\tset(copy, key, currentImpl(childValue))\n\t})\n\tif (state) {\n\t\tstate.finalized_ = false\n\t}\n\treturn copy\n}\n", "import {immerable} from \"../immer\"\nimport {\n\tImmerState,\n\tPatch,\n\tSetState,\n\tProxyArrayState,\n\tMapState,\n\tProxyObjectState,\n\tPatchPath,\n\tget,\n\teach,\n\thas,\n\tgetArchtype,\n\tgetPrototypeOf,\n\tisSet,\n\tisMap,\n\tloadPlugin,\n\tArchType,\n\tdie,\n\tisDraft,\n\tisDraftable,\n\tNOTHING,\n\terrors\n} from \"../internal\"\n\nexport function enablePatches() {\n\tconst errorOffset = 16\n\tif (process.env.NODE_ENV !== \"production\") {\n\t\terrors.push(\n\t\t\t'Sets cannot have \"replace\" patches.',\n\t\t\tfunction(op: string) {\n\t\t\t\treturn \"Unsupported patch operation: \" + op\n\t\t\t},\n\t\t\tfunction(path: string) {\n\t\t\t\treturn \"Cannot apply patch, path doesn't resolve: \" + path\n\t\t\t},\n\t\t\t\"Patching reserved attributes like __proto__, prototype and constructor is not allowed\"\n\t\t)\n\t}\n\n\tconst REPLACE = \"replace\"\n\tconst ADD = \"add\"\n\tconst REMOVE = \"remove\"\n\n\tfunction generatePatches_(\n\t\tstate: ImmerState,\n\t\tbasePath: PatchPath,\n\t\tpatches: Patch[],\n\t\tinversePatches: Patch[]\n\t): void {\n\t\tswitch (state.type_) {\n\t\t\tcase ArchType.Object:\n\t\t\tcase ArchType.Map:\n\t\t\t\treturn generatePatchesFromAssigned(\n\t\t\t\t\tstate,\n\t\t\t\t\tbasePath,\n\t\t\t\t\tpatches,\n\t\t\t\t\tinversePatches\n\t\t\t\t)\n\t\t\tcase ArchType.Array:\n\t\t\t\treturn generateArrayPatches(state, basePath, patches, inversePatches)\n\t\t\tcase ArchType.Set:\n\t\t\t\treturn generateSetPatches(\n\t\t\t\t\t(state as any) as SetState,\n\t\t\t\t\tbasePath,\n\t\t\t\t\tpatches,\n\t\t\t\t\tinversePatches\n\t\t\t\t)\n\t\t}\n\t}\n\n\tfunction generateArrayPatches(\n\t\tstate: ProxyArrayState,\n\t\tbasePath: PatchPath,\n\t\tpatches: Patch[],\n\t\tinversePatches: Patch[]\n\t) {\n\t\tlet {base_, assigned_} = state\n\t\tlet copy_ = state.copy_!\n\n\t\t// Reduce complexity by ensuring `base` is never longer.\n\t\tif (copy_.length < base_.length) {\n\t\t\t// @ts-ignore\n\t\t\t;[base_, copy_] = [copy_, base_]\n\t\t\t;[patches, inversePatches] = [inversePatches, patches]\n\t\t}\n\n\t\t// Process replaced indices.\n\t\tfor (let i = 0; i < base_.length; i++) {\n\t\t\tif (assigned_[i] && copy_[i] !== base_[i]) {\n\t\t\t\tconst path = basePath.concat([i])\n\t\t\t\tpatches.push({\n\t\t\t\t\top: REPLACE,\n\t\t\t\t\tpath,\n\t\t\t\t\t// Need to maybe clone it, as it can in fact be the original value\n\t\t\t\t\t// due to the base/copy inversion at the start of this function\n\t\t\t\t\tvalue: clonePatchValueIfNeeded(copy_[i])\n\t\t\t\t})\n\t\t\t\tinversePatches.push({\n\t\t\t\t\top: REPLACE,\n\t\t\t\t\tpath,\n\t\t\t\t\tvalue: clonePatchValueIfNeeded(base_[i])\n\t\t\t\t})\n\t\t\t}\n\t\t}\n\n\t\t// Process added indices.\n\t\tfor (let i = base_.length; i < copy_.length; i++) {\n\t\t\tconst path = basePath.concat([i])\n\t\t\tpatches.push({\n\t\t\t\top: ADD,\n\t\t\t\tpath,\n\t\t\t\t// Need to maybe clone it, as it can in fact be the original value\n\t\t\t\t// due to the base/copy inversion at the start of this function\n\t\t\t\tvalue: clonePatchValueIfNeeded(copy_[i])\n\t\t\t})\n\t\t}\n\t\tfor (let i = copy_.length - 1; base_.length <= i; --i) {\n\t\t\tconst path = basePath.concat([i])\n\t\t\tinversePatches.push({\n\t\t\t\top: REMOVE,\n\t\t\t\tpath\n\t\t\t})\n\t\t}\n\t}\n\n\t// This is used for both Map objects and normal objects.\n\tfunction generatePatchesFromAssigned(\n\t\tstate: MapState | ProxyObjectState,\n\t\tbasePath: PatchPath,\n\t\tpatches: Patch[],\n\t\tinversePatches: Patch[]\n\t) {\n\t\tconst {base_, copy_} = state\n\t\teach(state.assigned_!, (key, assignedValue) => {\n\t\t\tconst origValue = get(base_, key)\n\t\t\tconst value = get(copy_!, key)\n\t\t\tconst op = !assignedValue ? REMOVE : has(base_, key) ? REPLACE : ADD\n\t\t\tif (origValue === value && op === REPLACE) return\n\t\t\tconst path = basePath.concat(key as any)\n\t\t\tpatches.push(op === REMOVE ? {op, path} : {op, path, value})\n\t\t\tinversePatches.push(\n\t\t\t\top === ADD\n\t\t\t\t\t? {op: REMOVE, path}\n\t\t\t\t\t: op === REMOVE\n\t\t\t\t\t? {op: ADD, path, value: clonePatchValueIfNeeded(origValue)}\n\t\t\t\t\t: {op: REPLACE, path, value: clonePatchValueIfNeeded(origValue)}\n\t\t\t)\n\t\t})\n\t}\n\n\tfunction generateSetPatches(\n\t\tstate: SetState,\n\t\tbasePath: PatchPath,\n\t\tpatches: Patch[],\n\t\tinversePatches: Patch[]\n\t) {\n\t\tlet {base_, copy_} = state\n\n\t\tlet i = 0\n\t\tbase_.forEach((value: any) => {\n\t\t\tif (!copy_!.has(value)) {\n\t\t\t\tconst path = basePath.concat([i])\n\t\t\t\tpatches.push({\n\t\t\t\t\top: REMOVE,\n\t\t\t\t\tpath,\n\t\t\t\t\tvalue\n\t\t\t\t})\n\t\t\t\tinversePatches.unshift({\n\t\t\t\t\top: ADD,\n\t\t\t\t\tpath,\n\t\t\t\t\tvalue\n\t\t\t\t})\n\t\t\t}\n\t\t\ti++\n\t\t})\n\t\ti = 0\n\t\tcopy_!.forEach((value: any) => {\n\t\t\tif (!base_.has(value)) {\n\t\t\t\tconst path = basePath.concat([i])\n\t\t\t\tpatches.push({\n\t\t\t\t\top: ADD,\n\t\t\t\t\tpath,\n\t\t\t\t\tvalue\n\t\t\t\t})\n\t\t\t\tinversePatches.unshift({\n\t\t\t\t\top: REMOVE,\n\t\t\t\t\tpath,\n\t\t\t\t\tvalue\n\t\t\t\t})\n\t\t\t}\n\t\t\ti++\n\t\t})\n\t}\n\n\tfunction generateReplacementPatches_(\n\t\tbaseValue: any,\n\t\treplacement: any,\n\t\tpatches: Patch[],\n\t\tinversePatches: Patch[]\n\t): void {\n\t\tpatches.push({\n\t\t\top: REPLACE,\n\t\t\tpath: [],\n\t\t\tvalue: replacement === NOTHING ? undefined : replacement\n\t\t})\n\t\tinversePatches.push({\n\t\t\top: REPLACE,\n\t\t\tpath: [],\n\t\t\tvalue: baseValue\n\t\t})\n\t}\n\n\tfunction applyPatches_(draft: T, patches: Patch[]): T {\n\t\tpatches.forEach(patch => {\n\t\t\tconst {path, op} = patch\n\n\t\t\tlet base: any = draft\n\t\t\tfor (let i = 0; i < path.length - 1; i++) {\n\t\t\t\tconst parentType = getArchtype(base)\n\t\t\t\tlet p = path[i]\n\t\t\t\tif (typeof p !== \"string\" && typeof p !== \"number\") {\n\t\t\t\t\tp = \"\" + p\n\t\t\t\t}\n\n\t\t\t\t// See #738, avoid prototype pollution\n\t\t\t\tif (\n\t\t\t\t\t(parentType === ArchType.Object || parentType === ArchType.Array) &&\n\t\t\t\t\t(p === \"__proto__\" || p === \"constructor\")\n\t\t\t\t)\n\t\t\t\t\tdie(errorOffset + 3)\n\t\t\t\tif (typeof base === \"function\" && p === \"prototype\")\n\t\t\t\t\tdie(errorOffset + 3)\n\t\t\t\tbase = get(base, p)\n\t\t\t\tif (typeof base !== \"object\") die(errorOffset + 2, path.join(\"/\"))\n\t\t\t}\n\n\t\t\tconst type = getArchtype(base)\n\t\t\tconst value = deepClonePatchValue(patch.value) // used to clone patch to ensure original patch is not modified, see #411\n\t\t\tconst key = path[path.length - 1]\n\t\t\tswitch (op) {\n\t\t\t\tcase REPLACE:\n\t\t\t\t\tswitch (type) {\n\t\t\t\t\t\tcase ArchType.Map:\n\t\t\t\t\t\t\treturn base.set(key, value)\n\t\t\t\t\t\t/* istanbul ignore next */\n\t\t\t\t\t\tcase ArchType.Set:\n\t\t\t\t\t\t\tdie(errorOffset)\n\t\t\t\t\t\tdefault:\n\t\t\t\t\t\t\t// if value is an object, then it's assigned by reference\n\t\t\t\t\t\t\t// in the following add or remove ops, the value field inside the patch will also be modifyed\n\t\t\t\t\t\t\t// so we use value from the cloned patch\n\t\t\t\t\t\t\t// @ts-ignore\n\t\t\t\t\t\t\treturn (base[key] = value)\n\t\t\t\t\t}\n\t\t\t\tcase ADD:\n\t\t\t\t\tswitch (type) {\n\t\t\t\t\t\tcase ArchType.Array:\n\t\t\t\t\t\t\treturn key === \"-\"\n\t\t\t\t\t\t\t\t? base.push(value)\n\t\t\t\t\t\t\t\t: base.splice(key as any, 0, value)\n\t\t\t\t\t\tcase ArchType.Map:\n\t\t\t\t\t\t\treturn base.set(key, value)\n\t\t\t\t\t\tcase ArchType.Set:\n\t\t\t\t\t\t\treturn base.add(value)\n\t\t\t\t\t\tdefault:\n\t\t\t\t\t\t\treturn (base[key] = value)\n\t\t\t\t\t}\n\t\t\t\tcase REMOVE:\n\t\t\t\t\tswitch (type) {\n\t\t\t\t\t\tcase ArchType.Array:\n\t\t\t\t\t\t\treturn base.splice(key as any, 1)\n\t\t\t\t\t\tcase ArchType.Map:\n\t\t\t\t\t\t\treturn base.delete(key)\n\t\t\t\t\t\tcase ArchType.Set:\n\t\t\t\t\t\t\treturn base.delete(patch.value)\n\t\t\t\t\t\tdefault:\n\t\t\t\t\t\t\treturn delete base[key]\n\t\t\t\t\t}\n\t\t\t\tdefault:\n\t\t\t\t\tdie(errorOffset + 1, op)\n\t\t\t}\n\t\t})\n\n\t\treturn draft\n\t}\n\n\t// optimize: this is quite a performance hit, can we detect intelligently when it is needed?\n\t// E.g. auto-draft when new objects from outside are assigned and modified?\n\t// (See failing test when deepClone just returns obj)\n\tfunction deepClonePatchValue(obj: T): T\n\tfunction deepClonePatchValue(obj: any) {\n\t\tif (!isDraftable(obj)) return obj\n\t\tif (Array.isArray(obj)) return obj.map(deepClonePatchValue)\n\t\tif (isMap(obj))\n\t\t\treturn new Map(\n\t\t\t\tArray.from(obj.entries()).map(([k, v]) => [k, deepClonePatchValue(v)])\n\t\t\t)\n\t\tif (isSet(obj)) return new Set(Array.from(obj).map(deepClonePatchValue))\n\t\tconst cloned = Object.create(getPrototypeOf(obj))\n\t\tfor (const key in obj) cloned[key] = deepClonePatchValue(obj[key])\n\t\tif (has(obj, immerable)) cloned[immerable] = obj[immerable]\n\t\treturn cloned\n\t}\n\n\tfunction clonePatchValueIfNeeded(obj: T): T {\n\t\tif (isDraft(obj)) {\n\t\t\treturn deepClonePatchValue(obj)\n\t\t} else return obj\n\t}\n\n\tloadPlugin(\"Patches\", {\n\t\tapplyPatches_,\n\t\tgeneratePatches_,\n\t\tgenerateReplacementPatches_\n\t})\n}\n", "// types only!\nimport {\n\tImmerState,\n\tAnyMap,\n\tAnySet,\n\tMapState,\n\tSetState,\n\tDRAFT_STATE,\n\tgetCurrentScope,\n\tlatest,\n\tisDraftable,\n\tcreateProxy,\n\tloadPlugin,\n\tmarkChanged,\n\tdie,\n\tArchType,\n\teach\n} from \"../internal\"\n\nexport function enableMapSet() {\n\tclass DraftMap extends Map {\n\t\t[DRAFT_STATE]: MapState\n\n\t\tconstructor(target: AnyMap, parent?: ImmerState) {\n\t\t\tsuper()\n\t\t\tthis[DRAFT_STATE] = {\n\t\t\t\ttype_: ArchType.Map,\n\t\t\t\tparent_: parent,\n\t\t\t\tscope_: parent ? parent.scope_ : getCurrentScope()!,\n\t\t\t\tmodified_: false,\n\t\t\t\tfinalized_: false,\n\t\t\t\tcopy_: undefined,\n\t\t\t\tassigned_: undefined,\n\t\t\t\tbase_: target,\n\t\t\t\tdraft_: this as any,\n\t\t\t\tisManual_: false,\n\t\t\t\trevoked_: false\n\t\t\t}\n\t\t}\n\n\t\tget size(): number {\n\t\t\treturn latest(this[DRAFT_STATE]).size\n\t\t}\n\n\t\thas(key: any): boolean {\n\t\t\treturn latest(this[DRAFT_STATE]).has(key)\n\t\t}\n\n\t\tset(key: any, value: any) {\n\t\t\tconst state: MapState = this[DRAFT_STATE]\n\t\t\tassertUnrevoked(state)\n\t\t\tif (!latest(state).has(key) || latest(state).get(key) !== value) {\n\t\t\t\tprepareMapCopy(state)\n\t\t\t\tmarkChanged(state)\n\t\t\t\tstate.assigned_!.set(key, true)\n\t\t\t\tstate.copy_!.set(key, value)\n\t\t\t\tstate.assigned_!.set(key, true)\n\t\t\t}\n\t\t\treturn this\n\t\t}\n\n\t\tdelete(key: any): boolean {\n\t\t\tif (!this.has(key)) {\n\t\t\t\treturn false\n\t\t\t}\n\n\t\t\tconst state: MapState = this[DRAFT_STATE]\n\t\t\tassertUnrevoked(state)\n\t\t\tprepareMapCopy(state)\n\t\t\tmarkChanged(state)\n\t\t\tif (state.base_.has(key)) {\n\t\t\t\tstate.assigned_!.set(key, false)\n\t\t\t} else {\n\t\t\t\tstate.assigned_!.delete(key)\n\t\t\t}\n\t\t\tstate.copy_!.delete(key)\n\t\t\treturn true\n\t\t}\n\n\t\tclear() {\n\t\t\tconst state: MapState = this[DRAFT_STATE]\n\t\t\tassertUnrevoked(state)\n\t\t\tif (latest(state).size) {\n\t\t\t\tprepareMapCopy(state)\n\t\t\t\tmarkChanged(state)\n\t\t\t\tstate.assigned_ = new Map()\n\t\t\t\teach(state.base_, key => {\n\t\t\t\t\tstate.assigned_!.set(key, false)\n\t\t\t\t})\n\t\t\t\tstate.copy_!.clear()\n\t\t\t}\n\t\t}\n\n\t\tforEach(cb: (value: any, key: any, self: any) => void, thisArg?: any) {\n\t\t\tconst state: MapState = this[DRAFT_STATE]\n\t\t\tlatest(state).forEach((_value: any, key: any, _map: any) => {\n\t\t\t\tcb.call(thisArg, this.get(key), key, this)\n\t\t\t})\n\t\t}\n\n\t\tget(key: any): any {\n\t\t\tconst state: MapState = this[DRAFT_STATE]\n\t\t\tassertUnrevoked(state)\n\t\t\tconst value = latest(state).get(key)\n\t\t\tif (state.finalized_ || !isDraftable(value)) {\n\t\t\t\treturn value\n\t\t\t}\n\t\t\tif (value !== state.base_.get(key)) {\n\t\t\t\treturn value // either already drafted or reassigned\n\t\t\t}\n\t\t\t// despite what it looks, this creates a draft only once, see above condition\n\t\t\tconst draft = createProxy(value, state)\n\t\t\tprepareMapCopy(state)\n\t\t\tstate.copy_!.set(key, draft)\n\t\t\treturn draft\n\t\t}\n\n\t\tkeys(): IterableIterator {\n\t\t\treturn latest(this[DRAFT_STATE]).keys()\n\t\t}\n\n\t\tvalues(): IterableIterator {\n\t\t\tconst iterator = this.keys()\n\t\t\treturn {\n\t\t\t\t[Symbol.iterator]: () => this.values(),\n\t\t\t\tnext: () => {\n\t\t\t\t\tconst r = iterator.next()\n\t\t\t\t\t/* istanbul ignore next */\n\t\t\t\t\tif (r.done) return r\n\t\t\t\t\tconst value = this.get(r.value)\n\t\t\t\t\treturn {\n\t\t\t\t\t\tdone: false,\n\t\t\t\t\t\tvalue\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} as any\n\t\t}\n\n\t\tentries(): IterableIterator<[any, any]> {\n\t\t\tconst iterator = this.keys()\n\t\t\treturn {\n\t\t\t\t[Symbol.iterator]: () => this.entries(),\n\t\t\t\tnext: () => {\n\t\t\t\t\tconst r = iterator.next()\n\t\t\t\t\t/* istanbul ignore next */\n\t\t\t\t\tif (r.done) return r\n\t\t\t\t\tconst value = this.get(r.value)\n\t\t\t\t\treturn {\n\t\t\t\t\t\tdone: false,\n\t\t\t\t\t\tvalue: [r.value, value]\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} as any\n\t\t}\n\n\t\t[Symbol.iterator]() {\n\t\t\treturn this.entries()\n\t\t}\n\t}\n\n\tfunction proxyMap_(target: T, parent?: ImmerState): T {\n\t\t// @ts-ignore\n\t\treturn new DraftMap(target, parent)\n\t}\n\n\tfunction prepareMapCopy(state: MapState) {\n\t\tif (!state.copy_) {\n\t\t\tstate.assigned_ = new Map()\n\t\t\tstate.copy_ = new Map(state.base_)\n\t\t}\n\t}\n\n\tclass DraftSet extends Set {\n\t\t[DRAFT_STATE]: SetState\n\t\tconstructor(target: AnySet, parent?: ImmerState) {\n\t\t\tsuper()\n\t\t\tthis[DRAFT_STATE] = {\n\t\t\t\ttype_: ArchType.Set,\n\t\t\t\tparent_: parent,\n\t\t\t\tscope_: parent ? parent.scope_ : getCurrentScope()!,\n\t\t\t\tmodified_: false,\n\t\t\t\tfinalized_: false,\n\t\t\t\tcopy_: undefined,\n\t\t\t\tbase_: target,\n\t\t\t\tdraft_: this,\n\t\t\t\tdrafts_: new Map(),\n\t\t\t\trevoked_: false,\n\t\t\t\tisManual_: false\n\t\t\t}\n\t\t}\n\n\t\tget size(): number {\n\t\t\treturn latest(this[DRAFT_STATE]).size\n\t\t}\n\n\t\thas(value: any): boolean {\n\t\t\tconst state: SetState = this[DRAFT_STATE]\n\t\t\tassertUnrevoked(state)\n\t\t\t// bit of trickery here, to be able to recognize both the value, and the draft of its value\n\t\t\tif (!state.copy_) {\n\t\t\t\treturn state.base_.has(value)\n\t\t\t}\n\t\t\tif (state.copy_.has(value)) return true\n\t\t\tif (state.drafts_.has(value) && state.copy_.has(state.drafts_.get(value)))\n\t\t\t\treturn true\n\t\t\treturn false\n\t\t}\n\n\t\tadd(value: any): any {\n\t\t\tconst state: SetState = this[DRAFT_STATE]\n\t\t\tassertUnrevoked(state)\n\t\t\tif (!this.has(value)) {\n\t\t\t\tprepareSetCopy(state)\n\t\t\t\tmarkChanged(state)\n\t\t\t\tstate.copy_!.add(value)\n\t\t\t}\n\t\t\treturn this\n\t\t}\n\n\t\tdelete(value: any): any {\n\t\t\tif (!this.has(value)) {\n\t\t\t\treturn false\n\t\t\t}\n\n\t\t\tconst state: SetState = this[DRAFT_STATE]\n\t\t\tassertUnrevoked(state)\n\t\t\tprepareSetCopy(state)\n\t\t\tmarkChanged(state)\n\t\t\treturn (\n\t\t\t\tstate.copy_!.delete(value) ||\n\t\t\t\t(state.drafts_.has(value)\n\t\t\t\t\t? state.copy_!.delete(state.drafts_.get(value))\n\t\t\t\t\t: /* istanbul ignore next */ false)\n\t\t\t)\n\t\t}\n\n\t\tclear() {\n\t\t\tconst state: SetState = this[DRAFT_STATE]\n\t\t\tassertUnrevoked(state)\n\t\t\tif (latest(state).size) {\n\t\t\t\tprepareSetCopy(state)\n\t\t\t\tmarkChanged(state)\n\t\t\t\tstate.copy_!.clear()\n\t\t\t}\n\t\t}\n\n\t\tvalues(): IterableIterator {\n\t\t\tconst state: SetState = this[DRAFT_STATE]\n\t\t\tassertUnrevoked(state)\n\t\t\tprepareSetCopy(state)\n\t\t\treturn state.copy_!.values()\n\t\t}\n\n\t\tentries(): IterableIterator<[any, any]> {\n\t\t\tconst state: SetState = this[DRAFT_STATE]\n\t\t\tassertUnrevoked(state)\n\t\t\tprepareSetCopy(state)\n\t\t\treturn state.copy_!.entries()\n\t\t}\n\n\t\tkeys(): IterableIterator {\n\t\t\treturn this.values()\n\t\t}\n\n\t\t[Symbol.iterator]() {\n\t\t\treturn this.values()\n\t\t}\n\n\t\tforEach(cb: any, thisArg?: any) {\n\t\t\tconst iterator = this.values()\n\t\t\tlet result = iterator.next()\n\t\t\twhile (!result.done) {\n\t\t\t\tcb.call(thisArg, result.value, result.value, this)\n\t\t\t\tresult = iterator.next()\n\t\t\t}\n\t\t}\n\t}\n\tfunction proxySet_(target: T, parent?: ImmerState): T {\n\t\t// @ts-ignore\n\t\treturn new DraftSet(target, parent)\n\t}\n\n\tfunction prepareSetCopy(state: SetState) {\n\t\tif (!state.copy_) {\n\t\t\t// create drafts for all entries to preserve insertion order\n\t\t\tstate.copy_ = new Set()\n\t\t\tstate.base_.forEach(value => {\n\t\t\t\tif (isDraftable(value)) {\n\t\t\t\t\tconst draft = createProxy(value, state)\n\t\t\t\t\tstate.drafts_.set(value, draft)\n\t\t\t\t\tstate.copy_!.add(draft)\n\t\t\t\t} else {\n\t\t\t\t\tstate.copy_!.add(value)\n\t\t\t\t}\n\t\t\t})\n\t\t}\n\t}\n\n\tfunction assertUnrevoked(state: any /*ES5State | MapState | SetState*/) {\n\t\tif (state.revoked_) die(3, JSON.stringify(latest(state)))\n\t}\n\n\tloadPlugin(\"MapSet\", {proxyMap_, proxySet_})\n}\n", "import {\n\tIProduce,\n\tIProduceWithPatches,\n\tImmer,\n\tDraft,\n\tImmutable\n} from \"./internal\"\n\nexport {\n\tDraft,\n\tImmutable,\n\tPatch,\n\tPatchListener,\n\toriginal,\n\tcurrent,\n\tisDraft,\n\tisDraftable,\n\tNOTHING as nothing,\n\tDRAFTABLE as immerable,\n\tfreeze,\n\tObjectish\n} from \"./internal\"\n\nconst immer = new Immer()\n\n/**\n * The `produce` function takes a value and a \"recipe function\" (whose\n * return value often depends on the base state). The recipe function is\n * free to mutate its first argument however it wants. All mutations are\n * only ever applied to a __copy__ of the base state.\n *\n * Pass only a function to create a \"curried producer\" which relieves you\n * from passing the recipe function every time.\n *\n * Only plain objects and arrays are made mutable. All other objects are\n * considered uncopyable.\n *\n * Note: This function is __bound__ to its `Immer` instance.\n *\n * @param {any} base - the initial state\n * @param {Function} producer - function that receives a proxy of the base state as first argument and which can be freely modified\n * @param {Function} patchListener - optional function that will be called with all the patches produced here\n * @returns {any} a new state, or the initial state if nothing was modified\n */\nexport const produce: IProduce = immer.produce\n\n/**\n * Like `produce`, but `produceWithPatches` always returns a tuple\n * [nextState, patches, inversePatches] (instead of just the next state)\n */\nexport const produceWithPatches: IProduceWithPatches = immer.produceWithPatches.bind(\n\timmer\n)\n\n/**\n * Pass true to automatically freeze all copies created by Immer.\n *\n * Always freeze by default, even in production mode\n */\nexport const setAutoFreeze = immer.setAutoFreeze.bind(immer)\n\n/**\n * Pass true to enable strict shallow copy.\n *\n * By default, immer does not copy the object descriptors such as getter, setter and non-enumrable properties.\n */\nexport const setUseStrictShallowCopy = immer.setUseStrictShallowCopy.bind(immer)\n\n/**\n * Apply an array of Immer patches to the first argument.\n *\n * This function is a producer, which means copy-on-write is in effect.\n */\nexport const applyPatches = immer.applyPatches.bind(immer)\n\n/**\n * Create an Immer draft from the given base state, which may be a draft itself.\n * The draft can be modified until you finalize it with the `finishDraft` function.\n */\nexport const createDraft = immer.createDraft.bind(immer)\n\n/**\n * Finalize an Immer draft from a `createDraft` call, returning the base state\n * (if no changes were made) or a modified copy. The draft must *not* be\n * mutated afterwards.\n *\n * Pass a function as the 2nd argument to generate Immer patches based on the\n * changes that were made.\n */\nexport const finishDraft = immer.finishDraft.bind(immer)\n\n/**\n * This function is actually a no-op, but can be used to cast an immutable type\n * to an draft type and make TypeScript happy\n *\n * @param value\n */\nexport function castDraft(value: T): Draft {\n\treturn value as any\n}\n\n/**\n * This function is actually a no-op, but can be used to cast a mutable type\n * to an immutable type and make TypeScript happy\n * @param value\n */\nexport function castImmutable(value: T): Immutable {\n\treturn value as any\n}\n\nexport {Immer}\n\nexport {enablePatches} from \"./plugins/patches\"\nexport {enableMapSet} from \"./plugins/mapset\"\n", "import { produce, Draft, nothing, freeze } from \"immer\";\nimport { useState, useReducer, useCallback, useMemo, Dispatch } from \"react\";\n\nexport type DraftFunction = (draft: Draft) => void;\nexport type Updater = (arg: S | DraftFunction) => void;\nexport type ImmerHook = [S, Updater];\n\nexport function useImmer(initialValue: S | (() => S)): ImmerHook;\n\nexport function useImmer(initialValue: any) {\n const [val, updateValue] = useState(() =>\n freeze(\n typeof initialValue === \"function\" ? initialValue() : initialValue,\n true\n )\n );\n return [\n val,\n useCallback((updater) => {\n if (typeof updater === \"function\") updateValue(produce(updater));\n else updateValue(freeze(updater));\n }, []),\n ];\n}\n\n// Provides different overloads of `useImmerReducer` similar to `useReducer` from `@types/react`.\n\nexport type ImmerReducer = (\n draftState: Draft,\n action: A\n) => void | (S extends undefined ? typeof nothing : S);\n\n/**\n * @deprecated Use `ImmerReducer` instead since there is already a `Reducer` type in `@types/react`.\n */\nexport type Reducer = ImmerReducer;\n\nexport function useImmerReducer(\n reducer: ImmerReducer,\n initializerArg: S & I,\n initializer: (arg: S & I) => S\n): [S, Dispatch];\n\nexport function useImmerReducer(\n reducer: ImmerReducer,\n initializerArg: I,\n initializer: (arg: I) => S\n): [S, Dispatch];\n\nexport function useImmerReducer(\n reducer: ImmerReducer,\n initialState: S,\n initializer?: undefined\n): [S, Dispatch];\n\nexport function useImmerReducer(\n reducer: ImmerReducer,\n initializerArg: S & I,\n initializer?: (arg: S & I) => S\n) {\n const cachedReducer = useMemo(() => produce(reducer), [reducer]);\n return useReducer(cachedReducer, initializerArg as any, initializer as any);\n}\n", "// type JobId = string;\n// type UploadUrl = string;\n// type UploadInitValue = { jobId: JobId; uploadUrl: UploadUrl };\n// type UploadEndValue = never;\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport type ResponseValue = any;\n\nexport type OnSuccessRequest = (value: ResponseValue) => void;\nexport type OnErrorRequest = (err: string) => void;\n\n// Websocket messages are normally one-way--i.e. the client passes a\n// message to the server but there is no way for the server to provide\n// a response to that specific message. makeRequest provides a way to\n// do asynchronous RPC over websocket. Each request has a method name\n// and arguments, plus optionally one or more binary blobs can be\n// included as well. The request is tagged with a unique number that\n// the server will use to label the corresponding response.\n//\n// @param method A string that tells the server what logic to run.\n// @param args An array of objects that should also be passed to the\n// server in JSON-ified form.\n// @param onSuccess A function that will be called back if the server\n// responds with success. If the server provides a value in the\n// response, the function will be called with it as the only argument.\n// @param onError A function that will be called back if the server\n// responds with error, or if the request fails for any other reason.\n// The parameter to onError will be a string describing the error.\n// @param blobs Optionally, an array of Blob, ArrayBuffer, or string\n// objects that will be made available to the server as part of the\n// request. Strings will be encoded using UTF-8.\nexport function makeRequest(\n method: string,\n args: unknown[],\n onSuccess: OnSuccessRequest,\n onError: OnErrorRequest,\n blobs: Array | undefined\n) {\n window.Shiny.shinyapp!.makeRequest(method, args, onSuccess, onError, blobs);\n}\n\nexport function makeRequestPromise({\n method,\n args,\n blobs,\n}: {\n method: string;\n args: unknown[];\n blobs?: Array | undefined;\n}) {\n return new Promise((resolve, reject) => {\n makeRequest(\n method,\n args,\n (value: ResponseValue) => {\n resolve(value);\n },\n (err: string) => {\n reject(err);\n },\n blobs\n );\n });\n}\n", "import { ResponseValue, makeRequestPromise } from \"./request\";\n\nimport { CellStateEnum } from \"./cell\";\nimport { SetCellEditMapAtLoc } from \"./cell-edit-map\";\nimport type { PatchInfo } from \"./types\";\n\nexport type CellPatch = {\n rowIndex: number;\n columnIndex: number;\n value: any; // eslint-disable-line @typescript-eslint/no-explicit-any\n // prev: unknown;\n};\nexport type CellPatchPy = {\n row_index: number;\n column_index: number;\n value: unknown;\n // prev: unknown;\n};\n\nexport function updateCellsData({\n patchInfo,\n patches,\n onSuccess,\n onError,\n columns,\n setData,\n setCellEditMapAtLoc,\n}: {\n patchInfo: PatchInfo;\n patches: CellPatch[];\n onSuccess: (values: CellPatch[]) => void;\n onError: (err: string) => void;\n columns: readonly string[];\n setData: (fn: (draft: unknown[][]) => void) => void;\n setCellEditMapAtLoc: SetCellEditMapAtLoc;\n}) {\n // // Skip page index reset until after next rerender\n // skipAutoResetPageIndex();\n\n const patchesPy: CellPatchPy[] = patches.map((patch) => {\n return {\n row_index: patch.rowIndex,\n column_index: patch.columnIndex,\n value: patch.value,\n // prev: patch.prev,\n };\n });\n\n makeRequestPromise({\n method: patchInfo.key,\n args: [\n // list[CellPatch]\n patchesPy,\n ],\n })\n .then((newPatchesPy: ResponseValue) => {\n // Assert type of values is list\n if (!Array.isArray(newPatchesPy)) {\n throw new Error(\"Expected a response of a list of patches\");\n }\n\n for (const patch of newPatchesPy) {\n if (\n !(\"row_index\" in patch && \"column_index\" in patch && \"value\" in patch)\n ) {\n throw new Error(\n \"Expected list of patches containing `row_index`, `column_index`, and `value`\"\n );\n }\n }\n newPatchesPy = newPatchesPy as CellPatchPy[];\n\n const newPatches: CellPatch[] = newPatchesPy.map(\n (patch: CellPatchPy): CellPatch => {\n return {\n rowIndex: patch.row_index,\n columnIndex: patch.column_index,\n value: patch.value,\n };\n }\n );\n\n setData((draft) => {\n newPatches.forEach(({ rowIndex, columnIndex, value }) => {\n draft[rowIndex]![columnIndex] = value;\n });\n });\n\n // Set the old patches locations back to success state\n // This may be overkill, but it guarantees that the incoming patches exit the saving state\n patches.forEach(({ rowIndex, columnIndex, value }) => {\n setCellEditMapAtLoc(rowIndex, columnIndex, (obj_draft) => {\n // If the cell is still saving, then set it back to ready.\n // If not, then something else has changed the cell state, so don't change it.\n if (obj_draft.state !== CellStateEnum.EditSaving) return;\n\n obj_draft.state = CellStateEnum.Ready;\n obj_draft.value = value;\n obj_draft.errorTitle = undefined;\n });\n });\n // Set the new patches\n newPatches.forEach(({ rowIndex, columnIndex, value }) => {\n setCellEditMapAtLoc(rowIndex, columnIndex, (obj_draft) => {\n obj_draft.value = value;\n obj_draft.state = CellStateEnum.EditSuccess;\n // Remove save_error if it exists\n obj_draft.errorTitle = undefined;\n });\n });\n onSuccess(newPatches);\n })\n .catch((err: string) => {\n patches.forEach(({ rowIndex, columnIndex, value }) => {\n setCellEditMapAtLoc(rowIndex, columnIndex, (obj_draft) => {\n obj_draft.value = String(value);\n\n obj_draft.state = CellStateEnum.EditFailure;\n obj_draft.errorTitle = String(err);\n });\n });\n onError(err);\n });\n}\n", "import { ColumnDef, RowModel, flexRender } from \"@tanstack/react-table\";\nimport { Cell } from \"@tanstack/table-core\";\nimport React, {\n FC,\n ChangeEvent as ReactChangeEvent,\n ReactElement,\n FocusEvent as ReactFocusEvent,\n KeyboardEvent as ReactKeyboardEvent,\n MouseEvent as ReactMouseEvent,\n useCallback,\n useEffect,\n useRef,\n} from \"react\";\nimport { CellEdit, SetCellEditMapAtLoc } from \"./cell-edit-map\";\nimport { updateCellsData } from \"./data-update\";\nimport { SelectionSet } from \"./selection\";\nimport { CellStyle } from \"./style-info\";\nimport type { PatchInfo } from \"./types\";\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype HtmlDep = any;\n\n// States\n// # \u221A Ready\n// # \u221A Editing\n// # \u221A Saving / Disabled\n// # \u221A Error\n// # \u221A Saved\n// # Cancelled (is Ready state?)\n// # New\n// # Added\n// # Removed\nexport const CellStateEnum = {\n EditSaving: \"EditSaving\",\n EditSuccess: \"EditSuccess\",\n EditFailure: \"EditFailure\",\n Editing: \"Editing\",\n Ready: \"Ready\",\n} as const;\nexport const CellStateClassEnum = {\n EditSaving: \"cell-edit-saving\",\n EditSuccess: \"cell-edit-success\",\n EditFailure: \"cell-edit-failure\",\n Editing: \"cell-edit-editing\",\n Ready: undefined,\n} as const;\nexport type CellState = keyof typeof CellStateEnum;\n\ntype CellHtmlValue = {\n isShinyHtml: true;\n obj: { deps?: HtmlDep[]; html: string };\n};\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nconst isShinyHtml = (x: any): x is CellHtmlValue => {\n return (\n x !== null && // Note: x === null has `typeof x === \"object\"`\n typeof x === \"object\" &&\n Object.prototype.hasOwnProperty.call(x, \"isShinyHtml\") &&\n x.isShinyHtml === true\n );\n};\ntype CellValue = string | CellHtmlValue | null;\nconst getCellValueText = (cellValue: CellValue) => {\n if (isShinyHtml(cellValue)) return cellValue.obj.html;\n if (cellValue === null) return \"\";\n return cellValue as string;\n};\n\ninterface TableBodyCellProps {\n key: string;\n rowId: string;\n containerRef: React.RefObject;\n cell: Cell;\n patchInfo: PatchInfo;\n columns: readonly string[];\n coldefs: readonly ColumnDef[];\n rowIndex: number;\n columnIndex: number;\n editCellsIsAllowed: boolean;\n getSortedRowModel: () => RowModel;\n setData: (fn: (draft: unknown[][]) => void) => void;\n cellEditInfo: CellEdit | undefined;\n cellStyle: CellStyle | undefined;\n cellClassName: string | undefined;\n setCellEditMapAtLoc: SetCellEditMapAtLoc;\n selection: SelectionSet;\n}\n\nexport const TableBodyCell: FC = ({\n containerRef,\n rowId,\n cell,\n patchInfo,\n columns,\n coldefs,\n rowIndex,\n columnIndex,\n editCellsIsAllowed,\n getSortedRowModel,\n cellEditInfo,\n cellStyle,\n cellClassName,\n setData,\n setCellEditMapAtLoc,\n selection,\n}) => {\n const initialValue = cell.getValue() as\n | string\n | { isShinyHtml: true; obj: { deps?: HtmlDep[]; html: string } }\n | null;\n\n const isHtmlColumn = cell.column.columnDef.meta!.isHtmlColumn;\n\n const cellValue = cellEditInfo?.value ?? initialValue;\n\n const cellState = cellEditInfo?.state ?? CellStateEnum.Ready;\n const errorTitle = cellEditInfo?.errorTitle;\n // Listen to boolean value of cellEditInfo. This allows for the cell state to be restored if esc is hit\n const isEditing = cellEditInfo?.isEditing ?? false;\n const editValue = cellEditInfo?.editValue ?? getCellValueText(cellValue);\n\n const tdRef = useRef(null);\n const inputRef = useRef(null);\n\n // Keyboard navigation:\n // * When editing a cell:\n // * On esc key:\n // * \u221A Restore prior value / state / error\n // * \u221A Move focus from input to td\n // * On enter key:\n // * \u221A Save value\n // * \u221A Move to the cell below (or above w/ shift) and edit the new cell\n // * X Should shift+enter add a newline in a cell?\n // * On tab key:\n // * \u221A Save value\n // * \u221A Move to the cell to the right (or left w/ shift) and edit the new cell\n // * Scrolls out of view:\n // * Intercept keyboard events and execute the above actions\n // * (Currently, there literally is no input DOM element to accept keyboard events)\n // TODO-barret-future; More keyboard navigation!\n // * https://www.npmjs.com/package/@table-nav/react ?\n // * When focused on a td:\n // * Allow for arrow key navigation\n // * Have enter key enter edit mode for a cell\n // * \u221A When a td is focused, Have esc key move focus to the table\n // * X When table is focused, Have esc key blur the focus\n // TODO-barret-future; Combat edit mode being independent of selection mode\n // * In row / column selection mode, allow for arrow key navigation by focusing on a single cell, not a TR\n // * If a cell is focused,\n // * `enter key` allows you to go into edit mode; If editing is turned off, the selection is toggled\n // * `space key` allows you toggle the selection of the cell\n // * Arrow key navigation is required\n\n const resetEditing = useCallback(\n (\n {\n resetIsEditing = false,\n resetEditValue = false,\n }: { resetIsEditing?: boolean; resetEditValue?: boolean } = {\n resetIsEditing: true,\n resetEditValue: true,\n }\n ) => {\n setCellEditMapAtLoc(rowIndex, columnIndex, (obj_draft) => {\n if (resetIsEditing) obj_draft.isEditing = false;\n if (resetEditValue) obj_draft.editValue = undefined;\n });\n },\n [rowIndex, columnIndex, setCellEditMapAtLoc]\n );\n\n const handleEsc = (e: ReactKeyboardEvent) => {\n if (e.key !== \"Escape\") return;\n // Prevent default behavior\n e.preventDefault();\n e.stopPropagation();\n\n // Turn off editing and the _temp_ edit value\n resetEditing();\n selection.focusOffset(rowId, 0);\n };\n const handleTab = (e: ReactKeyboardEvent) => {\n if (e.key !== \"Tab\") return;\n // Prevent default behavior\n e.preventDefault();\n e.stopPropagation();\n\n const hasShift = e.shiftKey;\n\n let nextColumnIndex = columnIndex;\n // eslint-disable-next-line no-constant-condition\n while (true) {\n const newColumnIndex = nextColumnIndex + (hasShift ? -1 : 1);\n\n if (newColumnIndex < 0 || newColumnIndex >= coldefs.length) {\n // If the new column index is out of bounds, quit\n return;\n }\n\n nextColumnIndex = newColumnIndex;\n // Repeat until the loop if the next column is not an HTML column\n if (coldefs[newColumnIndex]!.meta!.isHtmlColumn !== true) {\n break;\n }\n }\n\n // Submit changes to the current cell\n attemptUpdate();\n\n // Turn on editing in next cell!\n setCellEditMapAtLoc(rowIndex, nextColumnIndex, (obj_draft) => {\n obj_draft.isEditing = true;\n });\n };\n // TODO future: Make Cmd-Enter add a newline in a cell.\n const handleEnter = (e: ReactKeyboardEvent) => {\n if (e.key !== \"Enter\") return;\n // Prevent default behavior\n e.preventDefault();\n e.stopPropagation();\n\n const hasShift = e.shiftKey;\n\n const rowModel = getSortedRowModel();\n const sortedRowIndex = rowModel.rows.findIndex((row) => row.id === rowId);\n // Couldn't find row... silently quit\n if (sortedRowIndex < 0) {\n return;\n }\n const nextSortedRowIndex = sortedRowIndex! + (hasShift ? -1 : 1);\n\n if (nextSortedRowIndex < 0 || nextSortedRowIndex >= rowModel.rows.length) {\n // If the new row index is out of bounds, quit\n return;\n }\n\n // Submit changes to the current cell\n attemptUpdate();\n\n // Turn on editing in the next cell!\n // Get the original row index\n const targetRowIndex = rowModel.rows[nextSortedRowIndex]!.index;\n setCellEditMapAtLoc(targetRowIndex, columnIndex, (obj_draft) => {\n obj_draft.isEditing = true;\n });\n };\n\n const onInputKeyDown = (e: ReactKeyboardEvent) => {\n [handleEsc, handleEnter, handleTab].forEach((fn) => fn(e));\n };\n\n const attemptUpdate = useCallback(() => {\n // Reset error title\n setCellEditMapAtLoc(rowIndex, columnIndex, (obj_draft) => {\n obj_draft.errorTitle = undefined;\n });\n\n // Only update if the string form of the value has changed\n if (`${getCellValueText(cellValue)}` === `${editValue}`) {\n // Reset all edit info\n resetEditing();\n // Set state to prior cell state\n setCellEditMapAtLoc(rowIndex, columnIndex, (obj_draft) => {\n obj_draft.state = cellState;\n });\n return;\n }\n\n // Only turn off editing for cell; Maintain all other edit info\n resetEditing({ resetIsEditing: true });\n\n // Set state to saving\n setCellEditMapAtLoc(rowIndex, columnIndex, (obj_draft) => {\n obj_draft.state = CellStateEnum.EditSaving;\n });\n\n // Update the data!\n // updateCellsData updates the underlying data via `setData` and `setCellEditMapAtLoc`\n updateCellsData({\n patchInfo: patchInfo,\n patches: [{ rowIndex, columnIndex, value: editValue }],\n onSuccess: (_patches) => {\n // Reset `editValue`\n resetEditing({ resetEditValue: true });\n\n // console.log(\"Success!!\");\n },\n onError: (_err) => {\n // console.log(\"Error!!\", _err);\n // // Do not reset edit value here so that users can \"restore\" their prior edit value\n // resetEditing({ resetEditValue: true });\n },\n columns,\n setData,\n setCellEditMapAtLoc,\n });\n }, [\n setCellEditMapAtLoc,\n rowIndex,\n columnIndex,\n cellValue,\n editValue,\n resetEditing,\n patchInfo,\n columns,\n setData,\n cellState,\n ]);\n\n // Select the input when it becomes editable\n useEffect(() => {\n if (!isEditing) return;\n if (!inputRef.current) return;\n\n inputRef.current.focus();\n inputRef.current.select();\n }, [isEditing]);\n\n // When editing a cell, set up a global click listener to reset edit info when\n // clicking outside of the cell\n // Use MouseDown event to match how selection is performed to prevent the click from bubbling up\n useEffect(() => {\n if (!isEditing) return;\n if (!tdRef.current) return;\n if (!inputRef.current) return;\n\n // TODO-barret; Restore cursor position and text selection here\n\n const onEdtingCellMouseDown = (e: MouseEvent) => {\n if (!tdRef.current?.contains(e.target as Node)) return;\n // Prevent the click from bubbling up to the body click listener\n e.stopPropagation();\n\n // Do not stop the event from preventing default as we need the click to work for the text area!\n // e.preventDefault();\n };\n const curRef = tdRef.current; // Capture the current ref\n curRef.addEventListener(\"mousedown\", onEdtingCellMouseDown);\n\n // Set up global click listener to reset edit info\n const onBodyMouseDown = (e: MouseEvent) => {\n if (e.target === inputRef.current) return;\n\n attemptUpdate();\n // Turn off editing for this cell\n resetEditing();\n };\n document.body.addEventListener(\"mousedown\", onBodyMouseDown);\n\n // Tear down global click listener when we're done\n return () => {\n curRef.removeEventListener(\"mousedown\", onEdtingCellMouseDown);\n document.body.removeEventListener(\"mousedown\", onBodyMouseDown);\n };\n }, [\n cellState,\n attemptUpdate,\n rowIndex,\n columnIndex,\n isEditing,\n resetEditing,\n ]);\n\n // Reselect the input when it comes into view!\n // (It could be scrolled out of view and then back into view)\n function onFocus(e: ReactFocusEvent) {\n if (isEditing) {\n e.target.select();\n }\n }\n\n function onChange(e: ReactChangeEvent) {\n // Update edit value to cell map\n setCellEditMapAtLoc(rowIndex, columnIndex, (obj_draft) => {\n obj_draft.editValue = e.target.value;\n });\n }\n\n // // https://medium.com/@oherterich/creating-a-textarea-with-dynamic-height-using-react-and-typescript-5ed2d78d9848\n // // Updates the height of a