Skip to content

Commit 08cd1f0

Browse files
machowschloerke
andauthored
feat(data frame): Support polars (#1474)
Co-authored-by: Barret Schloerke <[email protected]>
1 parent bdb5935 commit 08cd1f0

File tree

48 files changed

+2084
-761
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

48 files changed

+2084
-761
lines changed

js/data-frame/cell.tsx

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,8 @@ type CellHtmlValue = {
5454
// eslint-disable-next-line @typescript-eslint/no-explicit-any
5555
const isShinyHtml = (x: any): x is CellHtmlValue => {
5656
return (
57-
x !== null &&
58-
typeof x !== "string" &&
57+
x !== null && // Note: x === null has `typeof x === "object"`
58+
typeof x === "object" &&
5959
Object.prototype.hasOwnProperty.call(x, "isShinyHtml") &&
6060
x.isShinyHtml === true
6161
);
@@ -83,6 +83,7 @@ interface TableBodyCellProps {
8383
setData: (fn: (draft: unknown[][]) => void) => void;
8484
cellEditInfo: CellEdit | undefined;
8585
cellStyle: CellStyle | undefined;
86+
cellClassName: string | undefined;
8687
setCellEditMapAtLoc: SetCellEditMapAtLoc;
8788
selection: SelectionSet<string, HTMLTableRowElement>;
8889
}
@@ -100,6 +101,7 @@ export const TableBodyCell: FC<TableBodyCellProps> = ({
100101
getSortedRowModel,
101102
cellEditInfo,
102103
cellStyle,
104+
cellClassName,
103105
setData,
104106
setCellEditMapAtLoc,
105107
selection,
@@ -402,7 +404,7 @@ export const TableBodyCell: FC<TableBodyCellProps> = ({
402404
let content: ReactElement | ReturnType<typeof flexRender> | undefined =
403405
undefined;
404406
const cellTitle = errorTitle;
405-
let tableCellClass: string | undefined = undefined;
407+
let tableCellClass: string | undefined = cellClassName;
406408
const addToTableCellClass = (x: string | undefined) => {
407409
if (!x) return;
408410
if (tableCellClass) {

js/data-frame/index.tsx

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -109,16 +109,27 @@ const ShinyDataGrid: FC<ShinyDataGridProps<unknown>> = ({
109109
columns,
110110
typeHints,
111111
data: tableDataProp,
112-
options: payloadOptions,
112+
options: payloadOptions = {
113+
width: undefined,
114+
height: undefined,
115+
fill: false,
116+
styles: [],
117+
},
113118
} = payload;
114-
const { width, height, fill, filters: withFilters } = payloadOptions;
119+
const {
120+
width,
121+
height,
122+
fill,
123+
filters: withFilters,
124+
styles: initStyleInfos,
125+
} = payloadOptions;
115126

116127
const containerRef = useRef<HTMLDivElement>(null);
117128
const theadRef = useRef<HTMLTableSectionElement>(null);
118129
const tbodyRef = useRef<HTMLTableSectionElement>(null);
119130

120131
const _useStyleInfo = useStyleInfoMap({
121-
initStyleInfos: payloadOptions["styles"],
132+
initStyleInfos: initStyleInfos ?? [],
122133
nrow: tableDataProp.length,
123134
ncol: columns.length,
124135
});
@@ -486,7 +497,6 @@ const ShinyDataGrid: FC<ShinyDataGridProps<unknown>> = ({
486497
useEffect(() => {
487498
const handleStyles = (event: CustomEvent<{ styles: StyleInfo[] }>) => {
488499
const styles = event.detail.styles;
489-
resetStyleInfos();
490500
setStyleInfos(styles);
491501
};
492502

@@ -503,7 +513,7 @@ const ShinyDataGrid: FC<ShinyDataGridProps<unknown>> = ({
503513
handleStyles as EventListener
504514
);
505515
};
506-
}, [setStyleInfos]);
516+
}, [id, setStyleInfos]);
507517

508518
useEffect(() => {
509519
if (!id) return;
@@ -765,7 +775,7 @@ const ShinyDataGrid: FC<ShinyDataGridProps<unknown>> = ({
765775
rowIndex,
766776
columnIndex
767777
);
768-
const cellStyle = getCellStyle(
778+
const { cellStyle, cellClassName } = getCellStyle(
769779
styleInfoMap,
770780
"body",
771781
rowIndex,
@@ -787,6 +797,7 @@ const ShinyDataGrid: FC<ShinyDataGridProps<unknown>> = ({
787797
getSortedRowModel={table.getSortedRowModel}
788798
cellEditInfo={cellEditInfo}
789799
cellStyle={cellStyle}
800+
cellClassName={cellClassName}
790801
setData={setTableData}
791802
setCellEditMapAtLoc={setCellEditMapAtLoc}
792803
selection={selection}

js/data-frame/style-info.ts

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -83,12 +83,30 @@ export const useStyleInfoMap = ({
8383
rowIndex,
8484
columnIndex,
8585
});
86+
const prevObj = draft.get(key) ?? { style: {}, class: undefined };
87+
let newClass: string | undefined = undefined;
88+
if (prevObj.class) {
89+
if (styleInfo.class) {
90+
newClass = `${prevObj.class} ${styleInfo.class}`;
91+
} else {
92+
newClass = prevObj.class;
93+
}
94+
} else {
95+
if (styleInfo.class) {
96+
newClass = styleInfo.class;
97+
} else {
98+
newClass = undefined;
99+
}
100+
}
86101
draft.set(key, {
87-
location: styleInfo.location,
102+
location,
88103
rowIndex,
89104
columnIndex,
90-
style: styleInfo.style,
91-
class: styleInfo.class,
105+
style: {
106+
...prevObj.style,
107+
...styleInfo.style,
108+
},
109+
class: newClass,
92110
});
93111
}
94112
}
@@ -105,11 +123,13 @@ export const useStyleInfoMap = ({
105123

106124
const setStyleInfos = useCallback(
107125
(styleInfos: StyleInfo[]) => {
126+
// When settings styleInfos, reset all style infos
127+
resetStyleInfos();
108128
for (const styleInfo of styleInfos) {
109129
setStyleInfo(styleInfo);
110130
}
111131
},
112-
[setStyleInfo]
132+
[setStyleInfo, resetStyleInfos]
113133
);
114134

115135
// Init all style infos
@@ -138,9 +158,13 @@ export const getCellStyle = (
138158
location: StyleLocation,
139159
rowIndex: number,
140160
columnIndex: number
141-
): CellStyle | undefined => {
161+
): { cellStyle: CellStyle | undefined; cellClassName: string | undefined } => {
142162
const key = makeStyleInfoMapKey({ location, rowIndex, columnIndex });
143-
return x.get(key)?.style;
163+
const obj = x.get(key);
164+
return {
165+
cellStyle: obj?.style,
166+
cellClassName: obj?.class,
167+
};
144168
};
145169

146170
// Use a DOM element to convert CSS string to object

js/data-frame/types.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ export interface DataGridOptions {
2424
width?: string;
2525
height?: string;
2626
fill?: boolean;
27+
styles: StyleInfo[];
2728
}
2829

2930
export interface PandasData<TIndex> {
@@ -33,7 +34,6 @@ export interface PandasData<TIndex> {
3334
options: DataGridOptions;
3435
typeHints?: ReadonlyArray<TypeHint>;
3536
editable?: boolean;
36-
styles: StyleInfo[];
3737
}
3838

3939
export interface PatchInfo {

setup.cfg

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@ dev =
114114
matplotlib
115115
pandas
116116
pandas-stubs
117+
polars
117118
numpy
118119
shinyswatch>=0.2.4
119120
# Chat() provider types

shiny/playwright/controller/_controls.py

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6255,10 +6255,12 @@ def set_sort(
62556255
----------
62566256
sort
62576257
The sorting configuration to apply. Can be one of the following:
6258-
int: Index of the column to sort by (ascending order by default).
6259-
ColumnSort: A dictionary specifying a single column sort with 'col' and 'desc' keys.
6260-
list[ColumnSort]: A list of dictionaries for multi-column sorting.
6261-
None: No sorting applied (not implemented in the current code).
6258+
* `int`: Index of the column to sort by (ascending order by default).
6259+
* `ColumnSort`: A dictionary specifying a single column sort with 'col' and 'desc' keys.
6260+
* `list[int | ColumnSort]`: A list of ints or dictionaries for multi-column sorting.
6261+
* `None`: No sorting applied (not implemented in the current code).
6262+
6263+
If a `desc` values is provided within your `ColumnSort` shaped dictionary, then the direction will be set to that value. If no `desc` value is provided, the column will be sorted in the default sorting order.
62626264
timeout
62636265
The maximum time to wait for the action to complete. Defaults to `None`.
62646266
"""
@@ -6348,10 +6350,9 @@ def set_filter(
63486350
----------
63496351
filter
63506352
The filter to apply. Can be one of the following:
6351-
None: Resets all filters.
6352-
str: A string filter (deprecated, use ColumnFilterStr instead).
6353-
ColumnFilterStr: A dictionary specifying a string filter with 'col' and 'value' keys.
6354-
ColumnFilterNumber: A dictionary specifying a numeric range filter with 'col' and 'value' keys.
6353+
* `None`: Resets all filters.
6354+
* `ColumnFilterStr`: A dictionary specifying a string filter with 'col' and 'value' keys.
6355+
* `ColumnFilterNumber`: A dictionary specifying a numeric range filter with 'col' and 'value' keys.
63556356
timeout
63566357
The maximum time to wait for the action to complete. Defaults to `None`.
63576358
"""

shiny/playwright/expect/_expect.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ def expect_attribute_to_have_value(
4545
def expect_to_have_class(
4646
loc: Locator,
4747
cls: str,
48+
*,
4849
timeout: Timeout = None,
4950
) -> None:
5051
"""Expect a locator to contain a class value"""
@@ -56,6 +57,7 @@ def expect_to_have_class(
5657
def expect_not_to_have_class(
5758
loc: Locator,
5859
cls: str,
60+
*,
5961
timeout: Timeout = None,
6062
) -> None:
6163
"""Expect a locator not to contain a class value"""
@@ -69,6 +71,7 @@ def expect_to_have_style(
6971
css_key: str,
7072
# Str representation for value. Will be put in a regex with `css_key`
7173
css_value: StyleValue,
74+
*,
7275
timeout: Timeout = None,
7376
) -> None:
7477
"""Expect the `style` attribute to have a value. If `value` is `None`, then the style attribute should not exist."""

shiny/render/__init__.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@
1212
DataTable,
1313
data_frame,
1414
)
15-
from ._data_frame_utils import CellSelection, StyleInfo
15+
from ._data_frame_utils import CellSelection
16+
from ._data_frame_utils._types import DataFrameLike, StyleInfo
1617
from ._deprecated import ( # noqa: F401
1718
RenderFunction, # pyright: ignore[reportUnusedImport]
1819
RenderFunctionAsync, # pyright: ignore[reportUnusedImport]
@@ -47,4 +48,5 @@
4748
"CellValue",
4849
"CellSelection",
4950
"StyleInfo",
51+
"DataFrameLike",
5052
)

0 commit comments

Comments
 (0)