Skip to content

Commit

Permalink
Merge branch 'main' into fix-dropdown
Browse files Browse the repository at this point in the history
  • Loading branch information
Kelsie Besinger Yeh committed May 15, 2024
2 parents db1834c + 62bf485 commit 6e92f75
Show file tree
Hide file tree
Showing 15 changed files with 152 additions and 47 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@homebound/beam",
"version": "2.343.1",
"version": "2.344.2",
"author": "Homebound",
"license": "MIT",
"main": "dist/index.js",
Expand Down
2 changes: 2 additions & 0 deletions src/components/Icon.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ export const Icon = (props: IconProps) => {
"checkCircleFilled",
"loaderCircle",
"circleOutline",
"time",
];
const arrowIcons: IconProps["icon"][] = [
"chevronsDown",
Expand Down Expand Up @@ -154,6 +155,7 @@ export const Icon = (props: IconProps) => {
"designPackage",
"updateDesignPackage",
"exteriorStyle",
"lockOpen",
];
const navigationIcons: IconProps["icon"][] = [
"projects",
Expand Down
9 changes: 9 additions & 0 deletions src/components/Icon.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -813,6 +813,15 @@ export const Icons = {
fillRule="evenodd"
/>
),
time: (
<>
<path d="M12 2C6.486 2 2 6.486 2 12C2 17.514 6.486 22 12 22C17.514 22 22 17.514 22 12C22 6.486 17.514 2 12 2ZM12 20C7.589 20 4 16.411 4 12C4 7.589 7.589 4 12 4C16.411 4 20 7.589 20 12C20 16.411 16.411 20 12 20Z" />
<path d="M13 7H11V13H17V11H13V7Z" />
</>
),
lockOpen: (
<path d="M17 8V7C17 4.243 14.757 2 12 2C9.243 2 7 4.243 7 7V10H6C4.897 10 4 10.897 4 12V20C4 21.103 4.897 22 6 22H18C19.103 22 20 21.103 20 20V12C20 10.897 19.103 10 18 10H9V7C9 5.346 10.346 4 12 4C13.654 4 15 5.346 15 7V8H17ZM18 12L18.002 20H6V12H18Z" />
),
};

export type IconKey = keyof typeof Icons;
8 changes: 7 additions & 1 deletion src/components/Label.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,13 @@ function LabelComponent<X extends Only<Xss<LabelXss>, X>>(props: LabelProps<X>)
<label
{...labelProps}
{...others}
css={{ ...Css.dif.aic.gap1.sm.gray700.mbPx(inline ? 0 : 4).if(contrast).white.$, ...xss }}
css={{
...Css.dif.aic.gap1.sm.gray700
.mbPx(inline ? 0 : 4)
.if(contrast)
.white.if(!inline).asfs.$,
...xss,
}}
>
{label}
{suffix && ` ${suffix}`}
Expand Down
58 changes: 54 additions & 4 deletions src/components/Table/GridTable.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
condensedStyle,
dateColumn,
defaultStyle,
dragHandleColumn,
emptyCell,
GridCellAlignment,
GridColumn,
Expand All @@ -21,15 +22,14 @@ import {
GridTable,
Icon,
IconButton,
insertAtIndex,
numericColumn,
recursivelyGetContainingRow,
RowStyles,
selectColumn,
simpleHeader,
SimpleHeaderAndData,
useGridTableApi,
insertAtIndex,
dragHandleColumn,
recursivelyGetContainingRow,
} from "src/components/index";
import { Css, Palette } from "src/Css";
import { useComputed } from "src/hooks";
Expand Down Expand Up @@ -298,7 +298,17 @@ export function InfiniteScrollWithLoader() {
export function NoRowsFallback() {
const nameColumn: GridColumn<Row> = { header: "Name", data: ({ name }) => name };
const valueColumn: GridColumn<Row> = { header: "Value", data: ({ value }) => value };
return <GridTable columns={[nameColumn, valueColumn]} rows={[simpleHeader]} fallbackMessage="There were no rows." />;
return (
<div css={Css.wPx(500).hPx(500).$}>
<GridTable
columns={[nameColumn, valueColumn]}
as={"virtual"}
style={{ bordered: true, allWhite: true }}
rows={[simpleHeader]}
fallbackMessage="There were no rows."
/>
</div>
);
}

// Make a `Row` ADT for a table with a header + 3 levels of nesting
Expand Down Expand Up @@ -2065,3 +2075,43 @@ export function DraggableCardRows() {
/>
);
}

export function MinColumnWidths() {
const nameColumn: GridColumn<Row> = {
header: "Name",
data: ({ name }) => ({
content: name === "group" ? "Col-spans across all!" : `Width: 2fr; Min-width: 300px`,
colspan: name === "group" ? 3 : 1,
}),
w: 2,
mw: "300px",
};
const valueColumn: GridColumn<Row> = {
id: "value",
header: "Value",
data: ({ value }) => `Width: 1fr; Min-width: 200px`,
w: 1,
mw: "200px",
};
const actionColumn: GridColumn<Row> = {
header: "Action",
data: () => `Width: 1fr; Min-width: 150px`,
w: 1,
mw: "150px",
};
return (
<div css={Css.mx2.$}>
<GridTable
columns={[nameColumn, valueColumn, actionColumn]}
style={{ bordered: true, allWhite: true }}
rows={[
simpleHeader,
{ kind: "data", id: "group", data: { name: "group", value: 0 } },
{ kind: "data", id: "1", data: { name: "c", value: 1 } },
{ kind: "data", id: "2", data: { name: "B", value: 2 } },
{ kind: "data", id: "3", data: { name: "a", value: 3 } },
]}
/>
</div>
);
}
15 changes: 2 additions & 13 deletions src/components/Table/GridTable.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -953,7 +953,7 @@ describe("GridTable", () => {
});
});

