Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: allow overflow by default on ui.panel #896

Open
wants to merge 9 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions plugins/ui/src/deephaven/ui/components/grid.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,10 @@ def grid(
justify_content: JustifyContent = "stretch",
align_content: AlignContent = "start",
align_items: AlignItems = "stretch",
gap: DimensionValue | None = None,
gap: DimensionValue | None = "size-100",
column_gap: DimensionValue | None = None,
row_gap: DimensionValue | None = None,
flex: LayoutFlex | None = None,
flex: LayoutFlex | None = "auto",
flex_grow: float | None = None,
flex_shrink: float | None = None,
flex_basis: DimensionValue | None = None,
Expand Down
2 changes: 2 additions & 0 deletions plugins/ui/src/deephaven/ui/components/panel.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
AlignContent,
AlignItems,
DimensionValue,
Overflow,
)


Expand All @@ -24,6 +25,7 @@ def panel(
gap: DimensionValue | None = "size-100",
column_gap: DimensionValue | None = None,
row_gap: DimensionValue | None = None,
overflow: Overflow | None = "auto",
padding: DimensionValue | None = "size-100",
padding_top: DimensionValue | None = None,
padding_bottom: DimensionValue | None = None,
Expand Down
3 changes: 3 additions & 0 deletions plugins/ui/src/deephaven/ui/components/types/layout.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,9 @@
"legacy center",
]


Overflow = Union[Literal["visible", "hidden", "clip", "scroll", "auto"], str]

OverflowMode = Literal["wrap", "collapse"]

