@homebound/beam 2.166.1 → 2.169.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.
@@ -0,0 +1,17 @@
1
+ import { Key } from "react";
2
+ import { Matcher } from "react-day-picker";
3
+ import { Filter } from "./types";
4
+ import { Value } from "../../inputs";
5
+ import { DateRange } from "../../types";
6
+ export declare type DateRangeFilterProps<V extends Value, DV extends DateRangeFilterValue<V>> = {
7
+ label: string;
8
+ defaultValue?: DV;
9
+ placeholderText?: string;
10
+ disabledDays?: Matcher | Matcher[];
11
+ testFieldLabel?: string;
12
+ };
13
+ export declare type DateRangeFilterValue<V extends Value> = {
14
+ op: V;
15
+ value: DateRange | undefined;
16
+ };
17
+ export declare function dateRangeFilter<V extends Key>(props: DateRangeFilterProps<V, DateRangeFilterValue<V>>): (key: string) => Filter<DateRangeFilterValue<V>>;
@@ -0,0 +1,22 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.dateRangeFilter = void 0;
4
+ const jsx_runtime_1 = require("@emotion/react/jsx-runtime");
5
+ const BaseFilter_1 = require("./BaseFilter");
6
+ const Label_1 = require("../Label");
7
+ const inputs_1 = require("../../inputs");
8
+ const defaultTestId_1 = require("../../utils/defaultTestId");
9
+ function dateRangeFilter(props) {
10
+ return (key) => new DateRangeFilter(key, props);
11
+ }
12
+ exports.dateRangeFilter = dateRangeFilter;
13
+ class DateRangeFilter extends BaseFilter_1.BaseFilter {
14
+ render(value, setValue, tid, inModal, vertical) {
15
+ const { label, placeholderText, disabledDays, testFieldLabel, defaultValue } = this.props;
16
+ return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [vertical && (0, jsx_runtime_1.jsx)(Label_1.Label, { label: label }, void 0), (0, jsx_runtime_1.jsx)(inputs_1.DateRangeField, Object.assign({ compact: true, inlineLabel: true, isRangeFilterField: true, placeholder: placeholderText, label: testFieldLabel !== null && testFieldLabel !== void 0 ? testFieldLabel : "Date",
17
+ // Making sure that DateRange is Date type and not string before passing. Will never have undefined from/to
18
+ value: (value === null || value === void 0 ? void 0 : value.value)
19
+ ? { from: new Date(value.value.from), to: new Date(value.value.to) }
20
+ : undefined, onChange: (d) => (d ? setValue({ op: defaultValue === null || defaultValue === void 0 ? void 0 : defaultValue.op, value: d }) : setValue(undefined)), disabledDays: disabledDays }, tid[`${(0, defaultTestId_1.defaultTestId)(this.label)}_dateField`]), void 0)] }, void 0));
21
+ }
22
+ }
@@ -1,5 +1,7 @@
1
1
  export { dateFilter } from "./DateFilter";
2
2
  export type { DateFilterValue } from "./DateFilter";
3
+ export { dateRangeFilter } from "./DateRangeFilter";
4
+ export type { DateRangeFilterValue } from "./DateRangeFilter";
3
5
  export { multiFilter } from "./MultiFilter";
4
6
  export { singleFilter } from "./SingleFilter";
5
7
  export { booleanFilter } from "./BooleanFilter";
@@ -10,9 +10,11 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
10
10
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
11
11
  };
12
12
  Object.defineProperty(exports, "__esModule", { value: true });
13
- exports.toggleFilter = exports.booleanFilter = exports.singleFilter = exports.multiFilter = exports.dateFilter = void 0;
13
+ exports.toggleFilter = exports.booleanFilter = exports.singleFilter = exports.multiFilter = exports.dateRangeFilter = exports.dateFilter = void 0;
14
14
  var DateFilter_1 = require("./DateFilter");
15
15
  Object.defineProperty(exports, "dateFilter", { enumerable: true, get: function () { return DateFilter_1.dateFilter; } });
16
+ var DateRangeFilter_1 = require("./DateRangeFilter");
17
+ Object.defineProperty(exports, "dateRangeFilter", { enumerable: true, get: function () { return DateRangeFilter_1.dateRangeFilter; } });
16
18
  var MultiFilter_1 = require("./MultiFilter");
17
19
  Object.defineProperty(exports, "multiFilter", { enumerable: true, get: function () { return MultiFilter_1.multiFilter; } });
18
20
  var SingleFilter_1 = require("./SingleFilter");
@@ -1,4 +1,5 @@
1
1
  import { DateFilterValue } from "./DateFilter";
2
+ import { DateRangeFilterValue } from "./DateRangeFilter";
2
3
  import { FilterDefs } from "./types";
