Skip to content

Commit

Permalink
Filterbar styling (#919)
Browse files Browse the repository at this point in the history
* improve the keyboards navigation in Toolbar

* fix form control styling, uennecessaryb layout rerenders, table resize bug

* make sure all table config setting changes are saved, style tweaks

* calculated columns

* fix dropdown width

* fix width of combo in SaveLayout Panel

* remove console.log

* fix bug in OverflowContainer when orientation vertical

* remove global error listener, leave this to cypress
  • Loading branch information
heswell authored Oct 22, 2023
1 parent f4255bd commit b96066d
Show file tree
Hide file tree
Showing 63 changed files with 948 additions and 520 deletions.
2 changes: 1 addition & 1 deletion vuu-ui/cypress/support/component/index.css

Large diffs are not rendered by default.

7 changes: 7 additions & 0 deletions vuu-ui/cypress/support/component/index.css.map

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions vuu-ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
"showcase:build": " cd showcase && node scripts/build.mjs",
"test:cypress": "cypress run --component --browser chrome --headless",
"test:cypress:local": "cypress open --component --browser chrome",
"test:cypress:e2e": "cypress run --browser chrome",
"test:vite": "vitest run",
"bump": "node ./scripts/version.mjs",
"pub": "node ./scripts/publish.mjs",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
.vuuFilterTable {
--vuuFilterBar-flex: 0 0 33px;
display: flex;
flex-direction: column;
}
5 changes: 3 additions & 2 deletions vuu-ui/packages/vuu-filters/src/filter-bar/FilterBar.css
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@

.vuuFilterBar {
--vuu-svg-tune: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M3 18C3 18.55 3.45 19 4 19H9V17H4C3.45 17 3 17.45 3 18ZM3 6C3 6.55 3.45 7 4 7H13V5H4C3.45 5 3 5.45 3 6ZM13 20V19H20C20.55 19 21 18.55 21 18C21 17.45 20.55 17 20 17H13V16C13 15.45 12.55 15 12 15C11.45 15 11 15.45 11 16V20C11 20.55 11.45 21 12 21C12.55 21 13 20.55 13 20ZM7 10V11H4C3.45 11 3 11.45 3 12C3 12.55 3.45 13 4 13H7V14C7 14.55 7.45 15 8 15C8.55 15 9 14.55 9 14V10C9 9.45 8.55 9 8 9C7.45 9 7 9.45 7 10ZM21 12C21 11.45 20.55 11 20 11H11V13H20C20.55 13 21 12.55 21 12ZM16 9C16.55 9 17 8.55 17 8V7H20C20.55 7 21 6.55 21 6C21 5.45 20.55 5 20 5H17V4C17 3.45 16.55 3 16 3C15.45 3 15 3.45 15 4V8C15 8.55 15.45 9 16 9Z" /></svg>');
--vuuToolbar-height: 26px;
--vuuToolbar-height: 28px;
--salt-container-primary-borderColor: var(--vuu-color-purple-10);
--vuuOverflowContainer-minWidth: 0;
--saltButton-height: 26px;
Expand All @@ -11,9 +11,10 @@
background-color: var(--salt-container-secondary-background);
border-bottom: solid 1px #D6D7DA;
display: flex;
flex: var(--vuuFilterBar-flex);
gap: 4px;
height: 33px;
padding: 3px 8px;
padding: 0px 8px;
}

.vuuFilterbar-icon {
Expand Down
6 changes: 5 additions & 1 deletion vuu-ui/packages/vuu-filters/src/filter-bar/FilterBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,14 @@ export const FilterBar = ({
const rootRef = useRef<HTMLDivElement>(null);
const {
activeFilterIndex,
addButtonProps,
editFilter,
filters,
onClickAddFilter,
onClickRemoveFilter,
onChangeFilterClause,
onChangeActiveFilterIndex,
onNavigateOutOfBounds,
onKeyDown,
onMenuAction,
pillProps,
Expand Down Expand Up @@ -122,14 +124,16 @@ export const FilterBar = ({
<span className={`${classBase}-icon`} data-icon="tune" />
<Toolbar
activeItemIndex={activeFilterIndex}
height={26}
height={28}
onActiveChange={onChangeActiveFilterIndex}
onNavigateOutOfBounds={onNavigateOutOfBounds}
selectionStrategy="multiple-special-key"
>
{getChildren()}
</Toolbar>
{editFilter === undefined ? (
<Button
{...addButtonProps}
className={`${classBase}-add`}
data-icon="plus"
data-selectable={false}
Expand Down
27 changes: 26 additions & 1 deletion vuu-ui/packages/vuu-filters/src/filter-bar/useFilterBar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,13 @@ import {
import { PromptProps } from "@finos/vuu-popups";
import { dispatchMouseEvent, filterAsQuery } from "@finos/vuu-utils";
import { EditableLabelProps } from "@salt-ds/lab";
import { ActiveItemChangeHandler } from "@finos/vuu-layout";
import {
ActiveItemChangeHandler,
NavigationOutOfBoundsHandler,
} from "@finos/vuu-layout";
import {
KeyboardEvent,
KeyboardEventHandler,
RefObject,
useCallback,
useEffect,
Expand Down Expand Up @@ -45,6 +49,7 @@ export const useFilterBar = ({
onFiltersChanged,
showMenu: showMenuProp,
}: FilterBarHookProps) => {
const addButtonRef = useRef<HTMLButtonElement>(null);
const editingFilter = useRef<Filter | undefined>();
const [activeFilterIndex, setActiveFilterIndex] =
useState<number[]>(activeFilterIdexProp);
Expand Down Expand Up @@ -342,8 +347,27 @@ export const useFilterBar = ({
[editFilter]
);

const handleAddButtonKeyDown = useCallback<KeyboardEventHandler>((evt) => {
if (evt.key === "ArrowLeft") {
console.log("navgiate to the Toolbar");
}
}, []);

const handlePillNavigationOutOfBounds =
useCallback<NavigationOutOfBoundsHandler>((direction) => {
if (direction === "end") {
addButtonRef.current?.focus();
}
}, []);

const addButtonProps = {
ref: addButtonRef,
onKeyDown: handleAddButtonKeyDown,
};

return {
activeFilterIndex,
addButtonProps,
editFilter,
filters,
onChangeActiveFilterIndex: handleChangeActiveFilterIndex,
Expand All @@ -352,6 +376,7 @@ export const useFilterBar = ({
onChangeFilterClause: handleChangeFilterClause,
onKeyDown,
onMenuAction: handleMenuAction,
onNavigateOutOfBounds: handlePillNavigationOutOfBounds,
pillProps,
promptProps,
showMenu,
Expand Down
7 changes: 5 additions & 2 deletions vuu-ui/packages/vuu-filters/src/filter-pill/FilterPill.css
Original file line number Diff line number Diff line change
@@ -1,19 +1,21 @@
.vuuFilterPill {
--vuuToolbarItem-outlineColor: white;
align-items: center;
background: var(--salt-taggable-background);
border: solid 1px var(--salt-taggable-foreground);
border-radius: 26px;
color: var(--vuu-color-gray-50);
display: inline-flex;
height: 26px;
max-width: var(--vuuFilterPill-maxWidth, 200px);
padding: 0 8px;
position: relative;
user-select: none;
outline: none;
}

.vuuFilterPill.vuuToolbarItem {
height: 26px;
}

.vuuFilterPill[aria-selected="true"]{
--vuuPopupMenu-iconColor: white;
--salt-text-background-selected: var(--vuu-color-blue-40);
Expand All @@ -30,3 +32,4 @@
border-color: var(--salt-taggable-background-hover);
color: var(--vuu-color-gray-80);
}

Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,21 @@ describe("WHEN it initially renders, with enough space for all items", () => {
cy.mount(<TestFixtureSimpleOverflowContainer width={700} />);
const container = cy.findByTestId("overflow-container");
container.should("have.class", "vuuOverflowContainer");
container.should("not.have.class", "overflowed");
// cy.get(".saltTabstrip-inner > *")
// .should("have.length", 5)
// .filter(":visible")
// .should("have.length", 5);
container.should(
"not.have.class",
"vuuOverflowContainer-wrapContainer-overflowed"
);
});
});

describe("WHEN it initially renders, with space for all but one items", () => {
it("THEN all but one items will be visible, one will be marked as wrapped and overflow Indicator will be visible", () => {
cy.mount(<TestFixtureSimpleOverflowContainer width={600} />);
const container = cy.findByTestId("overflow-container");
const wrapContainer = container.children().first();
wrapContainer.should(
"have.class",
"vuuOverflowContainer-wrapContainer-overflowed"
);
});
// it("THEN no items will be overflowed", () => {
// cy.mount(<DefaultTabstrip width={400} />);
// cy.get(OVERFLOWED_ITEMS).should("have.length", 0);
// });
// it("THEN no overflow indicator will be present", () => {
// cy.mount(<DefaultTabstrip width={400} />);
// cy.get(OVERFLOW_IND).should("have.length", 0);
// });
});
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,17 @@ const metadataSaveLocation = "layouts/metadata";
const layoutsSaveLocation = "layouts/layouts";

export class LocalLayoutPersistenceManager implements LayoutPersistenceManager {
createLayout(metadata: Omit<LayoutMetadata, "id">, layout: LayoutJSON): Promise<string> {
return new Promise(resolve => {
console.log(`Saving layout as ${metadata.name} to group ${metadata.group}...`);
createLayout(
metadata: Omit<LayoutMetadata, "id">,
layout: LayoutJSON
): Promise<string> {
return new Promise((resolve) => {
console.log(
`Saving layout as ${metadata.name} to group ${metadata.group}...`
);

Promise.all([this.loadLayouts(), this.loadMetadata()])
.then(([existingLayouts, existingMetadata]) => {
Promise.all([this.loadLayouts(), this.loadMetadata()]).then(
([existingLayouts, existingMetadata]) => {
const id = getUniqueId();
this.appendAndPersist(
id,
Expand All @@ -24,8 +29,9 @@ export class LocalLayoutPersistenceManager implements LayoutPersistenceManager {
existingMetadata
);
resolve(id);
});
})
}
);
});
}

updateLayout(
Expand All @@ -37,12 +43,14 @@ export class LocalLayoutPersistenceManager implements LayoutPersistenceManager {
this.validateIds(id)
.then(() => Promise.all([this.loadLayouts(), this.loadMetadata()]))
.then(([existingLayouts, existingMetadata]) => {
const layouts = existingLayouts.filter(layout => layout.id !== id);
const metadata = existingMetadata.filter(metadata => metadata.id !== id);
const layouts = existingLayouts.filter((layout) => layout.id !== id);
const metadata = existingMetadata.filter(
(metadata) => metadata.id !== id
);
this.appendAndPersist(id, newMetadata, newLayout, layouts, metadata);
resolve();
})
.catch(e => reject(e));
.catch((e) => reject(e));
});
}

Expand All @@ -51,24 +59,28 @@ export class LocalLayoutPersistenceManager implements LayoutPersistenceManager {
this.validateIds(id)
.then(() => Promise.all([this.loadLayouts(), this.loadMetadata()]))
.then(([existingLayouts, existingMetadata]) => {
const layouts = existingLayouts.filter(layout => layout.id !== id);
const metadata = existingMetadata.filter(metadata => metadata.id !== id);
const layouts = existingLayouts.filter((layout) => layout.id !== id);
const metadata = existingMetadata.filter(
(metadata) => metadata.id !== id
);
this.saveLayoutsWithMetadata(layouts, metadata);
resolve();
})
.catch(e => reject(e));
.catch((e) => reject(e));
});
}

loadLayout(id: string): Promise<LayoutJSON> {
return new Promise((resolve, reject) => {
this.validateId(id, "layout")
.then(() => this.loadLayouts())
.then(existingLayouts => {
const layouts = existingLayouts.find(layout => layout.id === id) as Layout;
.then((existingLayouts) => {
const layouts = existingLayouts.find(
(layout) => layout.id === id
) as Layout;
resolve(layouts.json);
})
.catch(e => reject(e));
.catch((e) => reject(e));
});
}

Expand All @@ -80,11 +92,14 @@ export class LocalLayoutPersistenceManager implements LayoutPersistenceManager {
}

loadApplicationLayout(): Promise<LayoutJSON> {
console.log("loadApplicationLAyout");
return new Promise((resolve) => {
const applicationLayout = getLocalEntity<LayoutJSON>("api/vui");
if (applicationLayout) {
console.log(applicationLayout);
resolve(applicationLayout);
} else {
console.log(defaultLayout);
resolve(defaultLayout);
}
});
Expand All @@ -102,7 +117,7 @@ export class LocalLayoutPersistenceManager implements LayoutPersistenceManager {
}

private loadLayouts(): Promise<Layout[]> {
return new Promise(resolve => {
return new Promise((resolve) => {
const layouts = getLocalEntity<Layout[]>(layoutsSaveLocation);
resolve(layouts || []);
});
Expand Down Expand Up @@ -132,29 +147,33 @@ export class LocalLayoutPersistenceManager implements LayoutPersistenceManager {
// Ensures that there is exactly one Layout entry and exactly one Metadata
// entry in local storage corresponding to the provided ID.
private async validateIds(id: string): Promise<void> {
return Promise
.all([
this.validateId(id, "metadata").catch(error => error.message),
this.validateId(id, "layout").catch(error => error.message)
])
.then((errorMessages: string[]) => {
// filter() is used to remove any blank messages before joining.
// Avoids orphaned delimiters in combined messages, e.g. "; " or "; error 2"
const combinedMessage = errorMessages.filter(msg => msg !== undefined).join("; ");
if (combinedMessage) {
throw new Error(combinedMessage);
}
});
return Promise.all([
this.validateId(id, "metadata").catch((error) => error.message),
this.validateId(id, "layout").catch((error) => error.message),
]).then((errorMessages: string[]) => {
// filter() is used to remove any blank messages before joining.
// Avoids orphaned delimiters in combined messages, e.g. "; " or "; error 2"
const combinedMessage = errorMessages
.filter((msg) => msg !== undefined)
.join("; ");
if (combinedMessage) {
throw new Error(combinedMessage);
}
});
}

// Ensures that there is exactly one element (Layout or Metadata) in local
// storage corresponding to the provided ID.
private validateId(id: string, dataType: "metadata" | "layout"): Promise<void> {
private validateId(
id: string,
dataType: "metadata" | "layout"
): Promise<void> {
return new Promise((resolve, reject) => {
const loadFunc = dataType === "metadata" ? this.loadMetadata : this.loadLayouts;
const loadFunc =
dataType === "metadata" ? this.loadMetadata : this.loadLayouts;

loadFunc().then((array: WithId[]) => {
const count = array.filter(element => element.id === id).length;
const count = array.filter((element) => element.id === id).length;
switch (count) {
case 1: {
resolve();
Expand All @@ -164,9 +183,10 @@ export class LocalLayoutPersistenceManager implements LayoutPersistenceManager {
reject(new Error(`No ${dataType} with ID ${id}`));
break;
}
default: reject(new Error(`Non-unique ${dataType} with ID ${id}`));
default:
reject(new Error(`Non-unique ${dataType} with ID ${id}`));
}
});
})
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ export const useLayoutContextMenuItems = () => {
>(() => {
return [
(location, options) => {
console.log({ options });
const locations = location.split(" ");
const menuDescriptors: ContextMenuItemDescriptor[] = [];
if (locations.includes("main-tab")) {
Expand Down
Loading

0 comments on commit b96066d

Please sign in to comment.