@homebound/beam 2.108.0 → 2.111.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -12,6 +12,8 @@ export interface IconButtonProps extends BeamButtonProps, BeamFocusableProps {
12
12
  /** HTML attributes to apply to the button element when it is being used to trigger a menu. */
13
13
  menuTriggerProps?: AriaButtonProps;
14
14
  buttonRef?: RefObject<HTMLButtonElement>;
15
+ /** Whether to show a 16x16px version of the IconButton */
16
+ compact?: boolean;
15
17
  }
16
18
  export declare function IconButton(props: IconButtonProps): import("@emotion/react/jsx-runtime").JSX.Element;
17
19
  export declare const iconButtonStylesHover: {
@@ -10,7 +10,7 @@ const Css_1 = require("../Css");
10
10
  const utils_1 = require("../utils");
11
11
  const useTestIds_1 = require("../utils/useTestIds");
12
12
  function IconButton(props) {
13
- const { onClick: onPress, disabled, color, icon, autoFocus, inc, buttonRef, tooltip, menuTriggerProps, openInNew, } = props;
13
+ const { onClick: onPress, disabled, color, icon, autoFocus, inc, buttonRef, tooltip, menuTriggerProps, openInNew, compact = false, } = props;
14
14
  const isDisabled = !!disabled;
15
15
  const ariaProps = { onPress, isDisabled, autoFocus, ...menuTriggerProps };
16
16
  // eslint-disable-next-line react-hooks/rules-of-hooks
@@ -25,12 +25,13 @@ function IconButton(props) {
25
25
  const testIds = (0, useTestIds_1.useTestIds)(props, icon);
26
26
  const styles = (0, react_1.useMemo)(() => ({
27
27
  ...iconButtonStylesReset,
28
+ ...(compact ? iconButtonCompact : iconButtonNormal),
28
29
  ...(isHovered && exports.iconButtonStylesHover),
29
30
  ...(isFocusVisible && iconButtonStylesFocus),
30
31
  ...(isDisabled && iconButtonStylesDisabled),
31
- }), [isHovered, isFocusVisible, isDisabled]);
32
+ }), [isHovered, isFocusVisible, isDisabled, compact]);
32
33
  const buttonAttrs = { ...testIds, ...buttonProps, ...focusProps, ...hoverProps, ref: ref, css: styles };
33
- const buttonContent = ((0, jsx_runtime_1.jsx)(components_1.Icon, { icon: icon, color: color || (isDisabled ? Css_1.Palette.Gray400 : Css_1.Palette.Gray900), inc: inc }, void 0));
34
+ const buttonContent = ((0, jsx_runtime_1.jsx)(components_1.Icon, { icon: icon, color: color || (isDisabled ? Css_1.Palette.Gray400 : Css_1.Palette.Gray900), inc: compact ? 2 : inc }, void 0));
34
35
  const button = typeof onPress === "string" ? ((0, utils_1.isAbsoluteUrl)(onPress) || openInNew ? ((0, jsx_runtime_1.jsx)("a", Object.assign({}, buttonAttrs, { href: onPress, className: components_1.navLink, target: "_blank", rel: "noreferrer noopener" }, { children: buttonContent }), void 0)) : ((0, jsx_runtime_1.jsx)(react_router_dom_1.Link, Object.assign({}, buttonAttrs, { to: onPress, className: components_1.navLink }, { children: buttonContent }), void 0))) : ((0, jsx_runtime_1.jsx)("button", Object.assign({}, buttonAttrs, { children: buttonContent }), void 0));
35
36
  // If we're disabled b/c of a non-boolean ReactNode, or the caller specified tooltip text, then show it in a tooltip
36
37
  return (0, components_1.maybeTooltip)({
@@ -40,7 +41,9 @@ function IconButton(props) {
40
41
  });
41
42
  }
42
43
  exports.IconButton = IconButton;
43
- const iconButtonStylesReset = Css_1.Css.hPx(28).wPx(28).br8.bTransparent.bsSolid.bw2.bgTransparent.cursorPointer.outline0.p0.dif.aic.jcc.transition.$;
44
+ const iconButtonStylesReset = Css_1.Css.bTransparent.bsSolid.bgTransparent.cursorPointer.outline0.dif.aic.jcc.transition.$;
45
+ const iconButtonNormal = Css_1.Css.hPx(28).wPx(28).br8.bw2.$;
46
+ const iconButtonCompact = Css_1.Css.hPx(18).wPx(18).br4.bw1.$;
44
47
  exports.iconButtonStylesHover = Css_1.Css.bgGray200.$;
45
48
  const iconButtonStylesFocus = Css_1.Css.bLightBlue700.$;
46
49
  const iconButtonStylesDisabled = Css_1.Css.cursorNotAllowed.$;
