@homebound/beam 2.151.2 → 2.153.1

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.
@@ -11,8 +11,12 @@ const getInteractiveElement_1 = require("../utils/getInteractiveElement");
11
11
  const useTestIds_1 = require("../utils/useTestIds");
12
12
  function Button(props) {
13
13
  const { onClick: onPress, disabled, endAdornment, menuTriggerProps, tooltip, openInNew, download, contrast = false, ...otherProps } = props;
14
- const showExternalLinkIcon = (typeof onPress === "string" && (0, utils_1.isAbsoluteUrl)(onPress)) || openInNew;
15
- const isDisabled = !!disabled;
14
+ const asLink = typeof onPress === "string";
15
+ const showExternalLinkIcon = (asLink && (0, utils_1.isAbsoluteUrl)(onPress)) || openInNew;
16
+ const [isDisabled, setIsDisabled] = (0, react_1.useState)(!!disabled);
17
+ (0, react_1.useEffect)(() => {
18
+ setIsDisabled(!!disabled);
19
+ }, [disabled]);
16
20
  const ariaProps = { onPress, isDisabled, ...otherProps, ...menuTriggerProps };
17
21
  const { label,
18
22
  // Default the icon based on other properties.
@@ -21,8 +25,17 @@ function Button(props) {
21
25
  const tid = (0, useTestIds_1.useTestIds)(props, label);
22
26
  const { buttonProps, isPressed } = (0, react_aria_1.useButton)({
23
27
  ...ariaProps,
24
- onPress: typeof onPress === "string" ? utils_1.noop : onPress,
25
- elementType: typeof onPress === "string" ? "a" : "button",
28
+ onPress: asLink
29
+ ? utils_1.noop
30
+ : (e) => {
31
+ const result = onPress(e);
32
+ if (isPromise(result)) {
33
+ setIsDisabled(true);
34
+ result.finally(() => setIsDisabled(false));
35
+ }
36
+ return result;
37
+ },
38
+ elementType: asLink ? "a" : "button",
26
39
  }, ref);
27
40
  const { isFocusVisible, focusProps } = (0, react_aria_1.useFocusRing)(ariaProps);
28
41
  const { hoverProps, isHovered } = (0, react_aria_1.useHover)(ariaProps);
@@ -38,7 +51,7 @@ function Button(props) {
38
51
  ...buttonProps,
39
52
  ...focusProps,
40
53
  ...hoverProps,
41
- className: typeof onPress === "string" ? components_1.navLink : undefined,
54
+ className: asLink ? components_1.navLink : undefined,
42
55
  css: {
43
56
  ...Css_1.Css.buttonBase.tt("inherit").$,
44
57
  ...baseStyles,
@@ -110,3 +123,6 @@ const iconStyles = {
110
123
  md: Css_1.Css.mr1.$,
111
124
  lg: Css_1.Css.mrPx(10).$,
112
125
  };
126
+ function isPromise(obj) {
127
+ return typeof obj === "object" && "then" in obj && typeof obj.then === "function";
128
+ }
@@ -122,6 +122,8 @@ export declare type GridSortConfig<S> = {
122
122
  /** The optional initial column (index in columns) and direction to sort. */
123
123
  initial?: [S | GridColumn<any>, Direction] | undefined;
124
124
  caseSensitive?: boolean;
125
+ /** The optional primary sort column, this will be sorted first above/below table sort */
126
+ primary?: [S | GridColumn<any>, Direction] | undefined;
125
127
  } | {
126
128
  on: "server";
127
129
  /** The current sort by value + direction (if server-side sorting). */
@@ -16,32 +16,47 @@ function sortRows(columns, rows, sortState, caseSensitive) {
16
16
  exports.sortRows = sortRows;
17
17
  function sortBatch(columns, batch, sortState, caseSensitive) {
18
18
  // When client-side sort, the sort value is the column index
19
- const [value, direction] = sortState;
19
+ const [value, direction, primaryKey, primaryDirection] = sortState;
20
20
  const column = columns[value];
21
21
  const invert = direction === "DESC";
22
+ const primaryInvert = primaryDirection === "DESC";
23
+ const primaryColumn = primaryKey && columns[primaryKey];
22
24
  // Make a shallow copy for sorting to avoid mutating the original list
23
25
  return [...batch].sort((a, b) => {
24
- const v1 = sortValue((0, GridTable_1.applyRowFn)(column, a, {}, 0), caseSensitive);
25
- const v2 = sortValue((0, GridTable_1.applyRowFn)(column, b, {}, 0), caseSensitive);
26
- const v1e = v1 === null || v1 === undefined;
27
- const v2e = v2 === null || v2 === undefined;
28
26
  if ((a.pin || b.pin) && !(a.pin === b.pin)) {
29
27
  const ap = a.pin === "first" ? -1 : a.pin === "last" ? 1 : 0;
30
28
  const bp = b.pin === "first" ? -1 : b.pin === "last" ? 1 : 0;
31
29
  return ap === bp ? 0 : ap < bp ? -1 : 1;
32
30
  }
33
- else if ((v1e && v2e) || v1 === v2) {
34
- return 0;
31
+ else if (primaryColumn) {
32
+ // When primary key exist sort that priority first
33
+ const primaryCompare = compare(primaryColumn, a, b, primaryInvert, caseSensitive);
34
+ // if both rows are not primary sort equivalent
35
+ if (primaryCompare !== 0) {
36
+ return primaryCompare;
37
+ }
35
38
  }
36
- else if (v1e || v1 < v2) {
37
- return invert ? 1 : -1;
38
- }
39
- else if (v2e || v1 > v2) {
40
- return invert ? -1 : 1;
41
- }
42
- return 0;
39
+ return compare(column, a, b, invert, caseSensitive);
43
40
  });
44
41
  }
42
+ function compare(column, a, b, invert, caseSensitive) {
43
+ const v1 = sortValue((0, GridTable_1.applyRowFn)(column, a, {}, 0), caseSensitive);
44
+ const v2 = sortValue((0, GridTable_1.applyRowFn)(column, b, {}, 0), caseSensitive);
45
+ const v1e = v1 === null || v1 === undefined;
46
+ const v2e = v2 === null || v2 === undefined;
47
+ if ((v1e && v2e) || v1 === v2) {
48
+ return 0;
49
+ }
50
+ else if (v1e || v1 < v2) {
51
+ return invert ? 1 : -1;
52
+ }
53
+ else if (v2e || v1 > v2) {
54
+ return invert ? -1 : 1;
55
+ }
56
+ else {
57
+ return 0;
58
+ }
59
+ }
45
60
  /** Look at a row and get its sort value. */
46
61
  function sortValue(value, caseSensitive) {
47
62
  // Check sortValue and then fallback on value
@@ -7,7 +7,7 @@ import { Direction, GridColumn, GridSortConfig, Kinded } from "./GridTable";
7
7
  * a) `serverSideSortKey` if we're server-side sorting, or
8
8
  * b) it's index in the `columns` array, if client-side sorting
9
9
  */
10
- export declare type SortState<S> = readonly [S, Direction];
10
+ export declare type SortState<S> = readonly [S, Direction, S | undefined, Direction | undefined];
11
11
  export declare type SortOn = "client" | "server" | undefined;
12
12
  /** Small custom hook that wraps the "setSortColumn inverts the current sort" logic. */
13
13
  export declare function useSortState<R extends Kinded, S>(columns: GridColumn<R, S>[], sorting?: GridSortConfig<S>): [SortState<S> | undefined, (value: S) => void, SortOn, boolean];
@@ -10,23 +10,24 @@ function useSortState(columns, sorting) {
10
10
  // `setSortState` just changed anyway (in response to the user sorting a column).
11
11
  const initialSortState = (0, react_1.useMemo)(() => {
12
12
  if ((sorting === null || sorting === void 0 ? void 0 : sorting.on) === "client") {
13
- const { initial } = sorting;
13
+ const { initial, primary } = sorting;
14
+ const primaryKey = primary && (typeof primary[0] === "number" ? primary[0] : columns.indexOf(primary[0]));
14
15
  if (initial === undefined && "initial" in sorting) {
15
16
  // if explicitly set to `undefined`, then do not sort
16
17
  return undefined;
17
18
  }
18
19
  else if (initial) {
19
20
  const key = typeof initial[0] === "number" ? initial[0] : columns.indexOf(initial[0]);
20
- return [key, initial[1]];
21
+ return [key, initial[1], primaryKey, primary === null || primary === void 0 ? void 0 : primary[1]];
21
22
  }
22
23
  else {
23
24
  // If no explicit sorting, assume 1st column ascending
24
25
  const firstSortableColumn = columns.findIndex((c) => c.clientSideSort !== false);
25
- return [firstSortableColumn, GridTable_1.ASC];
26
+ return [firstSortableColumn, GridTable_1.ASC, primaryKey, primary === null || primary === void 0 ? void 0 : primary[1]];
26
27
  }
27
28
  }
28
29
  else {
29
- return sorting === null || sorting === void 0 ? void 0 : sorting.value;
30
+ return (sorting === null || sorting === void 0 ? void 0 : sorting.value) ? [sorting === null || sorting === void 0 ? void 0 : sorting.value[0], sorting === null || sorting === void 0 ? void 0 : sorting.value[1], undefined, undefined] : undefined;
30
31
  }
31
32
  },
32
33
  // We want to allow the user to not memoize `GridTableProps.sorting` b/c for the
@@ -57,17 +58,17 @@ function deriveSortState(currentSortState, clickedKey, initialSortState) {
57
58
  const [currentKey, currentDirection] = currentSortState || [];
58
59
  // If the current sort state is not defined, or clicking a new column, then sort ASC on the clicked key
59
60
  if (!currentSortState || clickedKey !== currentKey) {
60
- return [clickedKey, GridTable_1.ASC];
61
+ return [clickedKey, GridTable_1.ASC, initialSortState === null || initialSortState === void 0 ? void 0 : initialSortState[2], initialSortState === null || initialSortState === void 0 ? void 0 : initialSortState[3]];
61
62
  }
62
63
  // If there is an `initialSortState` and we're clicking on that same key, then flip the sort.
63
64
  // Handles cases where the initial sort is DESC so that we can allow for DESC to ASC sorting.
64
65
  if (initialSortState && initialSortState[0] === clickedKey) {
65
- return [clickedKey, currentDirection === GridTable_1.ASC ? GridTable_1.DESC : GridTable_1.ASC];
66
+ return [clickedKey, currentDirection === GridTable_1.ASC ? GridTable_1.DESC : GridTable_1.ASC, initialSortState === null || initialSortState === void 0 ? void 0 : initialSortState[2], initialSortState === null || initialSortState === void 0 ? void 0 : initialSortState[3]];
66
67
  }
67
68
  // Otherwise when clicking the current column, toggle through sort states
68
69
  if (currentDirection === GridTable_1.ASC) {
69
70
  // if ASC -> go to desc
70
- return [clickedKey, GridTable_1.DESC];
71
+ return [clickedKey, GridTable_1.DESC, initialSortState === null || initialSortState === void 0 ? void 0 : initialSortState[2], initialSortState === null || initialSortState === void 0 ? void 0 : initialSortState[3]];
71
72
  }
72
73
  // Else, direction is already DESC, so revert to original sort value.
73
74
  return initialSortState;
@@ -21,6 +21,7 @@ export interface DateFieldBaseProps extends Pick<TextFieldBaseProps<{}>, "border
21
21
  placeholder?: string;
22
22
  format?: keyof typeof dateFormats;
23
23
  iconLeft?: boolean;
24
+ hideCalendarIcon?: boolean;
24
25
  /**
25
26
  * Set custom logic for individual dates or date ranges to be disabled in the picker
26
27
  * exposed from `react-day-picker`: https://react-day-picker.js.org/api/DayPicker#modifiers
@@ -18,7 +18,7 @@ function DateFieldBase(props) {
18
18
  var _a;
19
19
  const { label, disabled, required, value, onFocus, onBlur,
20
20
  // Pull `onChange` out of the props, but we're not directly using it. Do not want to keep it in `...others`
21
- onChange: _onChange, errorMsg, helperText, inlineLabel = false, readOnly, format = "short", iconLeft = false, disabledDays, onEnter, defaultOpen, mode, ...others } = props;
21
+ onChange: _onChange, errorMsg, helperText, inlineLabel = false, readOnly, format = "short", iconLeft = false, hideCalendarIcon = false, disabledDays, onEnter, defaultOpen, mode, ...others } = props;
22
22
  const inputRef = (0, react_1.useRef)(null);
23
23
  const inputWrapRef = (0, react_1.useRef)(null);
24
24
  const buttonRef = (0, react_1.useRef)(null);
@@ -156,7 +156,7 @@ function DateFieldBase(props) {
156
156
  const parsed = mode === "range" ? (0, utils_1.parseDateRange)(v, utils_1.dateFormats.short) : (0, utils_1.parseDate)(v, utils_1.dateFormats.short);
157
157
  onChange(parsed);
158
158
  }
159
- }, endAdornment: !iconLeft && calendarButton, startAdornment: iconLeft && calendarButton, tooltip: (0, components_1.resolveTooltip)(disabled, undefined, readOnly) }, others), void 0), state.isOpen && ((0, jsx_runtime_1.jsx)(internal_1.Popover, Object.assign({ triggerRef: inputWrapRef, popoverRef: overlayRef, positionProps: positionProps, onClose: state.close, isOpen: state.isOpen }, { children: (0, jsx_runtime_1.jsx)(DatePickerOverlay_1.DatePickerOverlay, Object.assign({ overlayProps: overlayProps }, { children: props.mode === "range" ? ((0, jsx_runtime_1.jsx)(internal_1.DateRangePicker, Object.assign({ range: wipValue, disabledDays: disabledDays, onSelect: (dr) => {
159
+ }, endAdornment: (!hideCalendarIcon && !iconLeft) && calendarButton, startAdornment: (!hideCalendarIcon && iconLeft) && calendarButton, tooltip: (0, components_1.resolveTooltip)(disabled, undefined, readOnly) }, others), void 0), state.isOpen && ((0, jsx_runtime_1.jsx)(internal_1.Popover, Object.assign({ triggerRef: inputWrapRef, popoverRef: overlayRef, positionProps: positionProps, onClose: state.close, isOpen: state.isOpen }, { children: (0, jsx_runtime_1.jsx)(DatePickerOverlay_1.DatePickerOverlay, Object.assign({ overlayProps: overlayProps }, { children: props.mode === "range" ? ((0, jsx_runtime_1.jsx)(internal_1.DateRangePicker, Object.assign({ range: wipValue, disabledDays: disabledDays, onSelect: (dr) => {
160
160
  var _a;
161
161
  // Note: Do not close date range picker on select to allow the user to select multiple dates at a time
162
162
  setInputValue((_a = (0, utils_1.formatDateRange)(dr, utils_1.dateFormats.short)) !== null && _a !== void 0 ? _a : "");
@@ -15,7 +15,7 @@ export interface BeamButtonProps {
15
15
  */
16
16
  disabled?: boolean | ReactNode;
17
17
  /** If function, then it is the handler that is called when the press is released over the target. Otherwise if string, it is the URL path for the link */
18
- onClick: ((e: PressEvent) => void) | string;
18
+ onClick: ((e: PressEvent) => void) | ((e: PressEvent) => Promise<void>) | string;
19
19
  /** Text to be shown via a tooltip when the user hovers over the button */
20
20
  tooltip?: ReactNode;
21
21
  /** Whether to open link in a new tab. This only effects the element if the `onClick` is a `string`/URL. */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@homebound/beam",
3
- "version": "2.151.2",
3
+ "version": "2.153.1",
4
4
  "author": "Homebound",
5
5
  "license": "MIT",
6
6
  "main": "dist/index.js",