3
4
  export declare enum Stage {
4
5
  StageOne = "ONE",
@@ -37,13 +38,16 @@ export declare type ProjectFilter = {
37
38
  isTest?: boolean | null;
38
39
  doNotUse?: boolean | null;
39
40
  date?: DateFilterValue<string>;
41
+ dateRange?: DateRangeFilterValue<string>;
40
42
  };
41
43
  export declare type StageFilter = NonNullable<FilterDefs<ProjectFilter>["stage"]>;
42
44
  export declare type StageSingleFilter = NonNullable<FilterDefs<ProjectFilter>["stageSingle"]>;
43
45
  export declare type DateFilter = NonNullable<FilterDefs<ProjectFilter>["date"]>;
46
+ export declare type DateRangeFilter = NonNullable<FilterDefs<ProjectFilter>["dateRange"]>;
44
47
  export declare const stageFilter: StageFilter;
45
48
  export declare const stageSingleFilter: StageSingleFilter;
46
49
  export declare const taskDueFilter: DateFilter;
50
+ export declare const taskCompleteFilter: DateRangeFilter;
47
51
  export declare enum TaskStatus {
48
52
  NotStarted = "NOT_STARTED",
49
53
  InProgress = "IN_PROGRESS",
@@ -1,7 +1,8 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.ScheduleTypes = exports.TaskStatus = exports.taskDueFilter = exports.stageSingleFilter = exports.stageFilter = exports.Stage = void 0;
3
+ exports.ScheduleTypes = exports.TaskStatus = exports.taskCompleteFilter = exports.taskDueFilter = exports.stageSingleFilter = exports.stageFilter = exports.Stage = void 0;
4
4
  const DateFilter_1 = require("./DateFilter");
5
+ const DateRangeFilter_1 = require("./DateRangeFilter");
5
6
  const MultiFilter_1 = require("./MultiFilter");
6
7
  const SingleFilter_1 = require("./SingleFilter");
7
8
  var Stage;
@@ -33,6 +34,10 @@ exports.taskDueFilter = (0, DateFilter_1.dateFilter)({
33
34
  getOperationLabel: (o) => o.label,
34
35
  getOperationValue: (o) => o.value,
35
36
  });
37
+ exports.taskCompleteFilter = (0, DateRangeFilter_1.dateRangeFilter)({
38
+ label: "Task Completed",
39
+ placeholderText: "This is some placeholder text",
40
+ });
36
41
  var TaskStatus;
37
42
  (function (TaskStatus) {
38
43
  TaskStatus["NotStarted"] = "NOT_STARTED";
@@ -274,7 +274,7 @@ export declare type GridColumn<R extends Kinded, S = {}> = {
274
274
  };
275
275
  export declare const nonKindGridColumnKeys: string[];
276
276
  /** Allows rendering a specific cell. */
277
- declare type RenderCellFn<R extends Kinded> = (idx: number, css: Properties, content: ReactNode, row: R, rowStyle: RowStyle<R> | undefined) => ReactNode;
277
+ declare type RenderCellFn<R extends Kinded> = (idx: number, css: Properties, content: ReactNode, row: R, rowStyle: RowStyle<R> | undefined, classNames: string | undefined) => ReactNode;
278
278
  /** Defines row-specific styling for each given row `kind` in `R` */
279
279
  export declare type GridRowStyles<R extends Kinded> = {
280
280
  [P in R["kind"]]?: RowStyle<DiscriminateUnion<R, "kind", P>>;
@@ -316,6 +316,8 @@ export declare type GridCellContent = {
316
316
  onClick?: () => {} | string;
317
317
  /** Custom css to apply directly to this cell, i.e. cell-specific borders. */
318
318
  css?: Properties;
319
+ /** Allows cell to reveal content when the user hovers over a row. Content must be wrapped in an element in order to be hidden. IE <div>{value}</div>*/
320
+ revealOnRowHover?: true;
319
321
  };
320
322
  declare type MaybeFn<T> = T | (() => T);
321
323
  /**
@@ -490,6 +490,7 @@ function GridRow(props) {
490
490
  .map((openCardKind) => style.nestedCards.kinds[openCardKind])
491
491
  .filter((style) => style)
492
492
  : undefined;
493
+ const revealOnRowHoverClass = "revealOnRowHover";
493
494
  const rowStyleCellCss = maybeApplyFunction(row, rowStyle === null || rowStyle === void 0 ? void 0 : rowStyle.cellCss);
494
495
  const rowCss = {
495
496
  // For virtual tables use `display: flex` to keep all cells on the same row. For each cell in the row use `flexNone` to ensure they stay their defined widths
@@ -502,6 +503,10 @@ function GridRow(props) {
502
503
  // Maybe add the sticky header styles
503
504
  ...((isHeader || isTotals) && stickyHeader ? Css_1.Css.sticky.topPx(stickyOffset).z2.$ : undefined),
504
505
  ...(0, nestedCards_1.getNestedCardStyles)(row, openCardStyles, style, isActive),
506
+ ...{
507
+ [` > .${revealOnRowHoverClass} > *`]: Css_1.Css.invisible.$,
508
+ [`:hover > .${revealOnRowHoverClass} > *`]: Css_1.Css.visible.$,
509
+ },
505
510
  };
506
511
  let currentColspan = 1;
507
512
  let firstContentColumnStylesApplied = false;
@@ -523,6 +528,7 @@ function GridRow(props) {
523
528
  }
524
529
  const maybeContent = applyRowFn(column, row, api, level);
525
530
  currentColspan = isGridCellContent(maybeContent) ? (_a = maybeContent.colspan) !== null && _a !== void 0 ? _a : 1 : 1;
531
+ const revealOnRowHover = isGridCellContent(maybeContent) ? maybeContent.revealOnRowHover : false;
526
532
  const canSortColumn = (sortOn === "client" && column.clientSideSort !== false) ||
527
533
  (sortOn === "server" && !!column.serverSideSortKey);
528
534
  const alignment = getAlignment(column, maybeContent);
@@ -598,6 +604,7 @@ function GridRow(props) {
598
604
  },
599
605
  ...(column.mw ? Css_1.Css.mw(column.mw).$ : {}),
600
606
  };
607
+ const cellClassNames = revealOnRowHover ? revealOnRowHoverClass : undefined;
601
608
  const renderFn = ((rowStyle === null || rowStyle === void 0 ? void 0 : rowStyle.renderCell) || (rowStyle === null || rowStyle === void 0 ? void 0 : rowStyle.rowLink)) && wrapAction
602
609
  ? rowLinkRenderFn(as)
603
610
  : isHeader
@@ -605,7 +612,7 @@ function GridRow(props) {
605
612
  : (rowStyle === null || rowStyle === void 0 ? void 0 : rowStyle.onClick) && wrapAction
606
613
  ? rowClickRenderFn(as, api)
607
614
  : defaultRenderFn(as);
608
- return renderFn(columnIndex, cellCss, content, row, rowStyle);
615
+ return renderFn(columnIndex, cellCss, content, row, rowStyle, cellClassNames);
609
616
  }) }), void 0));
610
617
  return openCardStyles && openCardStyles.length > 0 ? (0, nestedCards_1.wrapCard)(openCardStyles, rowNode) : rowNode;
611
618
  }
@@ -696,12 +703,12 @@ function applyRowFn(column, row, api, level) {
696
703
  }
697
704
  exports.applyRowFn = applyRowFn;
698
705
  /** Renders our default cell element, i.e. if no row links and no custom renderCell are used. */
699
- const defaultRenderFn = (as) => (key, css, content) => {
706
+ const defaultRenderFn = (as) => (key, css, content, row, rowStyle, classNames) => {
700
707
  const Cell = as === "table" ? "td" : "div";
701
- return ((0, jsx_runtime_1.jsx)(Cell, Object.assign({ css: { ...css, ...tableRowStyles(as) } }, { children: content }), key));
708
+ return ((0, jsx_runtime_1.jsx)(Cell, Object.assign({ css: { ...css, ...tableRowStyles(as) }, className: classNames }, { children: content }), key));
702
709
  };
703
710
  /** Sets up the `GridContext` so that header cells can access the current sort settings. */
704
- const headerRenderFn = (columns, column, sortState, setSortKey, as) => (key, css, content) => {
711
+ const headerRenderFn = (columns, column, sortState, setSortKey, as) => (key, css, content, row, rowStyle, classNames) => {
705
712
  const [currentKey, direction] = sortState || [];
706
713
  // If server-side sorting, use the user's key for this column; client-side sorting, use the index.
707
714
  const ourSortKey = column.serverSideSortKey || columns.indexOf(column);
@@ -709,21 +716,21 @@ const headerRenderFn = (columns, column, sortState, setSortKey, as) => (key, css
709
716
  sorted: ourSortKey === currentKey ? direction : undefined,
710
717
  toggleSort: () => setSortKey(ourSortKey),
711
718
  };
712
- const Row = as === "table" ? "th" : "div";
713
- return ((0, jsx_runtime_1.jsx)(GridSortContext_1.GridSortContext.Provider, Object.assign({ value: context }, { children: (0, jsx_runtime_1.jsx)(Row, Object.assign({ css: { ...css, ...tableRowStyles(as, column) } }, { children: content }), void 0) }), key));
719
+ const Cell = as === "table" ? "th" : "div";
720
+ return ((0, jsx_runtime_1.jsx)(GridSortContext_1.GridSortContext.Provider, Object.assign({ value: context }, { children: (0, jsx_runtime_1.jsx)(Cell, Object.assign({ css: { ...css, ...tableRowStyles(as, column) }, className: classNames }, { children: content }), void 0) }), key));
714
721
  };
715
722
  /** Renders a cell element when a row link is in play. */
716
- const rowLinkRenderFn = (as) => (key, css, content, row, rowStyle) => {
723
+ const rowLinkRenderFn = (as) => (key, css, content, row, rowStyle, classNames) => {
717
724
  const to = rowStyle.rowLink(row);
718
725
  if (as === "table") {
719
- return ((0, jsx_runtime_1.jsx)("td", Object.assign({ css: { ...css, ...tableRowStyles(as) } }, { children: (0, jsx_runtime_1.jsx)(react_router_dom_1.Link, Object.assign({ to: to, css: Css_1.Css.noUnderline.color("unset").db.$, className: CssReset_1.navLink }, { children: content }), void 0) }), key));
726
+ return ((0, jsx_runtime_1.jsx)("td", Object.assign({ css: { ...css, ...tableRowStyles(as) }, className: classNames }, { children: (0, jsx_runtime_1.jsx)(react_router_dom_1.Link, Object.assign({ to: to, css: Css_1.Css.noUnderline.color("unset").db.$, className: CssReset_1.navLink }, { children: content }), void 0) }), key));
720
727
  }
721
- return ((0, jsx_runtime_1.jsx)(react_router_dom_1.Link, Object.assign({ to: to, css: { ...Css_1.Css.noUnderline.color("unset").$, ...css }, className: CssReset_1.navLink }, { children: content }), key));
728
+ return ((0, jsx_runtime_1.jsx)(react_router_dom_1.Link, Object.assign({ to: to, css: { ...Css_1.Css.noUnderline.color("unset").$, ...css }, className: `${CssReset_1.navLink} ${classNames}` }, { children: content }), key));
722
729
  };
723
730
  /** Renders a cell that will fire the RowStyle.onClick. */
724
- const rowClickRenderFn = (as, api) => (key, css, content, row, rowStyle) => {
731
+ const rowClickRenderFn = (as, api) => (key, css, content, row, rowStyle, classNames) => {
725
732
  const Row = as === "table" ? "tr" : "div";
726
- return ((0, jsx_runtime_1.jsx)(Row, Object.assign({}, { key }, { css: { ...css, ...tableRowStyles(as) }, onClick: () => rowStyle.onClick(row, api) }, { children: content }), void 0));
733
+ return ((0, jsx_runtime_1.jsx)(Row, Object.assign({}, { key }, { css: { ...css, ...tableRowStyles(as) }, className: classNames, onClick: () => rowStyle.onClick(row, api) }, { children: content }), void 0));
727
734
  };
728
735
  const alignmentToJustify = {
729
736
  left: "flex-start",
@@ -16,6 +16,7 @@ export interface TabsProps<V extends string, X> {
16
16
  onChange: (value: V) => void;
17
17
  contentXss?: X;
18
18
  alwaysShowAllTabs?: boolean;
19
+ includeBottomBorder?: boolean;
19
20
  }
20
21
  export interface RouteTabsProps<V extends string, X> extends Omit<TabsProps<V, X>, "onChange" | "selected" | "tabs"> {
21
22
  tabs: RouteTab<V>[];
@@ -65,26 +66,36 @@ export declare function getTabStyles(): {
65
66
  } & {
66
67
  paddingRight: import("csstype").Property.PaddingRight<0 | (string & {})> | undefined;
67
68
  } & {
68
- borderRadius: import("csstype").Property.BorderRadius<0 | (string & {})> | undefined;
69
+ outline: import("csstype").Property.Outline<0 | (string & {})> | undefined;
70
+ } & {
71
+ color: import("csstype").Property.Color | undefined;
72
+ } & {
73
+ width: import("csstype").Property.Width<0 | (string & {})> | undefined;
74
+ } & {
75
+ cursor: import("csstype").Property.Cursor | undefined;
69
76
  } & {
70
77
  fontWeight: import("csstype").Property.FontWeight | undefined;
71
78
  } & {
72
79
  fontSize: import("csstype").Property.FontSize<0 | (string & {})> | undefined;
73
80
  } & {
74
81
  lineHeight: import("csstype").Property.LineHeight<0 | (string & {})> | undefined;
82
+ };
83
+ activeStyles: {
84
+ borderBottomStyle: import("csstype").Property.BorderBottomStyle | undefined;
75
85
  } & {
76
- outline: import("csstype").Property.Outline<0 | (string & {})> | undefined;
86
+ borderBottomWidth: import("csstype").Property.BorderBottomWidth<0 | (string & {})> | undefined;
77
87
  } & {
78
- color: import("csstype").Property.Color | undefined;
88
+ paddingBottom: import("csstype").Property.PaddingBottom<0 | (string & {})> | undefined;
79
89
  } & {
80
- width: import("csstype").Property.Width<0 | (string & {})> | undefined;
90
+ borderColor: import("csstype").Property.BorderColor | undefined;
81
91
  } & {
82
- cursor: import("csstype").Property.Cursor | undefined;
83
- };
84
- activeStyles: {
85
- color: import("csstype").Property.Color | undefined;
92
+ fontWeight: import("csstype").Property.FontWeight | undefined;
86
93
  } & {
87
- backgroundColor: import("csstype").Property.BackgroundColor | undefined;
94
+ fontSize: import("csstype").Property.FontSize<0 | (string & {})> | undefined;
95
+ } & {
96
+ lineHeight: import("csstype").Property.LineHeight<0 | (string & {})> | undefined;
97
+ } & {
98
+ color: import("csstype").Property.Color | undefined;
88
99
  };
89
100
  disabledStyles: {
90
101
  color: import("csstype").Property.Color | undefined;
@@ -97,14 +108,24 @@ export declare function getTabStyles(): {
97
108
  boxShadow: import("csstype").Property.BoxShadow | undefined;
98
109
  };
99
110
  hoverStyles: {
100
- color: import("csstype").Property.Color | undefined;
111
+ borderBottomStyle: import("csstype").Property.BorderBottomStyle | undefined;
101
112
  } & {
102
- backgroundColor: import("csstype").Property.BackgroundColor | undefined;
113
+ borderBottomWidth: import("csstype").Property.BorderBottomWidth<0 | (string & {})> | undefined;
114
+ } & {
115
+ paddingBottom: import("csstype").Property.PaddingBottom<0 | (string & {})> | undefined;
116
+ } & {
117
+ borderColor: import("csstype").Property.BorderColor | undefined;
103
118
  };
104
119
  activeHoverStyles: {
105
120
  backgroundColor: import("csstype").Property.BackgroundColor | undefined;
106
121
  } & {
107
- color: import("csstype").Property.Color | undefined;
122
+ borderBottomStyle: import("csstype").Property.BorderBottomStyle | undefined;
123
+ } & {
124
+ borderBottomWidth: import("csstype").Property.BorderBottomWidth<0 | (string & {})> | undefined;
125
+ } & {
126
+ paddingBottom: import("csstype").Property.PaddingBottom<0 | (string & {})> | undefined;
127
+ } & {
128
+ borderColor: import("csstype").Property.BorderColor | undefined;
108
129
  };
109
130
  };
110
131
  export declare function getNextTabValue<V extends string>(selected: V, key: "ArrowLeft" | "ArrowRight", tabs: Tab<V>[] | RouteTab<V>[]): V;
@@ -45,7 +45,7 @@ exports.TabContent = TabContent;
45
45
  /** The top list of tabs. */
46
46
  function Tabs(props) {
47
47
  const { tabActionsRef, tabActionsDiv } = (0, BeamContext_1.useBeamContext)();
48
- const { ariaLabel, tabs, ...others } = props;
48
+ const { ariaLabel, tabs, includeBottomBorder, ...others } = props;
49
49
  const location = (0, react_router_1.useLocation)();
50
50
  const selected = isRouteTabs(props)
51
51
  ? uniqueTabValue(props.tabs.find((t) => !!(0, react_router_1.matchPath)(location.pathname, { path: t.path, exact: true })) || props.tabs[0])
@@ -84,7 +84,7 @@ function Tabs(props) {
84
84
  setActive(selected);
85
85
  }
86
86
  }
87
- return ((0, jsx_runtime_1.jsxs)("div", Object.assign({ css: Css_1.Css.df.aic.$ }, { children: [!hideTabs(props) && ((0, jsx_runtime_1.jsx)("div", Object.assign({ ref: ref, css: Css_1.Css.dif.childGap1.$, "aria-label": ariaLabel, role: "tablist" }, tid, { children: tabs.map((tab) => {
87
+ return ((0, jsx_runtime_1.jsxs)("div", Object.assign({ css: Css_1.Css.df.aic.$ }, { children: [!hideTabs(props) && ((0, jsx_runtime_1.jsx)("div", Object.assign({ ref: ref, css: { ...Css_1.Css.dif.childGap1.$, ...(includeBottomBorder ? { ...Css_1.Css.bb.bGray200.$ } : {}) }, "aria-label": ariaLabel, role: "tablist" }, tid, { children: tabs.map((tab) => {
88
88
  const uniqueValue = uniqueTabValue(tab);
89
89
  return ((0, jsx_runtime_1.jsx)(TabImpl, Object.assign({ active: active === uniqueValue, focusProps: focusProps, isFocusVisible: isFocusVisible, onClick: onClick, onKeyUp: onKeyUp, onBlur: onBlur, tab: tab }, tid[(0, defaultTestId_1.defaultTestId)(uniqueValue)]), uniqueValue));
90
90
  }) }), void 0)), (0, jsx_runtime_1.jsx)("div", { css: Css_1.Css.ml("auto").addIn("&>div", Css_1.Css.df.aic.childGap1.$).$, ref: tabActionsRef }, void 0)] }), void 0));
@@ -122,13 +122,20 @@ function TabImpl(props) {
122
122
  return isDisabled ? ((0, jsx_runtime_1.jsx)("div", Object.assign({}, tabProps, { children: tabLabel }), void 0)) : isRouteTab(tab) ? ((0, jsx_runtime_1.jsx)(react_router_dom_1.Link, Object.assign({}, { ...tabProps, ...interactiveProps }, { className: "navLink", to: tab.href }, { children: tabLabel }), void 0)) : ((0, jsx_runtime_1.jsx)("button", Object.assign({}, { ...tabProps, ...interactiveProps }, { children: tabLabel }), void 0));
123
123
  }
124
124
  function getTabStyles() {
125
+ const borderBottomWidthPx = 4;
126
+ const verticalPaddingPx = 6;
127
+ // Decrease the bottom padding by the same amount of the new border width to prevent text layout shift
128
+ const borderBottomStyles = Css_1.Css.bb
129
+ .add("borderBottomWidth", `${borderBottomWidthPx}px`)
130
+ .pbPx(verticalPaddingPx - borderBottomWidthPx).$;
125
131
  return {
126
- baseStyles: Css_1.Css.df.aic.hPx(32).pyPx(6).px1.br4.smEm.outline0.gray700.add("width", "fit-content").cursorPointer.$,
127
- activeStyles: Css_1.Css.lightBlue700.bgLightBlue50.$,
132
+ baseStyles: Css_1.Css.df.aic.hPx(32).pyPx(verticalPaddingPx).px1.outline0.gray700.add("width", "fit-content")
133
+ .cursorPointer.sm.$,
134
+ activeStyles: Css_1.Css.add(borderBottomStyles).bLightBlue700.smEm.gray900.$,
128
135
  disabledStyles: Css_1.Css.gray400.cursorNotAllowed.$,
129
136
  focusRingStyles: Css_1.Css.bgLightBlue50.bshFocus.$,
130
- hoverStyles: Css_1.Css.gray700.bgGray100.$,
131
- activeHoverStyles: Css_1.Css.bgLightBlue200.lightBlue700.$,
137
+ hoverStyles: Css_1.Css.add(borderBottomStyles).bGray400.$,
138
+ activeHoverStyles: Css_1.Css.bgLightBlue50.add(borderBottomStyles).bLightBlue700.$,
132
139
  };
133
140
  }
134
141
  exports.getTabStyles = getTabStyles;
@@ -6,5 +6,6 @@ export interface DateRangePickerProps {
6
6
  onSelect: (range: DateRange | undefined) => void;
7
7
  disabledDays?: Matcher | Matcher[];
8
8
  dottedDays?: Matcher[];
9
+ useYearPicker?: boolean;
9
10
  }
10
11
  export declare function DateRangePicker(props: DateRangePickerProps): import("@emotion/react/jsx-runtime").JSX.Element;
@@ -11,9 +11,9 @@ const utils_1 = require("../../../utils");
11
11
  require("./DatePicker.css");
12
12
  function DateRangePicker(props) {
13
13
  var _a;
14
- const { range, onSelect, disabledDays, dottedDays } = props;
14
+ const { range, onSelect, disabledDays, dottedDays, useYearPicker } = props;
15
15
  const tid = (0, utils_1.useTestIds)(props, "datePicker");
16
- return ((0, jsx_runtime_1.jsx)("div", Object.assign({ css: Css_1.Css.dib.bgWhite.xs.$ }, tid, { children: (0, jsx_runtime_1.jsx)(react_day_picker_1.DayPicker, { mode: "range", selected: range, components: { Caption: Header_1.Header, Head: WeekHeader_1.WeekHeader, Day: Day_1.Day }, defaultMonth: (_a = range === null || range === void 0 ? void 0 : range.to) !== null && _a !== void 0 ? _a : new Date(), onSelect: (selection, day, activeModifiers) => {
16
+ return ((0, jsx_runtime_1.jsx)("div", Object.assign({ css: Css_1.Css.dib.bgWhite.xs.$ }, tid, { children: (0, jsx_runtime_1.jsx)(react_day_picker_1.DayPicker, { mode: "range", selected: range, components: { Caption: useYearPicker ? Header_1.YearSkipHeader : Header_1.Header, Head: WeekHeader_1.WeekHeader, Day: Day_1.Day }, defaultMonth: (_a = range === null || range === void 0 ? void 0 : range.to) !== null && _a !== void 0 ? _a : new Date(), onSelect: (selection, day, activeModifiers) => {
17
17
  // Disallow returning disabled dates.
18
18
  if (activeModifiers.disabled)
19
19
  return;
@@ -1,2 +1,3 @@
1
1
  import { CaptionProps } from "react-day-picker";
2
2
  export declare function Header(props: CaptionProps): import("@emotion/react/jsx-runtime").JSX.Element;
3
+ export declare function YearSkipHeader(props: CaptionProps): import("@emotion/react/jsx-runtime").JSX.Element;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.Header = void 0;
3
+ exports.YearSkipHeader = exports.Header = void 0;
4
4
  const jsx_runtime_1 = require("@emotion/react/jsx-runtime");
5
5
  const date_fns_1 = require("date-fns");
6
6
  const react_day_picker_1 = require("react-day-picker");
@@ -12,3 +12,10 @@ function Header(props) {
12
12
  return ((0, jsx_runtime_1.jsxs)("div", Object.assign({ css: Css_1.Css.df.jcsb.aic.mlPx(12).mrPx(2).hPx(32).$ }, { children: [(0, jsx_runtime_1.jsx)("h1", Object.assign({ css: Css_1.Css.base.$ }, { children: (0, date_fns_1.format)(displayMonth, "MMMM yyyy") }), void 0), (0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)(IconButton_1.IconButton, { color: Css_1.Palette.Gray700, icon: "chevronLeft", onClick: () => goToMonth((0, date_fns_1.addMonths)(displayMonth, -1)) }, void 0), (0, jsx_runtime_1.jsx)(IconButton_1.IconButton, { color: Css_1.Palette.Gray700, icon: "chevronRight", onClick: () => goToMonth((0, date_fns_1.addMonths)(displayMonth, 1)) }, void 0)] }, void 0)] }), void 0));
13
13
  }
14
14
  exports.Header = Header;
15
+ // Header with year skip option
16
+ function YearSkipHeader(props) {
17
+ const { displayMonth } = props;
18
+ const { goToMonth } = (0, react_day_picker_1.useNavigation)();
19
+ return ((0, jsx_runtime_1.jsxs)("div", Object.assign({ css: Css_1.Css.df.jcsb.aic.mlPx(12).mrPx(12).hPx(32).$ }, { children: [(0, jsx_runtime_1.jsxs)("div", Object.assign({ css: Css_1.Css.df.fdr.jcsb.$ }, { children: [(0, jsx_runtime_1.jsx)(IconButton_1.IconButton, { color: Css_1.Palette.Gray700, icon: "chevronLeft", onClick: () => goToMonth((0, date_fns_1.addMonths)(displayMonth, -1)) }, void 0), (0, jsx_runtime_1.jsx)("h1", Object.assign({ css: Css_1.Css.base.$ }, { children: (0, date_fns_1.format)(displayMonth, "MMM") }), void 0), (0, jsx_runtime_1.jsx)(IconButton_1.IconButton, { color: Css_1.Palette.Gray700, icon: "chevronRight", onClick: () => goToMonth((0, date_fns_1.addMonths)(displayMonth, 1)) }, void 0)] }), void 0), (0, jsx_runtime_1.jsxs)("div", Object.assign({ css: Css_1.Css.df.fdr.jcsb.$ }, { children: [(0, jsx_runtime_1.jsx)(IconButton_1.IconButton, { color: Css_1.Palette.Gray700, icon: "chevronLeft", onClick: () => goToMonth((0, date_fns_1.addYears)(displayMonth, -1)) }, void 0), (0, jsx_runtime_1.jsx)("h1", Object.assign({ css: Css_1.Css.base.$ }, { children: (0, date_fns_1.format)(displayMonth, "yyyy") }), void 0), (0, jsx_runtime_1.jsx)(IconButton_1.IconButton, { color: Css_1.Palette.Gray700, icon: "chevronRight", onClick: () => goToMonth((0, date_fns_1.addYears)(displayMonth, 1)) }, void 0)] }), void 0)] }), void 0));
20
+ }
21
+ exports.YearSkipHeader = YearSkipHeader;
@@ -3,7 +3,7 @@ import { DateFieldProps } from "../inputs";
3
3
  export declare type BoundDateFieldProps = Omit<DateFieldProps, "label" | "value" | "onChange"> & {
4
4
  field: FieldState<any, Date | null | undefined>;
5
5
  label?: string;
6
- onChange?: (value: Date) => void;
6
+ onChange?: (value: Date | undefined) => void;
7
7
  };
8
8
  /** Wraps `TextField` and binds it to a form field. */
9
9
  export declare function BoundDateField(props: BoundDateFieldProps): import("@emotion/react/jsx-runtime").JSX.Element;
@@ -4,7 +4,7 @@ import { DateRange } from "../types";
4
4
  export declare type BoundDateRangeFieldProps = Omit<DateRangeFieldProps, "label" | "value" | "onChange"> & {
5
5
  field: FieldState<any, DateRange | null | undefined>;
6
6
  label?: string;
7
- onChange?: (value: DateRange) => void;
7
+ onChange?: (value: DateRange | undefined) => void;
8
8
  };
9
9
  /** Wraps `TextField` and binds it to a form field. */
10
10
  export declare function BoundDateRangeField(props: BoundDateRangeFieldProps): import("@emotion/react/jsx-runtime").JSX.Element;
@@ -30,17 +30,19 @@ export interface DateFieldBaseProps extends Pick<TextFieldBaseProps<{}>, "border
30
30
  onEnter?: VoidFunction;
31
31
  /** for storybook */
32
32
  defaultOpen?: boolean;
33
- onChange: ((value: Date) => void) | ((value: DateRange) => void);
33
+ onChange: ((value: Date | undefined) => void) | ((value: DateRange | undefined) => void);
34
34
  mode: DateFieldMode;
35
+ /** Range filters should only allow a full DateRange or nothing */
36
+ isRangeFilterField?: boolean;
35
37
  }
36
38
  export interface DateSingleFieldBaseProps extends DateFieldBaseProps {
37
39
  mode: "single";
38
40
  value: Date | undefined;
39
- onChange: (value: Date) => void;
41
+ onChange: (value: Date | undefined) => void;
40
42
  }
41
43
  export interface DateRangeFieldBaseProps extends DateFieldBaseProps {
42
44
  mode: "range";
43
45
  value: DateRange | undefined;
44
- onChange: (value: DateRange) => void;
46
+ onChange: (value: DateRange | undefined) => void;
45
47
  }
46
48
  export declare function DateFieldBase(props: DateRangeFieldBaseProps | DateSingleFieldBaseProps): import("@emotion/react/jsx-runtime").JSX.Element;
@@ -18,7 +18,8 @@ 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, hideCalendarIcon = 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, isRangeFilterField = false, ...others } = props;
22
+ const isRangeMode = mode === "range";
22
23
  const inputRef = (0, react_1.useRef)(null);
23
24
  const inputWrapRef = (0, react_1.useRef)(null);
24
25
  const buttonRef = (0, react_1.useRef)(null);
@@ -30,7 +31,7 @@ function DateFieldBase(props) {
30
31
  // The `wipValue` allows the "range" mode to set the value to `undefined`, even if the `onChange` response cannot be undefined.
31
32
  // This makes working within the DateRangePicker much more user friendly.
32
33
  const [wipValue, setWipValue] = (0, react_1.useState)(value);
33
- const [inputValue, setInputValue] = (0, react_1.useState)((_a = (props.mode === "range" ? (0, utils_1.formatDateRange)(props.value, dateFormat) : (0, utils_1.formatDate)(props.value, dateFormat))) !== null && _a !== void 0 ? _a : "");
34
+ const [inputValue, setInputValue] = (0, react_1.useState)((_a = (isRangeMode ? (0, utils_1.formatDateRange)(props.value, dateFormat) : (0, utils_1.formatDate)(props.value, dateFormat))) !== null && _a !== void 0 ? _a : "");
34
35
  const tid = (0, utils_2.useTestIds)(props, (0, defaultTestId_1.defaultTestId)(label));
35
36
  const isDisabled = !!disabled;
36
37
  const isReadOnly = !!readOnly;
@@ -61,7 +62,7 @@ function DateFieldBase(props) {
61
62
  (0, utils_2.maybeCall)(onFocus);
62
63
  if (wipValue && dateFormat !== utils_1.dateFormats.short) {
63
64
  // When focused, change to use the "short" date format, as it is simpler to update by hand and parse.
64
- setInputValue((_a = (props.mode === "range"
65
+ setInputValue((_a = (isRangeMode
65
66
  ? (0, utils_1.formatDateRange)(props.value, utils_1.dateFormats.short)
66
67
  : (0, utils_1.formatDate)(props.value, utils_1.dateFormats.short))) !== null && _a !== void 0 ? _a : "");
67
68
  }
@@ -75,15 +76,17 @@ function DateFieldBase(props) {
75
76
  (overlayRef.current && overlayRef.current.contains(e.relatedTarget))) {
76
77
  return;
77
78
  }
78
- const parsedDate = mode === "range" ? (0, utils_1.parseDateRange)(inputValue, utils_1.dateFormats.short) : (0, utils_1.parseDate)(inputValue, utils_1.dateFormats.short);
79
+ const parsedDate = isRangeMode
80
+ ? (0, utils_1.parseDateRange)(inputValue, utils_1.dateFormats.short)
81
+ : (0, utils_1.parseDate)(inputValue, utils_1.dateFormats.short);
79
82
  // If the user leaves the input and has an invalid date, reset to previous value.
80
83
  if (!isParsedDateValid(parsedDate)) {
81
84
  setWipValue(value);
82
- setInputValue((_a = (props.mode === "range" ? (0, utils_1.formatDateRange)(props.value, dateFormat) : (0, utils_1.formatDate)(props.value, dateFormat))) !== null && _a !== void 0 ? _a : "");
85
+ setInputValue((_a = (isRangeMode ? (0, utils_1.formatDateRange)(props.value, dateFormat) : (0, utils_1.formatDate)(props.value, dateFormat))) !== null && _a !== void 0 ? _a : "");
83
86
  }
84
87
  else if (dateFormat !== utils_1.dateFormats.short) {
85
88
  // Or if we need to reset the dateFormat back from `short` to whatever the user specified
86
- setInputValue((_b = (props.mode === "range" ? (0, utils_1.formatDateRange)(props.value, dateFormat) : (0, utils_1.formatDate)(props.value, dateFormat))) !== null && _b !== void 0 ? _b : "");
89
+ setInputValue((_b = (isRangeMode ? (0, utils_1.formatDateRange)(props.value, dateFormat) : (0, utils_1.formatDate)(props.value, dateFormat))) !== null && _b !== void 0 ? _b : "");
87
90
  }
88
91
  state.close();
89
92
  (0, utils_2.maybeCall)(onBlur);
@@ -120,48 +123,62 @@ function DateFieldBase(props) {
120
123
  // Avoid updating any WIP values.
121
124
  if (!isFocused && !state.isOpen) {
122
125
  setWipValue(value);
123
- setInputValue((_a = (props.mode === "range" ? (0, utils_1.formatDateRange)(props.value, dateFormat) : (0, utils_1.formatDate)(props.value, dateFormat))) !== null && _a !== void 0 ? _a : "");
126
+ setInputValue((_a = (isRangeMode ? (0, utils_1.formatDateRange)(props.value, dateFormat) : (0, utils_1.formatDate)(props.value, dateFormat))) !== null && _a !== void 0 ? _a : "");
124
127
  }
125
- // eslint-disable-next-line react-hooks/exhaustive-deps - Do not include `isFocused` or `state.isOpen`.
128
+ // eslint-disable-next-line react-hooks/exhaustive-deps
126
129
  // We don't want to update the internal `wipValue` or `inputValue` back to `value` just because focus state changes or the overlay opens
127
130
  }, [value, dateFormat]);
128
131
  // Create a type safe `onChange` to handle both Single and Range date fields.
129
132
  const onChange = (0, react_1.useCallback)((d) => {
130
133
  setWipValue(d);
131
134
  if (d && isParsedDateValid(d)) {
132
- if (props.mode === "range" && (0, react_day_picker_1.isDateRange)(d)) {
135
+ if (isRangeMode && (0, react_day_picker_1.isDateRange)(d)) {
133
136
  props.onChange(d);
134
137
  return;
135
138
  }
136
- if (props.mode === "single" && !(0, react_day_picker_1.isDateRange)(d)) {
139
+ if (!isRangeMode && !(0, react_day_picker_1.isDateRange)(d)) {
137
140
  props.onChange(d);
138
141
  return;
139
142
  }
140
143
  }
141
- }, [mode, props.onChange]);
144
+ else {
145
+ props.onChange(undefined);
146
+ return;
147
+ }
148
+ }, [isRangeMode, props.onChange]);
142
149
  // If showing the short date format, "01/01/20", so set size to 8. If medium (Wed, Nov 23) use 10 characters (leaving out the `,` character in the count because it is so small)
143
150
  // Otherwise the long format can be `undefined`.
144
151
  // Setting the size attribute only impacts the fields when displayed in a container that doesn't allow the field to grow to its max width, such as in an inline container.
145
152
  // TODO: figure this out... seems weird to have now that we support multiple dates formats....
146
153
  // How do other applications handle this defined sizing? Appears they use hard coded widths depending on format, which is similar here (using `size` instead of css `width`).
147
154
  // But would also need to allow for the input to be `fullWidth`, which is basically also what we're accomplishing here... so maybe fine?
148
- const inputSize = mode !== "range" ? (format === "short" ? 8 : format === "medium" ? 10 : undefined) : undefined;
155
+ const inputSize = !isRangeMode ? (format === "short" ? 8 : format === "medium" ? 10 : undefined) : undefined;
156
+ // Support input range filter field w/ a clear btn that will appear when overlay is closed and input is not focused
157
+ const clearButton = ((0, jsx_runtime_1.jsx)(jsx_runtime_1.Fragment, { children: inputValue !== "" && !state.isOpen && ((0, jsx_runtime_1.jsx)(components_1.IconButton, { icon: "xCircle", color: Css_1.Palette.Gray700, onClick: () => {
158
+ setInputValue("");
159
+ onChange(undefined);
160
+ } }, void 0)) }, void 0));
149
161
  const calendarButton = ((0, jsx_runtime_1.jsx)("button", Object.assign({ ref: buttonRef }, buttonProps, { disabled: isDisabled, css: Css_1.Css.if(isDisabled).cursorNotAllowed.$, tabIndex: -1 }, tid.calendarButton, { children: (0, jsx_runtime_1.jsx)(components_1.Icon, { icon: "calendar", color: Css_1.Palette.Gray700 }, void 0) }), void 0));
162
+ const EndFieldButtons = ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [isRangeFilterField && clearButton, !hideCalendarIcon && calendarButton] }, void 0));
150
163
  return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(TextFieldBase_1.TextFieldBase, Object.assign({}, textFieldProps, { errorMsg: errorMsg, helperText: helperText, required: required, labelProps: labelProps, inputProps: { ...triggerProps, ...inputProps, size: inputSize }, inputRef: inputRef, inputWrapRef: inputWrapRef, inlineLabel: inlineLabel, onChange: (v) => {
151
164
  // hide the calendar if the user is manually entering the date
152
165
  state.close();
153
166
  if (v) {
154
167
  setInputValue(v);
155
168
  // If changing the value directly (vs using the DatePicker), then we always use the short format
156
- const parsed = mode === "range" ? (0, utils_1.parseDateRange)(v, utils_1.dateFormats.short) : (0, utils_1.parseDate)(v, utils_1.dateFormats.short);
169
+ const parsed = isRangeMode ? (0, utils_1.parseDateRange)(v, utils_1.dateFormats.short) : (0, utils_1.parseDate)(v, utils_1.dateFormats.short);
157
170
  onChange(parsed);
158
171
  }
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) => {
172
+ // User has deleted all text in field
173
+ else if (v === undefined) {
174
+ setInputValue("");
175
+ }
176
+ }, endAdornment: !iconLeft && EndFieldButtons, 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: isRangeMode ? ((0, jsx_runtime_1.jsx)(internal_1.DateRangePicker, Object.assign({ range: wipValue, disabledDays: disabledDays, onSelect: (dr) => {
160
177
  var _a;
161
178
  // Note: Do not close date range picker on select to allow the user to select multiple dates at a time
162
179
  setInputValue((_a = (0, utils_1.formatDateRange)(dr, utils_1.dateFormats.short)) !== null && _a !== void 0 ? _a : "");
163
180
  onChange(dr);
164
- } }, tid.datePicker), void 0)) : ((0, jsx_runtime_1.jsx)(internal_1.DatePicker, Object.assign({ value: wipValue, disabledDays: disabledDays, onSelect: (d) => {
181
+ }, useYearPicker: isRangeFilterField }, tid.datePicker), void 0)) : ((0, jsx_runtime_1.jsx)(internal_1.DatePicker, Object.assign({ value: wipValue, disabledDays: disabledDays, onSelect: (d) => {
165
182
  var _a;
166
183
  setInputValue((_a = (0, utils_1.formatDate)(d, utils_1.dateFormats.short)) !== null && _a !== void 0 ? _a : "");
167
184
  onChange(d);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@homebound/beam",
3
- "version": "2.166.1",
3
+ "version": "2.169.0",
4
4
  "author": "Homebound",
5
5
  "license": "MIT",
6
6
  "main": "dist/index.js",