@@ -21,6 +21,8 @@ export interface ModalProps {
21
21
  onClose?: Callback;
22
22
  /** Imperative API for interacting with the Modal */
23
23
  api?: MutableRefObject<ModalApi | undefined>;
24
+ /** Adds a border for the header. */
25
+ drawHeaderBorder?: boolean;
24
26
  }
25
27
  export declare type ModalApi = {
26
28
  setSize: (size: ModalProps["size"]) => void;
@@ -20,7 +20,7 @@ const utils_1 = require("../../utils");
20
20
  * Provides underlay, modal container, and header. Will disable scrolling of page under the modal.
21
21
  */
22
22
  function Modal(props) {
23
- const { size = "md", content, forceScrolling, api } = props;
23
+ const { size = "md", content, forceScrolling, api, drawHeaderBorder = false } = props;
24
24
  const isFixedHeight = typeof size !== "string";
25
25
  const ref = (0, react_1.useRef)(null);
26
26
  const { modalBodyDiv, modalFooterDiv, modalHeaderDiv, drawerContentStack } = (0, BeamContext_1.useBeamContext)();
@@ -69,7 +69,7 @@ function Modal(props) {
69
69
  .df.fdc.wPx(width)
70
70
  .mh((0, Css_1.px)(defaultMinHeight))
71
71
  .if(isFixedHeight)
72
- .hPx(height).$, ref: ref }, overlayProps, dialogProps, modalProps, testId, { children: [(0, jsx_runtime_1.jsxs)("header", Object.assign({ css: Css_1.Css.df.p3.fs0.$ }, { children: [(0, jsx_runtime_1.jsx)("h1", Object.assign({ css: Css_1.Css.fg1.xl2Em.gray900.$, ref: modalHeaderRef }, titleProps, testId.title), void 0), (0, jsx_runtime_1.jsx)("span", Object.assign({ css: Css_1.Css.fs0.pl1.$ }, { children: (0, jsx_runtime_1.jsx)(IconButton_1.IconButton, Object.assign({ icon: "x", onClick: closeModal }, testId.titleClose), void 0) }), void 0)] }), void 0), (0, jsx_runtime_1.jsxs)("main", Object.assign({ ref: contentRef, css: Css_1.Css.fg1.overflowYAuto.if(hasScroll).bb.bGray200.if(!!forceScrolling).overflowYScroll.$ }, { children: [content, (0, jsx_runtime_1.jsx)("div", { ref: modalBodyRef }, void 0)] }), void 0), (0, jsx_runtime_1.jsx)("footer", Object.assign({ css: Css_1.Css.fs0.$ }, { children: (0, jsx_runtime_1.jsx)("div", { ref: modalFooterRef }, void 0) }), void 0)] }), void 0) }), void 0) }), void 0) }, void 0));
72
+ .hPx(height).$, ref: ref }, overlayProps, dialogProps, modalProps, testId, { children: [(0, jsx_runtime_1.jsxs)("header", Object.assign({ css: Css_1.Css.df.p3.fs0.if(drawHeaderBorder).bb.bGray200.$ }, { children: [(0, jsx_runtime_1.jsx)("h1", Object.assign({ css: Css_1.Css.fg1.xl2Em.gray900.$, ref: modalHeaderRef }, titleProps, testId.title), void 0), (0, jsx_runtime_1.jsx)("span", Object.assign({ css: Css_1.Css.fs0.pl1.$ }, { children: (0, jsx_runtime_1.jsx)(IconButton_1.IconButton, Object.assign({ icon: "x", onClick: closeModal }, testId.titleClose), void 0) }), void 0)] }), void 0), (0, jsx_runtime_1.jsxs)("main", Object.assign({ ref: contentRef, css: Css_1.Css.fg1.overflowYAuto.if(hasScroll).bb.bGray200.if(!!forceScrolling).overflowYScroll.$ }, { children: [content, (0, jsx_runtime_1.jsx)("div", { ref: modalBodyRef }, void 0)] }), void 0), (0, jsx_runtime_1.jsx)("footer", Object.assign({ css: Css_1.Css.fs0.$ }, { children: (0, jsx_runtime_1.jsx)("div", { ref: modalFooterRef }, void 0) }), void 0)] }), void 0) }), void 0) }), void 0) }, void 0));
73
73
  }
74
74
  exports.Modal = Modal;
75
75
  function ModalHeader({ children }) {
@@ -42,6 +42,7 @@ const useSortState_1 = require("./useSortState");
42
42
  const visitor_1 = require("./visitor");
43
43
  const Css_1 = require("../../Css");
44
44
  const hooks_1 = require("../../hooks");
45
+ const useRenderCount_1 = require("../../hooks/useRenderCount");
45
46
  const tinycolor2_1 = __importDefault(require("tinycolor2"));
46
47
  const _1 = require(".");
47
48
  exports.ASC = "ASC";
@@ -109,6 +110,11 @@ function GridTable(props) {
109
110
  },
110
111
  };