Alignment = Literal["start", "end"]
Expand Down
5 changes: 4 additions & 1 deletion plugins/ui/src/js/src/layout/ReactPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ interface Props
| 'paddingEnd'
| 'paddingX'
| 'paddingY'
| 'overflow'
| 'UNSAFE_style'
| 'UNSAFE_className'
>,
Expand Down Expand Up @@ -64,6 +65,7 @@ function ReactPanel({
backgroundColor,
direction = 'column',
wrap,
overflow = 'auto',
justifyContent,
alignContent,
alignItems = 'start',
Expand Down Expand Up @@ -182,6 +184,7 @@ function ReactPanel({
<ReactPanelContext.Provider value={panelId}>
<View
height="100%"
width="100%"
backgroundColor={backgroundColor}
padding={padding}
paddingTop={paddingTop}
Expand All @@ -190,6 +193,7 @@ function ReactPanel({
paddingEnd={paddingEnd}
paddingX={paddingX}
paddingY={paddingY}
overflow={overflow}
UNSAFE_style={UNSAFE_style}
UNSAFE_className={
UNSAFE_className == null
Expand All @@ -199,7 +203,6 @@ function ReactPanel({
>
<Flex
UNSAFE_className="dh-inner-react-panel"
height="100%"
wrap={wrap}
direction={direction}
justifyContent={justifyContent}
Expand Down
43 changes: 39 additions & 4 deletions plugins/ui/src/js/src/styles.scss
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
@import '@deephaven/components/scss/custom.scss';

.ui-portal-panel {
display: contents;
height: 100%;
width: 100%;
position: relative;
overflow: hidden;
}

.ui-object-container {
Expand All @@ -10,9 +13,41 @@
}

.dh-react-panel {
.dh-inner-react-panel .iris-grid {
border: 1px solid var(--dh-color-bg);
border-radius: $border-radius;
// using grid to allow the panel to grow to fill the container
// without having to set the width/height explicitly
// so that overflow will include it's padding
display: grid;

.dh-inner-react-panel {
// forces the panel to have an intrinsic size
// 100% width items shrink to fit the container
min-width: 0;

// todo out tuesday, devins thing, panels thing
// clem needs a thing as well
// import blog articles

// inner-panel is flex with align-start
// so that things like buttons don't stretch
// but we still want child flex/grid items to stretch
> .dh-flex,
> .dh-grid {
align-self: stretch;
}

.iris-grid {
// we don't want the grid to ever collapse to 0 height, so we set a min-height
// let's users know that the grid is there
min-height: 70px;
border: 1px solid var(--dh-color-bg);
border-radius: $border-radius;

canvas {
// setting canvas t0 position absolute
// removes the canvas from the normal flow
position: absolute;
}
}
}

&:has(.dh-inner-react-panel > .iris-grid:only-child),
Expand Down
12 changes: 12 additions & 0 deletions plugins/ui/src/js/src/widget/WidgetUtils.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,11 @@ const shouldWrapTextChildren = new Set<string>([
ELEMENT_NAME.view,
]);

const shouldAddClassName = new Set<string>([
ELEMENT_NAME.flex,
ELEMENT_NAME.grid,
]);

const log = Log.module('@deephaven/js-plugin-ui/WidgetUtils');

/*
Expand Down Expand Up @@ -175,6 +180,13 @@ export function getComponentForElement(element: ElementNode): React.ReactNode {
</ContextualHelp>
);
}
// classes can be used for deephaven ui specific css
// "deephaven.ui.components.Grid" -> "dh-grid"
if (shouldAddClassName.has(newElement[ELEMENT_KEY])) {
props.UNSAFE_className = `${props.UNSAFE_className ?? ''} ${`dh-${
newElement[ELEMENT_KEY].split('.').pop()?.toLowerCase() ?? ''
}`}`.trim();
}
dsmmcken marked this conversation as resolved.
Show resolved Hide resolved

return <Component {...props} />;
}
Expand Down
3 changes: 2 additions & 1 deletion tests/app.d/tests.app
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@ name=Plugins Test Application
file_0=express.py
file_1=matplotlib.py
file_2=ui.py
file_3=ui_render_all.py
file_3=ui_render_all.py
file_4=ui_flex.py
70 changes: 70 additions & 0 deletions tests/app.d/ui_flex.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
from deephaven import ui
from deephaven.plot import express as dx
from deephaven import empty_table

_t_flex = empty_table(100).update(["x = i", "y = sin(i)"])
_p_flex = dx.line(_t_flex, x="x", y="y")


@ui.component
def ui_flex_text_field_input_types_examples():
return [
ui.form(
ui.text_field(label="Name", type="text", is_required=True),
ui.text_field(label="Personal Website", type="url", is_required=True),
ui.text_field(label="Phone", type="tel", is_required=True),
ui.text_field(label="Email", type="email", is_required=True),
ui.text_field(label="Password", type="password", is_required=True),
ui.text_field(label="Search Bar", type="search"),
validation_behavior="native",
),
_t_flex,
]


@ui.component
def ui_flex_test_component():
return [ui.text_field(), _t_flex, _t_flex]


flex_0 = ui_flex_test_component()
flex_1 = ui_flex_text_field_input_types_examples()
flex_2 = ui.panel(_t_flex, _t_flex, background_color="red")
flex_3 = ui.button("test")
flex_4 = ui.text_field(label="test", label_position="side")
flex_5 = ui.panel(
ui.flex(_t_flex, _t_flex, direction="column"), background_color="blue"
)
flex_6 = ui.panel(ui.flex(_t_flex, _t_flex, direction="row"), background_color="green")
flex_7 = ui.panel(_t_flex, _p_flex, direction="row")
flex_8 = ui.panel(_t_flex, _p_flex)
flex_9 = ui.panel(ui.text_field(label="test"), _t_flex)
flex_10 = ui.panel(
ui.flex(ui.flex(_t_flex, _t_flex), ui.button("hello")), ui.text_field()
)
flex_11 = ui.panel(
ui.flex(ui.flex(_p_flex, _p_flex), ui.button("hello")), ui.text_field()
)
flex_12 = ui.panel(_p_flex, _p_flex, direction="row")
flex_13 = ui.panel(_p_flex, _p_flex)
flex_14 = ui.flex(
ui.button("hello flex"), align_items="center", justify_content="center"
)
flex_15 = ui.panel(
ui.button("hello panel"), align_items="center", justify_content="center"
)
flex_16 = ui.panel(ui.flex(ui.flex(_t_flex, _t_flex)))
flex_17 = ui.panel(
ui.flex(ui.button("test"), ui.action_button("test"), direction="column")
)
flex_18 = ui.panel(
ui.form(
ui.text_field(label="Name", label_position="side"),
ui.text_field(label="Name", label_position="side"),
ui.text_field(label="Name", label_position="side"),
ui.text_field(label="Name", label_position="side"),
),
)
flex_19 = ui.panel(
ui.grid(ui.button("test"), _t_flex, _p_flex, rows="min-content 1fr 1fr")
)
43 changes: 43 additions & 0 deletions tests/ui.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,3 +59,46 @@ test('UI all components render 2', async ({ page }) => {
await openPanel(page, 'ui_render_all2', selector.REACT_PANEL_VISIBLE);
await expect(page.locator(selector.REACT_PANEL_VISIBLE)).toHaveScreenshot();
});

// Tests flex components render as expected
test.describe('UI flex components', () => {
[
{ name: 'flex_0', traces: 0 },
{ name: 'flex_1', traces: 0 },
{ name: 'flex_2', traces: 0 },
{ name: 'flex_3', traces: 0 },
{ name: 'flex_4', traces: 0 },
{ name: 'flex_5', traces: 0 },
{ name: 'flex_6', traces: 0 },
{ name: 'flex_7', traces: 1 },
{ name: 'flex_8', traces: 1 },
{ name: 'flex_9', traces: 0 },
{ name: 'flex_10', traces: 0 },
{ name: 'flex_11', traces: 2 },
{ name: 'flex_12', traces: 2 },
{ name: 'flex_13', traces: 2 },
{ name: 'flex_14', traces: 0 },
{ name: 'flex_15', traces: 0 },
{ name: 'flex_16', traces: 0 },
{ name: 'flex_17', traces: 0 },
{ name: 'flex_18', traces: 0 },
{ name: 'flex_19', traces: 1 },
].forEach(i => {
test(i.name, async ({ page }) => {
await gotoPage(page, '');
await openPanel(page, i.name, selector.REACT_PANEL_VISIBLE);

// need to wait for plots to be loaded before taking screenshot
// easiest way to check that is if the traces are present
if (i.traces > 0) {
await expect(
await page.locator(selector.REACT_PANEL_VISIBLE).locator('.trace')
).toHaveCount(i.traces);
}

await expect(
page.locator(selector.REACT_PANEL_VISIBLE)
).toHaveScreenshot();
});
});
});
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified tests/ui.spec.ts-snapshots/UI-loads-1-chromium-linux.png
Binary file modified tests/ui.spec.ts-snapshots/UI-loads-1-firefox-linux.png
Binary file modified tests/ui.spec.ts-snapshots/UI-loads-1-webkit-linux.png
10 changes: 10 additions & 0 deletions tests/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,11 +45,21 @@ export async function openPanel(
await expect(appPanels).toBeEnabled();
await appPanels.click();

// search for the panel in list
const search = page.getByRole('searchbox', {
name: 'Find Table, Plot or Widget',
exact: true,
});
await search.fill(name);

// open panel
const targetPanel = page.getByRole('button', { name, exact: true });
expect(targetPanel).toBeEnabled();
await targetPanel.click();

// reset mouse position to not cause unintended hover effects
await page.mouse.move(0, 0);

// check for panel to be loaded
await expect(page.locator(panelLocator)).toHaveCount(panelCount + 1);
await expect(page.locator('.loading-spinner')).toHaveCount(0);
Expand Down
Loading