Skip to content

Commit

Permalink
refactor(ui): improvements to vanjs components to support page compon…
Browse files Browse the repository at this point in the history
…ents
  • Loading branch information
aarthy-dk committed Oct 3, 2024
1 parent a575af2 commit f8e26f3
Show file tree
Hide file tree
Showing 11 changed files with 456 additions and 73 deletions.
377 changes: 375 additions & 2 deletions testgen/ui/components/frontend/css/shared.css

Large diffs are not rendered by default.

14 changes: 7 additions & 7 deletions testgen/ui/components/frontend/js/components/breadcrumbs.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,15 @@
*/
import van from '../van.min.js';
import { Streamlit } from '../streamlit.js';
import { loadStylesheet } from '../utils.js';

const { a, div, span } = van.tags;

const Breadcrumbs = (/** @type Properties */ props) => {
Streamlit.setFrameHeight(24);
loadStylesheet('breadcrumbs', stylesheet);

if (!window.testgen.loadedStylesheets.breadcrumbs) {
document.adoptedStyleSheets.push(stylesheet);
window.testgen.loadedStylesheets.breadcrumbs = true;
if (!window.testgen.isPage) {
Streamlit.setFrameHeight(24);
}

return div(
Expand All @@ -31,7 +31,7 @@ const Breadcrumbs = (/** @type Properties */ props) => {
{ class: 'tg-breadcrumbs' },
breadcrumbs.reduce((items, b, idx) => {
const isLastItem = idx === breadcrumbs.length - 1;
items.push(a({ class: `tg-breadcrumbs--${ isLastItem ? 'current' : 'active'}`, href: `#/${b.path}`, onclick: () => navigate(b.path, b.params) }, b.label))
items.push(a({ class: `tg-breadcrumbs--${ isLastItem ? 'current' : 'active'}`, href: `#/${b.path}`, onclick: () => emiEvent(b.path, b.params) }, b.label))
if (!isLastItem) {
items.push(span({class: 'tg-breadcrumbs--arrow'}, '>'));
}
Expand All @@ -42,8 +42,8 @@ const Breadcrumbs = (/** @type Properties */ props) => {
)
};

function navigate(/** @type string */ path, /** @type object */ params) {
Streamlit.sendData({ path, params });
function emiEvent(/** @type string */ href, /** @type object */ params) {
Streamlit.sendData({ event: 'LinkClicked', href, params });
return false;
}

Expand Down
17 changes: 8 additions & 9 deletions testgen/ui/components/frontend/js/components/button.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
* @property {(bool)} disabled
* @property {string?} style
*/
import { enforceElementWidth } from '../utils.js';
import { enforceElementWidth, loadStylesheet } from '../utils.js';
import van from '../van.min.js';
import { Streamlit } from '../streamlit.js';

Expand All @@ -23,23 +23,22 @@ const BUTTON_TYPE = {
};

const Button = (/** @type Properties */ props) => {
Streamlit.setFrameHeight(40);
loadStylesheet('button', stylesheet);

const isIconOnly = props.type === BUTTON_TYPE.ICON || (props.icon?.val && !props.label?.val);
if (isIconOnly) { // Force a 40px width for the parent iframe & handle window resizing
enforceElementWidth(window.frameElement, 40);

if (!window.testgen.isPage) {
Streamlit.setFrameHeight(40);
if (isIconOnly) { // Force a 40px width for the parent iframe & handle window resizing
enforceElementWidth(window.frameElement, 40);
}
}

if (props.tooltip) {
window.frameElement.parentElement.setAttribute('data-tooltip', props.tooltip.val);
window.frameElement.parentElement.setAttribute('data-tooltip-position', props.tooltipPosition.val);
}

if (!window.testgen.loadedStylesheets.button) {
document.adoptedStyleSheets.push(stylesheet);
window.testgen.loadedStylesheets.button = true;
}

const onClickHandler = props.onclick || post;
return button(
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,15 @@
*/
import van from '../van.min.js';
import { Streamlit } from '../streamlit.js';
import { loadStylesheet } from '../utils.js';

const { div, span, i } = van.tags;

const ExpanderToggle = (/** @type Properties */ props) => {
Streamlit.setFrameHeight(24);
loadStylesheet('expanderToggle', stylesheet);

if (!window.testgen.loadedStylesheets.expanderToggle) {
document.adoptedStyleSheets.push(stylesheet);
window.testgen.loadedStylesheets.expanderToggle = true;
if (!window.testgen.isPage) {
Streamlit.setFrameHeight(24);
}

const expandedState = van.state(!!props.default.val);
Expand Down
25 changes: 12 additions & 13 deletions testgen/ui/components/frontend/js/components/link.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,28 +13,27 @@
* @property {number?} width
* @property {string?} style
*/
import { enforceElementWidth } from '../utils.js';
import { enforceElementWidth, loadStylesheet } from '../utils.js';
import van from '../van.min.js';
import { Streamlit } from '../streamlit.js';

const { a, div, i, span } = van.tags;

const Link = (/** @type Properties */ props) => {
Streamlit.setFrameHeight(props.height?.val || 24);
if (props.width?.val) {
enforceElementWidth(window.frameElement, props.width.val);
}
loadStylesheet('link', stylesheet);

if (!window.testgen.loadedStylesheets.link) {
document.adoptedStyleSheets.push(stylesheet);
window.testgen.loadedStylesheets.link = true;
if (!window.testgen.isPage) {
Streamlit.setFrameHeight(props.height?.val || 24);
if (props.width?.val) {
enforceElementWidth(window.frameElement, props.width.val);
}
}

return a(
{
class: `tg-link ${props.underline.val ? 'tg-link--underline' : ''}`,
class: `tg-link ${props.underline?.val ? 'tg-link--underline' : ''}`,
style: props.style,
onclick: () => navigate(props.href.val, props.params.val),
onclick: () => emitEvent(props.href.val, props.params.val),
},
div(
{class: 'tg-link--wrapper'},
Expand All @@ -51,13 +50,13 @@ const LinkIcon = (
/** @type string */position,
) => {
return i(
{class: `material-symbols-rounded tg-link--icon tg-link--icon-${position}`, style: `font-size: ${size.val}px;`},
{class: `material-symbols-rounded tg-link--icon tg-link--icon-${position}`, style: `font-size: ${size?.val || 20}px;`},
icon,
);
};

function navigate(href, params) {
Streamlit.sendData({ href, params });
function emitEvent(href, params) {
Streamlit.sendData({ event: 'LinkClicked', href, params });
}

const stylesheet = new CSSStyleSheet();
Expand Down
32 changes: 17 additions & 15 deletions testgen/ui/components/frontend/js/components/paginator.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,20 +7,18 @@
*/
import van from '../van.min.js';
import { Streamlit } from '../streamlit.js';
import { loadStylesheet } from '../utils.js';

const { div, span, i, button } = van.tags;

const Paginator = (/** @type Properties */ props) => {
const count = props.count.val;
const pageSize = props.pageSize.val;
loadStylesheet('paginator', stylesheet);

Streamlit.setFrameHeight(32);

if (!window.testgen.loadedStylesheets.expanderToggle) {
document.adoptedStyleSheets.push(stylesheet);
window.testgen.loadedStylesheets.expanderToggle = true;
if (!window.testgen.isPage) {
Streamlit.setFrameHeight(32);
}

const { count, pageSize } = props;
const pageIndexState = van.state(props.pageIndex.val || 0);

return div(
Expand All @@ -29,15 +27,15 @@ const Paginator = (/** @type Properties */ props) => {
{ class: 'tg-paginator--label' },
() => {
const pageIndex = pageIndexState.val;
return `${pageSize * pageIndex + 1} - ${Math.min(count, pageSize * (pageIndex + 1))} of ${count}`
return `${pageSize.val * pageIndex + 1} - ${Math.min(count.val, pageSize.val * (pageIndex + 1))} of ${count.val}`;
},
),
button(
{
class: 'tg-paginator--button',
onclick: () => {
pageIndexState.val = 0;
Streamlit.sendData(pageIndexState.val);
emitEvent(pageIndexState.val);
},
disabled: () => pageIndexState.val === 0,
},
Expand All @@ -48,7 +46,7 @@ const Paginator = (/** @type Properties */ props) => {
class: 'tg-paginator--button',
onclick: () => {
pageIndexState.val--;
Streamlit.sendData(pageIndexState.val);
emitEvent(pageIndexState.val);
},
disabled: () => pageIndexState.val === 0,
},
Expand All @@ -59,26 +57,30 @@ const Paginator = (/** @type Properties */ props) => {
class: 'tg-paginator--button',
onclick: () => {
pageIndexState.val++;
Streamlit.sendData(pageIndexState.val);
emitEvent(pageIndexState.val);
},
disabled: () => pageIndexState.val === Math.ceil(count / pageSize) - 1,
disabled: () => pageIndexState.val === Math.ceil(count.val / pageSize.val) - 1,
},
i({class: 'material-symbols-rounded'}, 'chevron_right')
),
button(
{
class: 'tg-paginator--button',
onclick: () => {
pageIndexState.val = Math.ceil(count / pageSize) - 1;
Streamlit.sendData(pageIndexState.val);
pageIndexState.val = Math.ceil(count.val / pageSize.val) - 1;
emitEvent(pageIndexState.val);
},
disabled: () => pageIndexState.val === Math.ceil(count / pageSize) - 1,
disabled: () => pageIndexState.val === Math.ceil(count.val / pageSize.val) - 1,
},
i({class: 'material-symbols-rounded'}, 'last_page')
),
);
};

function emitEvent(/** @type number */pageIndex) {
Streamlit.sendData({ event: 'PageChanged', pageIndex })
}

const stylesheet = new CSSStyleSheet();
stylesheet.replace(`
.tg-paginator {
Expand Down
7 changes: 2 additions & 5 deletions testgen/ui/components/frontend/js/components/select.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,14 @@
*/
import van from '../van.min.js';
import { Streamlit } from '../streamlit.js';
import { loadStylesheet } from '../utils.js';

const { div, label, option, select } = van.tags;

const Select = (/** @type {Properties} */ props) => {
loadStylesheet('select', stylesheet);
Streamlit.setFrameHeight();

if (!window.testgen.loadedStylesheets.select) {
document.adoptedStyleSheets.push(stylesheet);
window.testgen.loadedStylesheets.select = true;
}

const domId = Math.random().toString(36).substring(2);
const changeHandler = props.onChange || post;
return div(
Expand Down
11 changes: 5 additions & 6 deletions testgen/ui/components/frontend/js/components/sorting_selector.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import {Streamlit} from "../streamlit.js";
import van from '../van.min.js';
import { loadStylesheet } from '../utils.js';

/**
* @typedef ColDef
Expand All @@ -16,20 +17,18 @@ import van from '../van.min.js';
const { button, div, i, span } = van.tags;

const SortingSelector = (/** @type {Properties} */ props) => {
loadStylesheet('sortingSelector', stylesheet);

let defaultDirection = "ASC";

if (!window.testgen.loadedStylesheets.sortingSelector) {
document.adoptedStyleSheets.push(stylesheet);
window.testgen.loadedStylesheets.sortSelector = true;
}

const columns = props.columns.val;
const prevComponentState = props.state.val || [];

const columnLabel = columns.reduce((acc, [colLabel, colId]) => ({ ...acc, [colId]: colLabel}), {});

Streamlit.setFrameHeight(100 + 30 * columns.length);
if (!window.testgen.isPage) {
Streamlit.setFrameHeight(100 + 30 * columns.length);
}

const componentState = columns.reduce(
(state, [colLabel, colId]) => (
Expand Down
15 changes: 5 additions & 10 deletions testgen/ui/components/frontend/js/components/summary_bar.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
* @property {number} width
*/
import van from '../van.min.js';
import { Streamlit } from '../streamlit.js';
import { loadStylesheet } from '../utils.js';

const { div, span } = van.tags;
const colorMap = {
Expand All @@ -28,19 +28,14 @@ const colorMap = {
}

const SummaryBar = (/** @type Properties */ props) => {
loadStylesheet('summaryBar', stylesheet);

const height = props.height.val || 24;
const width = props.width.val;
const summaryItems = props.items.val;
const label = props.label.val;
const label = props.label?.val;
const total = summaryItems.reduce((sum, item) => sum + item.value, 0);

Streamlit.setFrameHeight(height + 24 + (label ? 24 : 0));

if (!window.testgen.loadedStylesheets.summaryBar) {
document.adoptedStyleSheets.push(stylesheet);
window.testgen.loadedStylesheets.summaryBar = true;
}

return div(
{ class: 'tg-summary-bar-wrapper' },
() => {
Expand All @@ -62,7 +57,7 @@ const SummaryBar = (/** @type Properties */ props) => {
() => {
return total ? div(
{ class: `tg-summary-bar--caption` },
summaryItems.map(item => `${item.label}: ${item.value}`).join(', '),
summaryItems.map(item => `${item.label}: ${item.value || 0}`).join(', '),
) : null;
},
);
Expand Down
21 changes: 20 additions & 1 deletion testgen/ui/components/frontend/js/utils.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import van from './van.min.js';

function enforceElementWidth(
/** @type Element */element,
/** @type number */width,
Expand All @@ -9,4 +11,21 @@ function enforceElementWidth(
observer.observe(element);
}

export { enforceElementWidth };
function loadStylesheet(
/** @type string */key,
/** @type CSSStyleSheet */stylesheet,
) {
if (!window.testgen.loadedStylesheets[key]) {
document.adoptedStyleSheets.push(stylesheet);
window.testgen.loadedStylesheets[key] = true;
}
}

function wrapProps(/** @type object */props) {
for (const [key, value] of Object.entries(props)) {
props[key] = van.state(value);
}
return props;
}

export { enforceElementWidth, loadStylesheet, wrapProps };
2 changes: 1 addition & 1 deletion testgen/ui/components/widgets/breadcrumbs.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ def breadcrumbs(
props={"breadcrumbs": breadcrumbs},
)
if data:
Router().navigate(to=data["path"], with_args=data["params"])
Router().navigate(to=data["href"], with_args=data["params"])

class Breadcrumb(typing.TypedDict):
path: str | None
Expand Down

0 comments on commit f8e26f3

Please sign in to comment.