111
112
  }
113
+ // We track render count at the table level, which seems odd (we should be able to track this
114
+ // internally within each GridRow using a useRef), but we have suspicions that react-virtuoso
115
+ // (or us) is resetting component state more than necessary, so we track render counts from
116
+ // here instead.
117
+ const { getCount } = (0, useRenderCount_1.useRenderCount)();
112
118
  const [sortState, setSortKey] = (0, useSortState_1.useSortState)(columns, sorting);
113
119
  const maybeSorted = (0, react_1.useMemo)(() => {
114
120
  if ((sorting === null || sorting === void 0 ? void 0 : sorting.on) === "client" && sortState) {
@@ -140,6 +146,7 @@ function GridTable(props) {
140
146
  openCards: nestedCards ? nestedCards.currentOpenCards() : undefined,
141
147
  columnSizes,
142
148
  level,
149
+ getCount,
143
150
  ...sortProps,
144
151
  }), `${row.kind}-${row.id}`));
145
152
  }
@@ -445,7 +452,7 @@ function getFirstOrLastCellCss(style, columnIndex, columns) {
445
452
  }
446
453
  // We extract GridRow to its own mini-component primarily so we can React.memo'ize it.
447
454
  function GridRow(props) {
448
- const { as, columns, row, style, rowStyles, stickyHeader, stickyOffset, sorting, sortState, setSortKey, openCards, columnSizes, level, ...others } = props;
455
+ const { as, columns, row, style, rowStyles, stickyHeader, stickyOffset, sorting, sortState, setSortKey, openCards, columnSizes, level, getCount, ...others } = props;
449
456
  // We treat the "header" kind as special for "good defaults" styling
450
457
  const isHeader = row.kind === "header";
451
458
  const rowStyle = rowStyles === null || rowStyles === void 0 ? void 0 : rowStyles[row.kind];
@@ -471,7 +478,7 @@ function GridRow(props) {
471
478
  ...(0, nestedCards_1.getNestedCardStyles)(row, openCardStyles, style),
472
479
  };
473
480
  let currentColspan = 1;
474
- const rowNode = ((0, jsx_runtime_1.jsx)(Row, Object.assign({ css: rowCss }, others, { "data-gridrow": true }, { children: columns.map((column, columnIndex) => {
481
+ const rowNode = ((0, jsx_runtime_1.jsx)(Row, Object.assign({ css: rowCss }, others, { "data-gridrow": true }, getCount(row.id), { children: columns.map((column, columnIndex) => {
475
482
  var _a, _b;
476
483
  if (column.mw) {
477
484
  // Validate the column's minWidth definition if set.
@@ -0,0 +1,17 @@
1
+ /**
2
+ * A hook to add `data-render=${count}` to an element.
3
+ *
4
+ * This will output even in production mode, which in theory is not necessary
5
+ * and we could/should avoid, but it should also be np.
6
+ *
7
+ * The intent is to leave it "always on" for dev & tests, so that engineers
8
+ * and test suites can very easily grab "what was the render count of that?"
9
+ * w/o bringing in one-off modes/tools.
10
+ *
11
+ * (One-off modes/tools are more appropriate for truly adhoc performance
12
+ * but the intent is to use this in GridTable where "what's the render count?"
13
+ * will be a common question.)
14
+ */
15
+ export declare function useRenderCount(): {
16
+ getCount: (id: string) => object;
17
+ };
@@ -0,0 +1,28 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.useRenderCount = void 0;
4
+ const react_1 = require("react");
5
+ /**
6
+ * A hook to add `data-render=${count}` to an element.
7
+ *
8
+ * This will output even in production mode, which in theory is not necessary
9
+ * and we could/should avoid, but it should also be np.
10
+ *
11
+ * The intent is to leave it "always on" for dev & tests, so that engineers
12
+ * and test suites can very easily grab "what was the render count of that?"
13
+ * w/o bringing in one-off modes/tools.
14
+ *
15
+ * (One-off modes/tools are more appropriate for truly adhoc performance
16
+ * but the intent is to use this in GridTable where "what's the render count?"
17
+ * will be a common question.)
18
+ */
19
+ function useRenderCount() {
20
+ const ref = (0, react_1.useRef)(new Map());
21
+ const getCount = (0, react_1.useCallback)((id) => {
22
+ const count = ref.current.get(id) || 1;
23
+ ref.current.set(id, count + 1);
24
+ return { "data-render": count };
25
+ }, []);
26
+ return { getCount };
27
+ }
28
+ exports.useRenderCount = useRenderCount;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@homebound/beam",
3
- "version": "2.108.0",
3
+ "version": "2.111.0",
4
4
  "author": "Homebound",
5
5
  "license": "MIT",
6
6
  "main": "dist/index.js",