it("throws error if column min-width definition is set with a non-px/percentage value", async () => {
it("throws error if column min-width definition is set with a non-px value", async () => {
// Given a column with an invalid `mw` value, then the render will fail
await expect(
render(
Expand All @@ -962,7 +962,7 @@ describe("GridTable", () => {
rows={[simpleHeader, { kind: "data", id: "1", data: { name: "a", value: 3 } }]}
/>,
),
).rejects.toThrow("Beam Table column min-width definition only supports px or percentage values");
).rejects.toThrow("Beam Table column minWidth definition only supports pixel units");
});

it("accepts pixel values for column min-width definition", async () => {
Expand All @@ -976,17 +976,6 @@ describe("GridTable", () => {
expect(r.gridTable).toBeTruthy();
});

it("accepts percentage values for column min-width definition", async () => {
// Given a column with an valid `mw` percentage value, then the render will succeed.
const r = await render(
<GridTable
columns={[{ header: () => "Name", data: "Test", mw: "100%" }]}
rows={[simpleHeader, { kind: "data", id: "1", data: { name: "a", value: 3 } }]}
/>,
);
expect(r.gridTable).toBeTruthy();
});

it("can handle onClick for rows", async () => {
const onClick = jest.fn();
const rowStyles: RowStyles<Row> = { header: {}, data: { onClick } };
Expand Down
11 changes: 5 additions & 6 deletions src/components/Table/GridTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import memoizeOne from "memoize-one";
import { runInAction } from "mobx";
import React, { MutableRefObject, ReactElement, useEffect, useMemo, useRef, useState } from "react";
import { Components, Virtuoso, VirtuosoHandle } from "react-virtuoso";
import { Loader } from "src/components";
import { getTableRefWidthStyles, Loader } from "src/components";
import { DiscriminateUnion, GridRowKind } from "src/components/index";
import { PresentationFieldProps, PresentationProvider } from "src/components/PresentationContext";
import { GridTableApi, GridTableApiImpl } from "src/components/Table/GridTableApi";
Expand All @@ -20,7 +20,7 @@ import {
import { assignDefaultColumnIds } from "src/components/Table/utils/columns";
import { GridRowLookup } from "src/components/Table/utils/GridRowLookup";
import { TableStateContext } from "src/components/Table/utils/TableState";
import { EXPANDABLE_HEADER, KEPT_GROUP, isCursorBelowMidpoint, zIndices } from "src/components/Table/utils/utils";
import { EXPANDABLE_HEADER, isCursorBelowMidpoint, KEPT_GROUP, zIndices } from "src/components/Table/utils/utils";
import { Css, Only } from "src/Css";
import { useComputed } from "src/hooks";
import { useRenderCount } from "src/hooks/useRenderCount";
Expand Down Expand Up @@ -484,9 +484,7 @@ export function GridTable<R extends Kinded, X extends Only<GridTableXss, X> = an
return (
<TableStateContext.Provider value={rowStateContext}>
<PresentationProvider fieldProps={fieldProps} wrap={style?.presentationSettings?.wrap}>
{/* If virtualized take some pixels off the width to accommodate when virtuoso's scrollbar is introduced. */}
{/* Otherwise a horizontal scrollbar will _always_ appear once the vertical scrollbar is needed */}
<div ref={resizeRef} css={Css.w100.if(as === "virtual").w("calc(100% - 20px)").$} />
<div ref={resizeRef} css={getTableRefWidthStyles(as === "virtual")} />
{renders[_as](
style,
id,
Expand Down Expand Up @@ -713,7 +711,8 @@ function renderVirtual<R extends Kinded>(
if (firstRowMessage) {
if (index === 0) {
return (
<div css={Css.add("gridColumn", `${columns.length} span`).$}>
// Ensure the fallback message is the same width as the table
<div css={getTableRefWidthStyles(true)}>
<div css={{ ...style.firstRowMessageCss }}>{firstRowMessage}</div>
</div>
);
Expand Down
10 changes: 1 addition & 9 deletions src/components/Table/components/Row.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { observer } from "mobx-react";
import { ReactElement, useContext, useRef, useCallback, RefObject } from "react";
import { ReactElement, useCallback, useContext, useRef } from "react";
import {
defaultRenderFn,
headerRenderFn,
Expand Down Expand Up @@ -176,13 +176,6 @@ function RowImpl<R extends Kinded, S>(props: RowProps<R>): ReactElement {
const applyFirstContentColumnStyles = !isHeader && isFirstContentColumn;
foundFirstContentColumn ||= applyFirstContentColumnStyles;

if (column.mw) {
// Validate the column's minWidth definition if set.
if (!column.mw.endsWith("px") && !column.mw.endsWith("%")) {
throw new Error("Beam Table column min-width definition only supports px or percentage values");
}
}

// When using the variation of the table with an EXPANDABLE_HEADER, then our HEADER and TOTAL rows have special border styling
// Keep track of the when we get to the last expanded column so we can apply this styling properly.
if (hasExpandableHeader && (isHeader || isTotals)) {
Expand Down Expand Up @@ -333,7 +326,6 @@ function RowImpl<R extends Kinded, S>(props: RowProps<R>): ReactElement {
width: `calc(${columnSizes.slice(columnIndex, columnIndex + currentColspan).join(" + ")}${
applyFirstContentColumnStyles && levelIndent ? ` - ${levelIndent}px` : ""
})`,
...(typeof column.mw === "string" ? Css.mw(column.mw).$ : {}),
};

const cellClassNames = revealOnRowHover ? revealOnRowHoverClass : undefined;
Expand Down
2 changes: 1 addition & 1 deletion src/components/Table/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ export type GridColumn<R extends Kinded> = {
* Example: Collapsed state shows number of books. Expanded state shows titles of books.
*/
expandedWidth?: number | string;
/** The minimum width the column can shrink to */
/** The minimum width the column can shrink to. This must be defined in pixels */
mw?: string;
/** The column's default alignment for each cell. */
align?: GridCellAlignment;
Expand Down
54 changes: 47 additions & 7 deletions src/components/Table/utils/columns.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { GridColumn, GridColumnWithId, Kinded, nonKindGridColumnKeys } from "src
import { DragData, emptyCell } from "src/components/Table/utils/utils";
import { isFunction, newMethodMissingProxy } from "src/utils";
import { Icon } from "src";
import { Css, Palette } from "src/Css";
import { Css } from "src/Css";

/** Provides default styling for a GridColumn representing a Date. */
export function column<T extends Kinded>(columnDef: GridColumn<T>): GridColumn<T> {
Expand Down Expand Up @@ -135,32 +135,62 @@ export function calcColumnSizes<R extends Kinded>(
{ claimedPercentages: 0, claimedPixels: 0, totalFr: 0 },
);

// In the event a column defines a fractional unit (fr) as the `w` value and a `mw` value in pixels,
// it is possible that the min-width value will kick in and throw off our claimedPixel and totalFr calculations.
// Once a `tableWidth` is defined, then we can adjust the claimedPixels and totalFr based on minWidth being present for any columns
let adjustedClaimedPixels = claimedPixels;
let adjustedTotalFr = totalFr;
if (tableWidth) {
columns.forEach(({ w, mw }) => {
const frUnit = parseFr(w);
if (mw === undefined || frUnit === undefined) return;

const mwPx = Number(mw.replace("px", ""));
const calcedWidth =
(tableWidth - (claimedPercentages / 100) * tableWidth - adjustedClaimedPixels) * (frUnit / adjustedTotalFr);
// If the calculated width is less than the minWidth, then this column will be sized via pixels instead of `fr` units.
if (calcedWidth < mwPx) {
// Adjust the claimedPixels and totalFr accordingly
adjustedClaimedPixels += mwPx;
adjustedTotalFr -= frUnit;
}
});
}

// This is our "fake but for some reason it lines up better" fr calc
function fr(myFr: number): string {
function fr(myFr: number, mw: number): string {
// If the tableWidth, then return a pixel value
if (tableWidth) {
const widthBasis = Math.max(tableWidth, tableMinWidthPx);
return `(${(widthBasis - (claimedPercentages / 100) * widthBasis - claimedPixels) * (myFr / totalFr)}px)`;
const calcedWidth =
(widthBasis - (claimedPercentages / 100) * widthBasis - adjustedClaimedPixels) * (myFr / adjustedTotalFr);

return `${Math.max(calcedWidth, mw)}px`;
}
// Otherwise return the `calc()` value
return `((100% - ${claimedPercentages}% - ${claimedPixels}px) * (${myFr} / ${totalFr}))`;
}

const sizes = columns.map(({ id, expandedWidth, w: _w }) => {
const sizes = columns.map(({ id, expandedWidth, w: _w, mw: _mw }) => {
// Ensure `mw` is a pixel value if defined
if (_mw !== undefined && !_mw.endsWith("px")) {
throw new Error("Beam Table column minWidth definition only supports pixel units");
}
const mw = _mw ? Number(_mw.replace("px", "")) : 0;
const w = expandedColumnIds.includes(id) && expandedWidth !== undefined ? expandedWidth : _w;

if (typeof w === "undefined") {
return fr(1);
return fr(1, mw);
} else if (typeof w === "string") {
if (w.endsWith("%") || w.endsWith("px")) {
return w;
} else if (w.endsWith("fr")) {
return fr(Number(w.replace("fr", "")));
return fr(Number(w.replace("fr", "")), mw);
} else {
throw new Error("Beam Table column width definition only supports px, percentage, or fr units");
}
} else {
return fr(w);
return fr(w, mw);
}
});

Expand Down Expand Up @@ -237,3 +267,13 @@ export function dragHandleColumn<T extends Kinded>(columnDef?: Partial<GridColum
};
}) as any;
}

function parseFr(w: string | number | undefined): number | undefined {
return typeof w === "number"
? w
: typeof w === "undefined"
? 1
: typeof w === "string" && w.endsWith("fr")
? Number(w.replace("fr", ""))
: undefined;
}
6 changes: 6 additions & 0 deletions src/components/Table/utils/utils.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -301,3 +301,9 @@ export function recursivelyGetContainingRow<R extends Kinded>(

return undefined;
}

export function getTableRefWidthStyles(isVirtual: boolean) {
// If virtualized take some pixels off the width to accommodate when virtuoso's scrollbar is introduced.
// Otherwise a horizontal scrollbar will _always_ appear once the vertical scrollbar is needed
return Css.w100.if(isVirtual).w("calc(100% - 20px)").$;
}
3 changes: 2 additions & 1 deletion src/components/Tooltip.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,8 @@ export function Tooltip(props: TooltipProps) {
{...(!state.isOpen && typeof title === "string" ? { title } : {})}
{...tid}
// Add display contents to prevent the tooltip wrapping element from short-circuiting inherited styles (i.e. flex item positioning)
css={Css.display("contents").$}
// Once the element is `:active`, allow pointer events (i.e. click events) to pass through to the children.
css={Css.display("contents").addIn(":active", Css.add("pointerEvents", "none").$).$}
// Adding `draggable` as a hack to allow focus to continue through this element and into its children.
// This is due to some code in React-Aria that prevents default due ot mobile browser inconsistencies,
// and the only way they don't prevent default is if the element is draggable.
Expand Down
1 change: 1 addition & 0 deletions src/inputs/TextFieldBase.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,7 @@ export function TextFieldBase<X, O>(props: TextFieldBaseProps<X, O>) {
labelProps={labelProps}
hidden={labelStyle === "hidden" || compound}
label={label}
inline={labelStyle !== "above"}
suffix={labelSuffix}
contrast={contrast}
{...tid.label}
Expand Down
2 changes: 1 addition & 1 deletion src/inputs/ToggleChipGroup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ export function ToggleChipGroup(props: ToggleChipGroupProps) {

return (
<div {...groupProps} css={Css.relative.df.fdc.if(labelStyle === "left").fdr.maxw100.$}>
<Label label={label} {...labelProps} hidden={hideLabel} />
<Label label={label} {...labelProps} hidden={hideLabel} inline={labelStyle === "left"} />
<div css={Css.df.gap1.add("flexWrap", "wrap").if(labelStyle === "left").ml2.$}>
{options.map((o) => (
<ToggleChip
Expand Down
Loading

0 comments on commit 6e92f75

Please sign in to comment.