@homebound/beam 2.141.2 → 2.143.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.
Files changed (36) hide show
  1. package/dist/Css.d.ts +3 -0
  2. package/dist/Css.js +2 -0
  3. package/dist/components/ButtonDatePicker.js +6 -2
  4. package/dist/components/Icon.d.ts +2 -0
  5. package/dist/components/Icon.js +3 -1
  6. package/dist/components/internal/DatePicker/DatePicker.css +5 -0
  7. package/dist/components/internal/DatePicker/DatePickerOverlay.d.ts +3 -6
  8. package/dist/components/internal/DatePicker/DatePickerOverlay.js +2 -6
  9. package/dist/components/internal/DatePicker/DateRangePicker.d.ts +10 -0
  10. package/dist/components/internal/DatePicker/DateRangePicker.js +23 -0
  11. package/dist/components/internal/DatePicker/Day.js +22 -7
  12. package/dist/components/internal/DatePicker/index.d.ts +1 -0
  13. package/dist/components/internal/DatePicker/index.js +1 -0
  14. package/dist/forms/BoundDateRangeField.d.ts +10 -0
  15. package/dist/forms/BoundDateRangeField.js +27 -0
  16. package/dist/forms/formStateDomain.d.ts +3 -0
  17. package/dist/forms/formStateDomain.js +2 -1
  18. package/dist/forms/index.d.ts +1 -0
  19. package/dist/forms/index.js +1 -0
  20. package/dist/inputs/DateFields/DateField.d.ts +4 -0
  21. package/dist/inputs/DateFields/DateField.js +9 -0
  22. package/dist/inputs/{DateField.mock.d.ts → DateFields/DateField.mock.d.ts} +1 -1
  23. package/dist/inputs/{DateField.mock.js → DateFields/DateField.mock.js} +1 -1
  24. package/dist/inputs/{DateField.d.ts → DateFields/DateFieldBase.d.ts} +18 -11
  25. package/dist/inputs/{DateField.js → DateFields/DateFieldBase.js} +80 -83
  26. package/dist/inputs/DateFields/DateRangeField.d.ts +4 -0
  27. package/dist/inputs/DateFields/DateRangeField.js +9 -0
  28. package/dist/inputs/DateFields/index.d.ts +5 -0
  29. package/dist/inputs/DateFields/index.js +18 -0
  30. package/dist/inputs/DateFields/utils.d.ts +14 -0
  31. package/dist/inputs/DateFields/utils.js +82 -0
  32. package/dist/inputs/TextFieldBase.js +1 -1
  33. package/dist/inputs/index.d.ts +1 -1
  34. package/dist/inputs/index.js +1 -1
  35. package/dist/types.d.ts +2 -0
  36. package/package.json +2 -2
package/dist/Css.d.ts CHANGED
@@ -2849,6 +2849,9 @@ declare class CssBuilder<T extends Properties1> {
2849
2849
  } & {
2850
2850
  backgroundColor: import("csstype").Property.BackgroundColor | undefined;
2851
2851
  }>;
2852
+ get contentEmpty(): CssBuilder<T & {
2853
+ content: import("csstype").Property.Content | undefined;
2854
+ }>;
2852
2855
  get $(): T;
2853
2856
  if(t: boolean | Breakpoint): CssBuilder<T>;
2854
2857
  get else(): CssBuilder<T>;
package/dist/Css.js CHANGED
@@ -859,6 +859,8 @@ class CssBuilder {
859
859
  get listReset() { return this.add("padding", 0).add("margin", 0).add("listStyle", "none"); }
860
860
  // underlay
861
861
  get underlay() { return this.add("position", "fixed").add("top", 0).add("bottom", 0).add("left", 0).add("right", 0).add("display", "flex").add("alignItems", "center").add("justifyContent", "center").add("backgroundColor", "rgba(36,36,36,0.2)"); }
862
+ // contentEmpty
863
+ get contentEmpty() { return this.add("content", "''"); }
862
864
  // aliases
863
865
  get $() { return maybeImportant(sortObject(this.rules), this.opts.important); }
864
866
  if(t) {
@@ -5,16 +5,20 @@ const jsx_runtime_1 = require("@emotion/react/jsx-runtime");
5
5
  const react_1 = require("react");
6
6
  const react_aria_1 = require("react-aria");
7
7
  const react_stately_1 = require("react-stately");
8
+ const DatePicker_1 = require("./internal/DatePicker/DatePicker");
8
9
  const DatePickerOverlay_1 = require("./internal/DatePicker/DatePickerOverlay");
9
10
  const OverlayTrigger_1 = require("./internal/OverlayTrigger");
10
11
  const utils_1 = require("../utils");
11
12
  const defaultTestId_1 = require("../utils/defaultTestId");
12
13
  function ButtonDatePicker(props) {
13
- const { defaultOpen, disabled, trigger } = props;
14
+ const { defaultOpen, disabled, trigger, onSelect, ...datePickerProps } = props;
14
15
  const state = (0, react_stately_1.useMenuTriggerState)({ isOpen: defaultOpen });
15
16
  const buttonRef = (0, react_1.useRef)(null);
16
17
  const { menuTriggerProps, menuProps } = (0, react_aria_1.useMenuTrigger)({ isDisabled: !!disabled }, state, buttonRef);
17
18
  const tid = (0, utils_1.useTestIds)(props, (0, OverlayTrigger_1.isTextButton)(trigger) ? (0, defaultTestId_1.defaultTestId)(trigger.label) : trigger.icon);
18
- return ((0, jsx_runtime_1.jsx)(OverlayTrigger_1.OverlayTrigger, Object.assign({}, props, { menuTriggerProps: menuTriggerProps, state: state, buttonRef: buttonRef }, tid, { children: (0, jsx_runtime_1.jsx)(DatePickerOverlay_1.DatePickerOverlay, Object.assign({}, props, { state: state, overlayProps: menuProps }, tid.datePicker), void 0) }), void 0));
19
+ return ((0, jsx_runtime_1.jsx)(OverlayTrigger_1.OverlayTrigger, Object.assign({}, props, { menuTriggerProps: menuTriggerProps, state: state, buttonRef: buttonRef }, tid, { children: (0, jsx_runtime_1.jsx)(DatePickerOverlay_1.DatePickerOverlay, Object.assign({ overlayProps: menuProps }, { children: (0, jsx_runtime_1.jsx)(DatePicker_1.DatePicker, Object.assign({}, datePickerProps, { onSelect: (d) => {
20
+ onSelect(d);
21
+ state.close();
22
+ } }, tid.datePicker), void 0) }), void 0) }), void 0));
19
23
  }
20
24
  exports.ButtonDatePicker = ButtonDatePicker;
@@ -49,6 +49,7 @@ export declare const Icons: {
49
49
  attachment: import("@emotion/react/jsx-runtime").JSX.Element;
50
50
  archive: import("@emotion/react/jsx-runtime").JSX.Element;
51
51
  unarchive: import("@emotion/react/jsx-runtime").JSX.Element;
52
+ duplicate: import("@emotion/react/jsx-runtime").JSX.Element;
52
53
  errorCircle: import("@emotion/react/jsx-runtime").JSX.Element;
53
54
  checkCircle: import("@emotion/react/jsx-runtime").JSX.Element;
54
55
  infoCircle: import("@emotion/react/jsx-runtime").JSX.Element;
@@ -82,5 +83,6 @@ export declare const Icons: {
82
83
  templates: import("@emotion/react/jsx-runtime").JSX.Element;
83
84
  tradePartners: import("@emotion/react/jsx-runtime").JSX.Element;
84
85
  buildingHouse: import("@emotion/react/jsx-runtime").JSX.Element;
86
+ house: import("@emotion/react/jsx-runtime").JSX.Element;
85
87
  };
86
88
  export declare type IconKey = keyof typeof Icons;
@@ -50,6 +50,7 @@ exports.Icons = {
50
50
  attachment: ((0, jsx_runtime_1.jsx)("path", { d: "M5.70034 11.879L13.2477 4.15188C14.7481 2.61751 17.2048 2.61457 18.7439 4.15187C20.2147 5.69292 20.2456 8.1905 18.7439 9.72637L12.1677 16.4463C11.1677 17.4455 9.53953 17.4417 8.57861 16.4145L8.5763 16.4121C7.61217 15.4147 7.64468 13.8162 8.60983 12.8511L8.6113 12.8496L13.7859 7.56715C13.9307 7.42307 14.1608 7.40384 14.3248 7.56783L15.121 8.36403L15.1269 8.3691C15.2788 8.49929 15.2951 8.72507 15.1451 8.90458L9.9755 14.146C9.84287 14.2789 9.78341 14.4569 9.77747 14.6231C9.77157 14.7885 9.81776 14.9643 9.92515 15.0986L9.93923 15.1162L9.95684 15.1303C10.2011 15.3257 10.5715 15.346 10.8022 15.1153L17.3808 8.39291L17.3829 8.39073C18.1402 7.59359 18.1402 6.28461 17.3829 5.48747L17.3793 5.48379C16.6171 4.72167 15.3745 4.72167 14.6124 5.48379L14.6107 5.48549L7.06489 13.211L7.06402 13.2118C5.72803 14.5488 5.72839 16.7596 7.02689 18.0962C8.32851 19.4362 10.437 19.436 11.7387 18.0962L17.9191 11.7721C18.0556 11.6365 18.2859 11.6367 18.422 11.7728L19.2542 12.605L19.2601 12.6101C19.4197 12.7469 19.4187 12.9691 19.2846 13.1031L19.283 13.1048L13.1015 19.43C11.0256 21.5403 7.70624 21.5062 5.66445 19.4304C3.62176 17.3177 3.65669 13.9573 5.70034 11.879Z" }, void 0)),
51
51
  archive: ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)("path", { "fill-rule": "evenodd", d: "M19 10H5L5 18H19V10ZM3 8V18C3 19.1046 3.89543 20 5 20H19C20.1046 20 21 19.1046 21 18V8H3Z" }, void 0), (0, jsx_runtime_1.jsx)("path", { "fill-rule": "evenodd", d: "M3.81818 6V8H20.1818V6H3.81818ZM2.90909 4C2.40701 4 2 4.44772 2 5V9C2 9.55228 2.40701 10 2.90909 10H21.0909C21.593 10 22 9.55228 22 9V5C22 4.44772 21.593 4 21.0909 4H2.90909Z" }, void 0), (0, jsx_runtime_1.jsx)("rect", { x: "8", y: "11", width: "8", height: "2", rx: "1" }, void 0)] }, void 0)),
52
52
  unarchive: ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)("path", { d: "M13 12V8H16L12 3L8 8H11V12H13Z" }, void 0), (0, jsx_runtime_1.jsx)("path", { d: "M17 10H19V18H5L5 10H7V8H3V18C3 19.1046 3.89543 20 5 20H19C20.1046 20 21 19.1046 21 18V8H17V10Z" }, void 0), (0, jsx_runtime_1.jsx)("rect", { x: "8", y: "15", width: "8", height: "2", rx: "1" }, void 0)] }, void 0)),
53
+ duplicate: ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)("path", { d: "M11 10H9V13H6V15H9V18H11V15H14V13H11V10Z" }, void 0), (0, jsx_runtime_1.jsx)("path", { d: "M4 22H16C17.103 22 18 21.103 18 20V8C18 6.897 17.103 6 16 6H4C2.897 6 2 6.897 2 8V20C2 21.103 2.897 22 4 22ZM4 8H16L16.002 20H4V8Z" }, void 0), (0, jsx_runtime_1.jsx)("path", { d: "M20 2H8V4H20V16H22V4C22 2.897 21.103 2 20 2Z" }, void 0)] }, void 0)),
53
54
  // Alerts
54
55
  errorCircle: ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)("path", { d: "M11.953 2C6.465 2 2 6.486 2 12C2 17.514 6.486 22 12 22C17.514 22 22 17.514 22 12C22 6.486 17.493 2 11.953 2ZM12 20C7.589 20 4 16.411 4 12C4 7.589 7.567 4 11.953 4C16.391 4 20 7.589 20 12C20 16.411 16.411 20 12 20Z" }, void 0), (0, jsx_runtime_1.jsx)("path", { d: "M11 7H13V14H11V7ZM11 15H13V17H11V15Z" }, void 0)] }, void 0)),
55
56
  checkCircle: ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)("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" }, void 0), (0, jsx_runtime_1.jsx)("path", { d: "M9.99909 13.587L7.70009 11.292L6.28809 12.708L10.0011 16.413L16.7071 9.70697L15.2931 8.29297L9.99909 13.587Z" }, void 0)] }, void 0)),
@@ -87,5 +88,6 @@ exports.Icons = {
87
88
  finances: ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)("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" }, void 0), (0, jsx_runtime_1.jsx)("path", { d: "M12 11C10 11 10 10.374 10 9.99996C10 9.51596 10.701 8.99996 12 8.99996C13.185 8.99996 13.386 9.63796 13.4 10.018L14.4 9.99996H15.4C15.4 8.97396 14.734 7.53096 13 7.12096V6.01196H11V7.08496C9.029 7.41596 8 8.71196 8 9.99996C8 11.12 8.52 13 12 13C14 13 14 13.676 14 14C14 14.415 13.38 15 12 15C10.159 15 10.011 14.143 10 14H8C8 14.918 8.661 16.553 11 16.92V18H13V16.915C14.971 16.584 16 15.288 16 14C16 12.88 15.48 11 12 11Z" }, void 0)] }, void 0)),
88
89
  templates: ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)("path", { d: "M20 2H10C8.897 2 8 2.897 8 4V8H4C2.897 8 2 8.897 2 10V20C2 21.103 2.897 22 4 22H14C15.103 22 16 21.103 16 20V16H20C21.103 16 22 15.103 22 14V4C22 2.897 21.103 2 20 2ZM4 20V10H14L14.002 20H4ZM20 14H16V10C16 8.897 15.103 8 14 8H10V4H20V14Z" }, void 0), (0, jsx_runtime_1.jsx)("path", { d: "M6 12H12V14H6V12ZM6 16H12V18H6V16Z" }, void 0)] }, void 0)),
89
90
  tradePartners: ((0, jsx_runtime_1.jsx)("path", { d: "M5.12204 21C5.50004 21.378 6.00204 21.586 6.53604 21.586C7.07004 21.586 7.57204 21.378 7.95004 21L12.286 16.664C13.002 16.885 13.745 16.997 14.503 16.997C16.506 16.997 18.39 16.218 19.805 14.802C21.951 12.655 22.592 9.453 21.437 6.644L20.867 5.256L16.623 9.499L14.502 7.377L18.745 3.134L17.356 2.563C16.446 2.189 15.485 2 14.499 2C12.496 2 10.613 2.78 9.19804 4.196C7.21304 6.18 6.51604 9.068 7.33604 11.714L3.00004 16.05C2.22004 16.829 2.22004 18.099 3.00004 18.878L5.12204 21ZM9.67004 12.209L9.41604 11.593C8.56804 9.532 9.03804 7.183 10.612 5.61C11.65 4.572 13.03 4 14.499 4C14.676 4 14.851 4.008 15.025 4.025L11.672 7.378L16.621 12.328L19.976 8.973C20.132 10.581 19.573 12.204 18.389 13.389C16.839 14.939 14.425 15.416 12.405 14.585L11.79 14.33L6.53604 19.586H6.53704L6.53604 20.586V19.586L4.41404 17.464L9.67004 12.209Z" }, void 0)),
90
- buildingHouse: ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)("path", { d: "M19.0002 2.00002H9.00019C7.89719 2.00002 7.00019 2.89702 7.00019 4.00002V9.58602L2.29319 14.293C2.00719 14.579 1.92119 15.009 2.07619 15.383C2.23119 15.757 2.59619 16 3.00019 16V17V21C3.00019 21.553 3.44819 22 4.00019 22H12.0002H20.0002C20.5532 22 21.0002 21.553 21.0002 21V4.00002C21.0002 2.89702 20.1032 2.00002 19.0002 2.00002ZM11.0002 20H5.00019V17V15V14.414L8.00019 11.414L11.0002 14.414V15V18V20ZM19.0002 20H13.0002V18V16C13.4042 16 13.7702 15.757 13.9242 15.383C14.0792 15.009 13.9932 14.579 13.7072 14.293L9.00019 9.58602V4.00002H19.0002V20Z" }, void 0), (0, jsx_runtime_1.jsx)("path", { d: "M11 6.00002H13V8.00002H11V6.00002ZM15 6.00002H17V8.00002H15V6.00002ZM15 10.031H17V12H15V10.031ZM15 14H17V16H15V14ZM7 15H9V17H7V15Z" }, void 0)] }, void 0))
91
+ buildingHouse: ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)("path", { d: "M19.0002 2.00002H9.00019C7.89719 2.00002 7.00019 2.89702 7.00019 4.00002V9.58602L2.29319 14.293C2.00719 14.579 1.92119 15.009 2.07619 15.383C2.23119 15.757 2.59619 16 3.00019 16V17V21C3.00019 21.553 3.44819 22 4.00019 22H12.0002H20.0002C20.5532 22 21.0002 21.553 21.0002 21V4.00002C21.0002 2.89702 20.1032 2.00002 19.0002 2.00002ZM11.0002 20H5.00019V17V15V14.414L8.00019 11.414L11.0002 14.414V15V18V20ZM19.0002 20H13.0002V18V16C13.4042 16 13.7702 15.757 13.9242 15.383C14.0792 15.009 13.9932 14.579 13.7072 14.293L9.00019 9.58602V4.00002H19.0002V20Z" }, void 0), (0, jsx_runtime_1.jsx)("path", { d: "M11 6.00002H13V8.00002H11V6.00002ZM15 6.00002H17V8.00002H15V6.00002ZM15 10.031H17V12H15V10.031ZM15 14H17V16H15V14ZM7 15H9V17H7V15Z" }, void 0)] }, void 0)),
92
+ house: ((0, jsx_runtime_1.jsx)("path", { d: "M5.00299 22H9.00299H15.003H19.003C20.106 22 21.003 21.103 21.003 20V11C21.003 10.735 20.898 10.48 20.71 10.293L12.71 2.29301C12.319 1.90201 11.687 1.90201 11.296 2.29301L3.29599 10.293C3.10799 10.48 3.00299 10.735 3.00299 11V20C3.00299 21.103 3.89999 22 5.00299 22ZM10.003 20V15H14.003V20H10.003ZM5.00299 11.414L12.003 4.41401L19.003 11.414L19.004 20H16.003V15C16.003 13.897 15.106 13 14.003 13H10.003C8.89999 13 8.00299 13.897 8.00299 15V20H5.00299V11.414Z" }, void 0))
91
93
  };
@@ -14,6 +14,11 @@
14
14
  --rdp-outline-selected: 2px solid rgba(3,105,161,1);
15
15
  }
16
16
 
17
+ /* Added in By Beam */
18
+ .rdp-cell:focus-visible {
19
+ outline: 0;
20
+ }
21
+
17
22
  .rdp {
18
23
  /* Modified by Beam (1em -> 16px) */
19
24
  margin: 16px;
@@ -1,9 +1,6 @@
1
- import { HTMLAttributes } from "react";
2
- import { OverlayTriggerState } from "react-stately";
3
- import { DatePickerProps } from "./DatePicker";
4
- interface DatePickerOverlayProps extends DatePickerProps {
1
+ import { HTMLAttributes, PropsWithChildren } from "react";
2
+ interface DatePickerOverlayProps {
5
3
  overlayProps: HTMLAttributes<HTMLElement>;
6
- state: OverlayTriggerState;
7
4
  }
8
- export declare function DatePickerOverlay({ overlayProps, state, ...datePickerProps }: DatePickerOverlayProps): import("@emotion/react/jsx-runtime").JSX.Element;
5
+ export declare function DatePickerOverlay({ overlayProps, children }: PropsWithChildren<DatePickerOverlayProps>): import("@emotion/react/jsx-runtime").JSX.Element;
9
6
  export {};
@@ -2,16 +2,12 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.DatePickerOverlay = void 0;
4
4
  const jsx_runtime_1 = require("@emotion/react/jsx-runtime");
5
- const DatePicker_1 = require("./DatePicker");
6
5
  const Css_1 = require("../../../Css");
7
6
  // Small wrapper around DatePicker to provide necessary styling and state handling when displayed as an overlay.
8
- function DatePickerOverlay({ overlayProps, state, ...datePickerProps }) {
7
+ function DatePickerOverlay({ overlayProps, children }) {
9
8
  return (
10
9
  // Adds `tabIndex` so clicking within the DatePicker will provide a `e.relatedTarget` on blur and focus events.
11
10
  // This allows for components such as the DateField to conditionally trigger their 'onBlur' prop. E.g. If the user leaves the field to interact with the DatePicker, then don't call onBlur
12
- (0, jsx_runtime_1.jsx)("div", Object.assign({ css: Css_1.Css.br4.bshModal.$ }, overlayProps, { tabIndex: 0 }, { children: (0, jsx_runtime_1.jsx)(DatePicker_1.DatePicker, Object.assign({}, datePickerProps, { onSelect: (d) => {
13
- datePickerProps.onSelect(d);
14
- state.close();
15
- } }), void 0) }), void 0));
11
+ (0, jsx_runtime_1.jsx)("div", Object.assign({ css: Css_1.Css.br4.bshModal.$ }, overlayProps, { tabIndex: 0 }, { children: children }), void 0));
16
12
  }
17
13
  exports.DatePickerOverlay = DatePickerOverlay;
@@ -0,0 +1,10 @@
1
+ import { Matcher } from "react-day-picker";
2
+ import { DateRange } from "../../../types";
3
+ import "./DatePicker.css";
4
+ export interface DateRangePickerProps {
5
+ range: DateRange | undefined;
6
+ onSelect: (range: DateRange | undefined) => void;
7
+ disabledDays?: Matcher | Matcher[];
8
+ dottedDays?: Matcher[];
9
+ }
10
+ export declare function DateRangePicker(props: DateRangePickerProps): import("@emotion/react/jsx-runtime").JSX.Element;
@@ -0,0 +1,23 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DateRangePicker = void 0;
4
+ const jsx_runtime_1 = require("@emotion/react/jsx-runtime");
5
+ const react_day_picker_1 = require("react-day-picker");
6
+ const Day_1 = require("./Day");
7
+ const Header_1 = require("./Header");
8
+ const WeekHeader_1 = require("./WeekHeader");
9
+ const Css_1 = require("../../../Css");
10
+ const utils_1 = require("../../../utils");
11
+ require("./DatePicker.css");
12
+ function DateRangePicker(props) {
13
+ var _a;
14
+ const { range, onSelect, disabledDays, dottedDays } = props;
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) => {
17
+ // Disallow returning disabled dates.
18
+ if (activeModifiers.disabled)
19
+ return;
20
+ onSelect(selection);
21
+ }, disabled: disabledDays, modifiers: { indicatorDot: dottedDays !== null && dottedDays !== void 0 ? dottedDays : [] } }, void 0) }), void 0));
22
+ }
23
+ exports.DateRangePicker = DateRangePicker;
@@ -19,22 +19,37 @@ function Day(props) {
19
19
  return (0, jsx_runtime_1.jsx)("div", Object.assign({}, divProps), void 0);
20
20
  }
21
21
  const { className, children, ...otherProps } = buttonProps;
22
- const { selected = false, indicatorDot = false, disabled = false, today = false } = activeModifiers;
22
+ const { selected = false, indicatorDot = false, disabled = false, today = false, range_middle = false, range_start = false, range_end = false, } = activeModifiers;
23
+ // It is possible that we have selected only one day for the range. In this case the date will be both the start and end.
24
+ // When this happens, do not show styling as if there is an existing range.
25
+ const showRangeStyles = !(range_end === true && range_start === true);
26
+ const showActiveStyles = !disabled;
23
27
  return ((0, jsx_runtime_1.jsx)("button", Object.assign({}, otherProps, { ref: buttonRef, type: "button", css: {
24
- ...Css_1.Css.overflowHidden.pbPx(4).if(disabled).cursorNotAllowed.$,
28
+ ...Css_1.Css.relative.pbPx(4).outline0.if(disabled).cursorNotAllowed.$,
25
29
  // Do not apply interaction styles for disabled or already selected days.
26
30
  ...(!selected &&
27
31
  !disabled && {
28
32
  "&:hover:not(:active) > div": Css_1.Css.bgGray100.$,
29
- "&:active > div": Css_1.Css.bgGray400.$,
30
33
  }),
34
+ ...(!disabled && { "&:active > div": Css_1.Css.bgGray400.gray900.$ }),
35
+ "&:focus:not(:active) > div": Css_1.Css.ba.bLightBlue700.if(selected).bLightBlue900.$,
36
+ ...(showRangeStyles &&
37
+ range_start &&
38
+ Css_1.Css.addIn(":after", { ...rangeBaseStyles, ...Css_1.Css.rightPx(-2).wPx(8).$ }).$),
39
+ ...(showRangeStyles && range_end && Css_1.Css.addIn(":after", { ...rangeBaseStyles, ...Css_1.Css.wPx(8).leftPx(-2).$ }).$),
40
+ ...(showRangeStyles && range_middle && Css_1.Css.addIn(":after", { ...rangeBaseStyles, ...Css_1.Css.leftPx(-2).$ }).$),
31
41
  } }, tid, { children: (0, jsx_runtime_1.jsxs)("div", Object.assign({ css: {
32
- ...Css_1.Css.relative.br4.df.aic.jcc.wPx(28).hPx(30).mtPx(2).br4.$,
33
- ...(today && Css_1.Css.bgGray100.$),
34
- ...(selected && Css_1.Css.white.bgLightBlue700.$),
42
+ ...Css_1.Css.overflowHidden.gray900.relative.z1.br4.df.aic.jcc.wPx(28).hPx(30).mtPx(2).br4.$,
43
+ ...(today && !range_middle && Css_1.Css.bgGray100.$),
44
+ ...(selected && !range_middle && Css_1.Css.white.bgLightBlue700.$),
35
45
  ...(disabled && Css_1.Css.gray500.$),
36
46
  } }, { children: [(0, jsx_runtime_1.jsx)("div", Object.assign({ css: Css_1.Css.mtPx(-2).$ }, { children: children }), void 0), indicatorDot && ((0, jsx_runtime_1.jsx)("div", Object.assign({
37
47
  // Using `absolute` position as to not change the placement of the day's number when this is introduced
38
- css: Css_1.Css.absolute.bottomPx(4).wPx(4).hPx(4).bgLightBlue700.br4.if(selected).bgWhite.$ }, tid.indicatorDot), void 0))] }), void 0) }), void 0));
48
+ css: Css_1.Css.absolute
49
+ .bottomPx(4)
50
+ .wPx(4)
51
+ .hPx(4)
52
+ .bgLightBlue700.br4.if(selected && !range_middle).bgWhite.$ }, tid.indicatorDot), void 0))] }), void 0) }), void 0));
39
53
  }
40
54
  exports.Day = Day;
55
+ const rangeBaseStyles = Css_1.Css.absolute.topPx(2).contentEmpty.hPx(30).wPx(32).bgLightBlue100.$;
@@ -1,2 +1,3 @@
1
1
  export * from "./DatePicker";
2
2
  export * from "./DatePickerOverlay";
3
+ export * from "./DateRangePicker";
@@ -12,3 +12,4 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
12
12
  Object.defineProperty(exports, "__esModule", { value: true });
13
13
  __exportStar(require("./DatePicker"), exports);
14
14
  __exportStar(require("./DatePickerOverlay"), exports);
15
+ __exportStar(require("./DateRangePicker"), exports);
@@ -0,0 +1,10 @@
1
+ import { FieldState } from "@homebound/form-state";
2
+ import { DateRangeFieldProps } from "../inputs";
3
+ import { DateRange } from "../types";
4
+ export declare type BoundDateRangeFieldProps = Omit<DateRangeFieldProps, "label" | "value" | "onChange"> & {
5
+ field: FieldState<any, DateRange | null | undefined>;
6
+ label?: string;
7
+ onChange?: (value: DateRange) => void;
8
+ };
9
+ /** Wraps `TextField` and binds it to a form field. */
10
+ export declare function BoundDateRangeField(props: BoundDateRangeFieldProps): import("@emotion/react/jsx-runtime").JSX.Element;
@@ -0,0 +1,27 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.BoundDateRangeField = void 0;
4
+ const jsx_runtime_1 = require("@emotion/react/jsx-runtime");
5
+ const mobx_react_1 = require("mobx-react");
6
+ const inputs_1 = require("../inputs");
7
+ const utils_1 = require("../utils");
8
+ const defaultLabel_1 = require("../utils/defaultLabel");
9
+ /** Wraps `TextField` and binds it to a form field. */
10
+ function BoundDateRangeField(props) {
11
+ const { field, onChange = (value) => field.set(value), label = (0, defaultLabel_1.defaultLabel)(field.key), onBlur, onFocus, onEnter, ...others } = props;
12
+ const testId = (0, utils_1.useTestIds)(props, field.key);
13
+ return ((0, jsx_runtime_1.jsx)(mobx_react_1.Observer, { children: () => ((0, jsx_runtime_1.jsx)(inputs_1.DateRangeField, Object.assign({ label: label, value: field.value || undefined, onChange: (value) => {
14
+ onChange(value);
15
+ field.maybeAutoSave();
16
+ }, errorMsg: field.touched ? field.errors.join(" ") : undefined, required: field.required, onBlur: () => {
17
+ field.blur();
18
+ (0, utils_1.maybeCall)(onBlur);
19
+ }, onFocus: () => {
20
+ field.focus();
21
+ (0, utils_1.maybeCall)(onFocus);
22
+ }, onEnter: () => {
23
+ (0, utils_1.maybeCall)(onEnter);
24
+ field.maybeAutoSave();
25
+ } }, testId, others), void 0)) }, void 0));
26
+ }
27
+ exports.BoundDateRangeField = BoundDateRangeField;
@@ -1,6 +1,8 @@
1
+ import { DateRange } from "../types";
1
2
  export declare const jan1: Date;
2
3
  export declare const jan2: Date;
3
4
  export declare const jan10: Date;
5
+ export declare const jan19: Date;
4
6
  export declare const jan29: Date;
5
7
  export declare const dd100: DeweyDecimalClassification;
6
8
  export declare const dd200: DeweyDecimalClassification;
@@ -20,6 +22,7 @@ export interface AuthorInput {
20
22
  isAvailable?: boolean | null;
21
23
  animals?: string[] | null;
22
24
  bio?: string | null;
25
+ saleDates?: DateRange | null;
23
26
  }
24
27
  export interface AuthorAddress {
25
28
  street?: string | null;
@@ -3,10 +3,11 @@
3
3
  // by a GraphQL schema for a `saveAuthor` mutation that takes an author
4
4
  // plus the author's books.
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.DateOnly = exports.dd200 = exports.dd100 = exports.jan29 = exports.jan10 = exports.jan2 = exports.jan1 = void 0;
6
+ exports.DateOnly = exports.dd200 = exports.dd100 = exports.jan29 = exports.jan19 = exports.jan10 = exports.jan2 = exports.jan1 = void 0;
7
7
  exports.jan1 = new Date(2020, 0, 1);
8
8
  exports.jan2 = new Date(2020, 0, 2);
9
9
  exports.jan10 = new Date(2020, 0, 10);
10
+ exports.jan19 = new Date(2020, 0, 19);
10
11
  exports.jan29 = new Date(2020, 0, 29);
11
12
  exports.dd100 = { number: "100", category: "Philosophy" };
12
13
  exports.dd200 = { number: "200", category: "Religion" };
@@ -2,6 +2,7 @@ export * from "./BoundCheckboxField";
2
2
  export * from "./BoundCheckboxGroupField";
3
3
  export * from "./BoundChipSelectField";
4
4
  export * from "./BoundDateField";
5
+ export * from "./BoundDateRangeField";
5
6
  export * from "./BoundMultiSelectField";
6
7
  export * from "./BoundNumberField";
7
8
  export * from "./BoundRadioGroupField";
@@ -14,6 +14,7 @@ __exportStar(require("./BoundCheckboxField"), exports);
14
14
  __exportStar(require("./BoundCheckboxGroupField"), exports);
15
15
  __exportStar(require("./BoundChipSelectField"), exports);
16
16
  __exportStar(require("./BoundDateField"), exports);
17
+ __exportStar(require("./BoundDateRangeField"), exports);
17
18
  __exportStar(require("./BoundMultiSelectField"), exports);
18
19
  __exportStar(require("./BoundNumberField"), exports);
19
20
  __exportStar(require("./BoundRadioGroupField"), exports);
@@ -0,0 +1,4 @@
1
+ import { DateSingleFieldBaseProps } from "./DateFieldBase";
2
+ export interface DateFieldProps extends Omit<DateSingleFieldBaseProps, "mode"> {
3
+ }
4
+ export declare function DateField(props: DateFieldProps): import("@emotion/react/jsx-runtime").JSX.Element;
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DateField = void 0;
4
+ const jsx_runtime_1 = require("@emotion/react/jsx-runtime");
5
+ const DateFieldBase_1 = require("./DateFieldBase");
6
+ function DateField(props) {
7
+ return (0, jsx_runtime_1.jsx)(DateFieldBase_1.DateFieldBase, Object.assign({}, props, { mode: "single" }), void 0);
8
+ }
9
+ exports.DateField = DateField;
@@ -1,3 +1,3 @@
1
- import { DateFieldProps } from "./";
1
+ import { DateFieldProps } from "..";
2
2
  /** Mocks out `DateField` as a text `<input>` field. */
3
3
  export declare function DateField(props: DateFieldProps): import("@emotion/react/jsx-runtime").JSX.Element;
@@ -4,7 +4,7 @@ exports.DateField = 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_1 = require("react");
7
- const utils_1 = require("../utils");
7
+ const utils_1 = require("../../utils");
8
8
  /** Mocks out `DateField` as a text `<input>` field. */
9
9
  function DateField(props) {
10
10
  const { onChange = () => { }, errorMsg, onBlur, onFocus } = props;
@@ -1,10 +1,10 @@
1
1
  import { ReactNode } from "react";
2
2
  import { Matcher } from "react-day-picker";
3
- import { TextFieldBaseProps } from "./TextFieldBase";
4
- export interface DateFieldProps extends Pick<TextFieldBaseProps<{}>, "borderless" | "visuallyDisabled" | "hideLabel" | "compact"> {
5
- value: Date | undefined;
3
+ import { DateFieldMode, dateFormats } from "./utils";
4
+ import { TextFieldBaseProps } from "../TextFieldBase";
5
+ import { DateRange } from "../../types";
6
+ export interface DateFieldBaseProps extends Pick<TextFieldBaseProps<{}>, "borderless" | "visuallyDisabled" | "hideLabel" | "compact"> {
6
7
  label: string;
7
- onChange: (value: Date) => void;
8
8
  /** Called when the component loses focus */
9
9
  onBlur?: () => void;
10
10
  /** Called when the component is in focus. */
@@ -27,12 +27,19 @@ export interface DateFieldProps extends Pick<TextFieldBaseProps<{}>, "borderless
27
27
  */
28
28
  disabledDays?: Matcher | Matcher[];
29
29
  onEnter?: VoidFunction;
30
+ /** for storybook */
30
31
  defaultOpen?: boolean;
32
+ onChange: ((value: Date) => void) | ((value: DateRange) => void);
33
+ mode: DateFieldMode;
34
+ }
35
+ export interface DateSingleFieldBaseProps extends DateFieldBaseProps {
36
+ mode: "single";
37
+ value: Date | undefined;
38
+ onChange: (value: Date) => void;
39
+ }
40
+ export interface DateRangeFieldBaseProps extends DateFieldBaseProps {
41
+ mode: "range";
42
+ value: DateRange | undefined;
43
+ onChange: (value: DateRange) => void;
31
44
  }
32
- export declare function DateField(props: DateFieldProps): import("@emotion/react/jsx-runtime").JSX.Element;
33
- declare const dateFormats: {
34
- short: string;
35
- medium: string;
36
- long: string;
37
- };
38
- export {};
45
+ export declare function DateFieldBase(props: DateRangeFieldBaseProps | DateSingleFieldBaseProps): import("@emotion/react/jsx-runtime").JSX.Element;
@@ -1,20 +1,24 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.DateField = void 0;
3
+ exports.DateFieldBase = void 0;
4
4
  const jsx_runtime_1 = require("@emotion/react/jsx-runtime");
5
- const date_fns_1 = require("date-fns");
6
5
  const react_1 = require("react");
7
6
  const react_aria_1 = require("react-aria");
7
+ const react_day_picker_1 = require("react-day-picker");
8
8
  const react_stately_1 = require("react-stately");
9
- const components_1 = require("../components");
10
- const internal_1 = require("../components/internal");
11
- const DatePickerOverlay_1 = require("../components/internal/DatePicker/DatePickerOverlay");
12
- const Css_1 = require("../Css");
13
- const TextFieldBase_1 = require("./TextFieldBase");
14
- const utils_1 = require("../utils");
15
- const defaultTestId_1 = require("../utils/defaultTestId");
16
- function DateField(props) {
17
- const { label, disabled, required, value, onChange, onFocus, onBlur, errorMsg, helperText, inlineLabel = false, readOnly, format = "short", iconLeft = false, disabledDays, onEnter, defaultOpen, ...others } = props;
9
+ const components_1 = require("../../components");
10
+ const internal_1 = require("../../components/internal");
11
+ const DatePickerOverlay_1 = require("../../components/internal/DatePicker/DatePickerOverlay");
12
+ const Css_1 = require("../../Css");
13
+ const utils_1 = require("./utils");
14
+ const TextFieldBase_1 = require("../TextFieldBase");
15
+ const utils_2 = require("../../utils");
16
+ const defaultTestId_1 = require("../../utils/defaultTestId");
17
+ function DateFieldBase(props) {
18
+ var _a;
19
+ const { label, disabled, required, value, onFocus, onBlur,
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;
18
22
  const inputRef = (0, react_1.useRef)(null);
19
23
  const inputWrapRef = (0, react_1.useRef)(null);
20
24
  const buttonRef = (0, react_1.useRef)(null);
@@ -22,19 +26,14 @@ function DateField(props) {
22
26
  // Local focus state to conditionally call onBlur when the date picker closes.
23
27
  // E.g. If the picker closes due to focus going back to the input field then don't call onBlur. Also used to avoid updating WIP values
24
28
  const [isFocused, setIsFocused] = (0, react_1.useState)(false);
25
- const dateFormat = getDateFormat(format);
26
- const [inputValue, setInputValue] = (0, react_1.useState)(value ? formatDate(value, dateFormat) : "");
27
- const tid = (0, utils_1.useTestIds)(props, (0, defaultTestId_1.defaultTestId)(label));
29
+ const dateFormat = (0, utils_1.getDateFormat)(format);
30
+ // The `wipValue` allows the "range" mode to set the value to `undefined`, even if the `onChange` response cannot be undefined.
31
+ // This makes working within the DateRangePicker much more user friendly.
32
+ 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 tid = (0, utils_2.useTestIds)(props, (0, defaultTestId_1.defaultTestId)(label));
28
35
  const isDisabled = !!disabled;
29
36
  const isReadOnly = !!readOnly;
30
- // Handle case where the input value is updated from outside the component.
31
- (0, react_1.useEffect)(() => {
32
- // Avoid updating any WIP values.
33
- if (!isFocused) {
34
- setInputValue(value ? formatDate(value, dateFormat) : "");
35
- }
36
- // eslint-disable-next-line react-hooks/exhaustive-deps - Do not include `isFocused`, we don't want to update the internal `inputValue` back to `value` just because focus state changes
37
- }, [value, dateFormat]);
38
37
  const textFieldProps = {
39
38
  ...others,
40
39
  label,
@@ -47,7 +46,7 @@ function DateField(props) {
47
46
  onOpenChange: (isOpen) => {
48
47
  // Handles calling `onBlur` for the case where the user interacts with the overlay, removing focus from the input field, and eventually closes the overlay (whether clicking away, or selecting a date)
49
48
  if (!isOpen && !isFocused) {
50
- (0, utils_1.maybeCall)(onBlur);
49
+ (0, utils_2.maybeCall)(onBlur);
51
50
  }
52
51
  },
53
52
  isOpen: defaultOpen,
@@ -55,16 +54,20 @@ function DateField(props) {
55
54
  const { labelProps, inputProps } = (0, react_aria_1.useTextField)({
56
55
  ...textFieldProps,
57
56
  onFocus: () => {
57
+ var _a;
58
58
  // Open overlay on focus of the input.
59
59
  state.open();
60
60
  setIsFocused(true);
61
- (0, utils_1.maybeCall)(onFocus);
62
- if (value) {
61
+ (0, utils_2.maybeCall)(onFocus);
62
+ if (wipValue && dateFormat !== utils_1.dateFormats.short) {
63
63
  // When focused, change to use the "short" date format, as it is simpler to update by hand and parse.
64
- setInputValue(formatDate(value, dateFormats.short));
64
+ setInputValue((_a = (props.mode === "range"
65
+ ? (0, utils_1.formatDateRange)(props.value, utils_1.dateFormats.short)
66
+ : (0, utils_1.formatDate)(props.value, utils_1.dateFormats.short))) !== null && _a !== void 0 ? _a : "");
65
67
  }
66
68
  },
67
69
  onBlur: (e) => {
70
+ var _a, _b;
68
71
  setIsFocused(false);
69
72
  // If we are interacting any other part of `inputWrap` ref (such as the calendar button) return early as clicking anywhere within there will push focus to the input field.
70
73
  // Or if interacting with the DatePicker then also return early. The overlay will handle calling `onBlur` once it closes.
@@ -72,22 +75,23 @@ function DateField(props) {
72
75
  (overlayRef.current && overlayRef.current.contains(e.relatedTarget))) {
73
76
  return;
74
77
  }
75
- const parsedDate = parseDate(inputValue, dateFormats.short);
78
+ const parsedDate = mode === "range" ? (0, utils_1.parseDateRange)(inputValue, utils_1.dateFormats.short) : (0, utils_1.parseDate)(inputValue, utils_1.dateFormats.short);
76
79
  // If the user leaves the input and has an invalid date, reset to previous value.
77
- if (!parsedDate) {
78
- setInputValue(value ? formatDate(value, dateFormat) : "");
80
+ if (!isParsedDateValid(parsedDate)) {
81
+ 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 : "");
79
83
  }
80
- else if (dateFormat !== dateFormats.short) {
84
+ else if (dateFormat !== utils_1.dateFormats.short) {
81
85
  // Or if we need to reset the dateFormat back from `short` to whatever the user specified
82
- setInputValue(formatDate(parsedDate, dateFormat));
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 : "");
83
87
  }
84
88
  state.close();
85
- (0, utils_1.maybeCall)(onBlur);
89
+ (0, utils_2.maybeCall)(onBlur);
86
90
  },
87
91
  onKeyDown: (e) => {
88
92
  var _a;
89
93
  if (e.key === "Enter") {
90
- (0, utils_1.maybeCall)(onEnter);
94
+ (0, utils_2.maybeCall)(onEnter);
91
95
  (_a = inputRef.current) === null || _a === void 0 ? void 0 : _a.blur();
92
96
  }
93
97
  },
@@ -110,13 +114,38 @@ function DateField(props) {
110
114
  shouldUpdatePosition: true,
111
115
  offset: 4,
112
116
  });
117
+ // Handle case where the input value is updated from outside the component.
118
+ (0, react_1.useEffect)(() => {
119
+ var _a;
120
+ // Avoid updating any WIP values.
121
+ if (!isFocused && !state.isOpen) {
122
+ 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 : "");
124
+ }
125
+ // eslint-disable-next-line react-hooks/exhaustive-deps - Do not include `isFocused` or `state.isOpen`.
126
+ // We don't want to update the internal `wipValue` or `inputValue` back to `value` just because focus state changes or the overlay opens
127
+ }, [value, dateFormat]);
128
+ // Create a type safe `onChange` to handle both Single and Range date fields.
129
+ const onChange = (0, react_1.useCallback)((d) => {
130
+ setWipValue(d);
131
+ if (d && isParsedDateValid(d)) {
132
+ if (props.mode === "range" && (0, react_day_picker_1.isDateRange)(d)) {
133
+ props.onChange(d);
134
+ return;
135
+ }
136
+ if (props.mode === "single" && !(0, react_day_picker_1.isDateRange)(d)) {
137
+ props.onChange(d);
138
+ return;
139
+ }
140
+ }
141
+ }, [mode, props.onChange]);
113
142
  // 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)
114
143
  // Otherwise the long format can be `undefined`.
115
144
  // 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.
116
145
  // TODO: figure this out... seems weird to have now that we support multiple dates formats....
117
146
  // 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`).
118
147
  // But would also need to allow for the input to be `fullWidth`, which is basically also what we're accomplishing here... so maybe fine?
119
- const inputSize = format === "short" ? 8 : format === "medium" ? 10 : undefined;
148
+ const inputSize = mode !== "range" ? (format === "short" ? 8 : format === "medium" ? 10 : undefined) : undefined;
120
149
  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));
121
150
  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) => {
122
151
  // hide the calendar if the user is manually entering the date
@@ -124,55 +153,23 @@ function DateField(props) {
124
153
  if (v) {
125
154
  setInputValue(v);
126
155
  // If changing the value directly (vs using the DatePicker), then we always use the short format
127
- const parsed = parseDate(v, dateFormats.short);
128
- if (parsed) {
129
- onChange(parsed);
130
- }
156
+ const parsed = mode === "range" ? (0, utils_1.parseDateRange)(v, utils_1.dateFormats.short) : (0, utils_1.parseDate)(v, utils_1.dateFormats.short);
157
+ onChange(parsed);
131
158
  }
132
- }, 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({ value: value, onSelect: (d) => {
133
- setInputValue(formatDate(d, dateFormat));
134
- onChange(d);
135
- }, state: state, disabledDays: disabledDays, overlayProps: overlayProps }, tid.datePicker), void 0) }), void 0))] }, void 0));
136
- }
137
- exports.DateField = DateField;
138
- function formatDate(date, format) {
139
- return (0, date_fns_1.format)(date, format);
140
- }
141
- function parseDate(str, format) {
142
- // Copy/pasted from react-day-picker so that typing "2/2/2" doesn't turn into "02/02/0002"
143
- const split = str.split("/");
144
- if (split.length !== 3) {
145
- return undefined;
146
- }
147
- // Wait for the year to be 2 chars
148
- if (split[2].length !== 2) {
149
- return undefined;
150
- }
151
- const month = parseInt(split[0], 10) - 1;
152
- const day = parseInt(split[1], 10);
153
- let year = parseInt(split[2], 10);
154
- // This is also ~verbatim copy/pasted from react-day-picker
155
- if (isNaN(year) ||
156
- String(year).length > 4 ||
157
- isNaN(month) ||
158
- isNaN(day) ||
159
- day <= 0 ||
160
- day > 31 ||
161
- month < 0 ||
162
- month >= 12) {
163
- return undefined;
164
- }
165
- const parsed = (0, date_fns_1.parse)(str, format, new Date());
166
- if (!(0, date_fns_1.isDate)(parsed)) {
167
- return undefined;
168
- }
169
- return parsed;
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) => {
160
+ var _a;
161
+ // Note: Do not close date range picker on select to allow the user to select multiple dates at a time
162
+ setInputValue((_a = (0, utils_1.formatDateRange)(dr, utils_1.dateFormats.short)) !== null && _a !== void 0 ? _a : "");
163
+ onChange(dr);
164
+ } }, tid.datePicker), void 0)) : ((0, jsx_runtime_1.jsx)(internal_1.DatePicker, Object.assign({ value: wipValue, disabledDays: disabledDays, onSelect: (d) => {
165
+ var _a;
166
+ setInputValue((_a = (0, utils_1.formatDate)(d, utils_1.dateFormats.short)) !== null && _a !== void 0 ? _a : "");
167
+ onChange(d);
168
+ state.close();
169
+ } }, tid.datePicker), void 0)) }), void 0) }), void 0))] }, void 0));
170
170
  }
171
- const dateFormats = {
172
- short: "MM/dd/yy",
173
- medium: "EEE, MMM d",
174
- long: "EEEE LLLL d, uuuu",
175
- };
176
- function getDateFormat(format) {
177
- return format ? dateFormats[format] : dateFormats.short;
171
+ exports.DateFieldBase = DateFieldBase;
172
+ function isParsedDateValid(d) {
173
+ // Only consider a DateRange valid when both `from` and `to` values are valid dates
174
+ return d !== undefined && (!(0, react_day_picker_1.isDateRange)(d) || ((0, react_day_picker_1.isDateRange)(d) && (0, utils_1.isValidDate)(d.from) && (0, utils_1.isValidDate)(d.to)));
178
175
  }
@@ -0,0 +1,4 @@
1
+ import { DateRangeFieldBaseProps } from "./DateFieldBase";
2
+ export interface DateRangeFieldProps extends Omit<DateRangeFieldBaseProps, "mode"> {
3
+ }
4
+ export declare function DateRangeField(props: DateRangeFieldProps): import("@emotion/react/jsx-runtime").JSX.Element;
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DateRangeField = void 0;
4
+ const jsx_runtime_1 = require("@emotion/react/jsx-runtime");
5
+ const DateFieldBase_1 = require("./DateFieldBase");
6
+ function DateRangeField(props) {
7
+ return (0, jsx_runtime_1.jsx)(DateFieldBase_1.DateFieldBase, Object.assign({}, props, { mode: "range" }), void 0);
8
+ }
9
+ exports.DateRangeField = DateRangeField;
@@ -0,0 +1,5 @@
1
+ export { DateField } from "./DateField";
2
+ export type { DateFieldProps } from "./DateField";
3
+ export { DateRangeField } from "./DateRangeField";
4
+ export type { DateRangeFieldProps } from "./DateRangeField";
5
+ export * from "./utils";
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
5
+ }) : (function(o, m, k, k2) {
6
+ if (k2 === undefined) k2 = k;
7
+ o[k2] = m[k];
8
+ }));
9
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
10
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
11
+ };
12
+ Object.defineProperty(exports, "__esModule", { value: true });
13
+ exports.DateRangeField = exports.DateField = void 0;
14
+ var DateField_1 = require("./DateField");
15
+ Object.defineProperty(exports, "DateField", { enumerable: true, get: function () { return DateField_1.DateField; } });
16
+ var DateRangeField_1 = require("./DateRangeField");
17
+ Object.defineProperty(exports, "DateRangeField", { enumerable: true, get: function () { return DateRangeField_1.DateRangeField; } });
18
+ __exportStar(require("./utils"), exports);
@@ -0,0 +1,14 @@
1
+ import { DateRange } from "../../types";
2
+ export declare type DateFieldModeTuple = readonly ["range", DateRange] | readonly ["single", Date];
3
+ export declare type DateFieldMode = "single" | "range";
4
+ export declare const dateFormats: {
5
+ short: string;
6
+ medium: string;
7
+ long: string;
8
+ };
9
+ export declare function getDateFormat(format: keyof typeof dateFormats | undefined): string;
10
+ export declare function formatDate(date: Date | undefined, format: string): string;
11
+ export declare function formatDateRange(date: DateRange | undefined, format: string): string | undefined;
12
+ export declare function parseDate(str: string, format: string): Date | undefined;
13
+ export declare function parseDateRange(str: string, format: string): DateRange | undefined;
14
+ export declare function isValidDate(d: Date | undefined): boolean;
@@ -0,0 +1,82 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.isValidDate = exports.parseDateRange = exports.parseDate = exports.formatDateRange = exports.formatDate = exports.getDateFormat = exports.dateFormats = void 0;
4
+ const date_fns_1 = require("date-fns");
5
+ exports.dateFormats = {
6
+ short: "MM/dd/yy",
7
+ medium: "EEE, MMM d",
8
+ long: "EEEE LLLL d, uuuu",
9
+ };
10
+ function getDateFormat(format) {
11
+ return format ? exports.dateFormats[format] : exports.dateFormats.short;
12
+ }
13
+ exports.getDateFormat = getDateFormat;
14
+ function formatDate(date, format) {
15
+ if (!date)
16
+ return "";
17
+ return (0, date_fns_1.format)(date, format);
18
+ }
19
+ exports.formatDate = formatDate;
20
+ function formatDateRange(date, format) {
21
+ if (!date)
22
+ return "";
23
+ const { from, to } = date;
24
+ const fromFormatted = from ? (0, date_fns_1.format)(from, format) : "";
25
+ const toFormatted = to ? (0, date_fns_1.format)(to, format) : "";
26
+ // return `undefined` if both dates are improperly formatted
27
+ return !fromFormatted && !toFormatted ? undefined : `${fromFormatted} - ${toFormatted}`;
28
+ }
29
+ exports.formatDateRange = formatDateRange;
30
+ function parseDate(str, format) {
31
+ return parseDateString(str, format);
32
+ }
33
+ exports.parseDate = parseDate;
34
+ function parseDateRange(str, format) {
35
+ const [from = "", to = ""] = str.split("-");
36
+ const fromDate = parseDateString(from.trim(), format);
37
+ const toDate = parseDateString(to.trim(), format);
38
+ // In the event the user mixes up the to/from dates then correct them.
39
+ if (toDate && fromDate && toDate < fromDate) {
40
+ return { from: toDate, to: fromDate };
41
+ }
42
+ // If both dates are undefined, return undefined rather than { from: undefined; to: undefined }
43
+ if (toDate === undefined && fromDate === undefined) {
44
+ return undefined;
45
+ }
46
+ return { from: fromDate, to: toDate };
47
+ }
48
+ exports.parseDateRange = parseDateRange;
49
+ function parseDateString(str, format) {
50
+ // Copy/pasted from react-day-picker so that typing "2/2/2" doesn't turn into "02/02/0002"
51
+ const split = str.split("/");
52
+ if (split.length !== 3) {
53
+ return undefined;
54
+ }
55
+ // Wait for the year to be 2 chars
56
+ if (split[2].length !== 2) {
57
+ return undefined;
58
+ }
59
+ const month = parseInt(split[0], 10) - 1;
60
+ const day = parseInt(split[1], 10);
61
+ let year = parseInt(split[2], 10);
62
+ // This is also ~verbatim copy/pasted from react-day-picker
63
+ if (isNaN(year) ||
64
+ String(year).length > 4 ||
65
+ isNaN(month) ||
66
+ isNaN(day) ||
67
+ day <= 0 ||
68
+ day > 31 ||
69
+ month < 0 ||
70
+ month >= 12) {
71
+ return undefined;
72
+ }
73
+ const parsed = (0, date_fns_1.parse)(str, format, new Date());
74
+ if (!isValidDate(parsed)) {
75
+ return undefined;
76
+ }
77
+ return parsed;
78
+ }
79
+ function isValidDate(d) {
80
+ return d !== undefined && (0, date_fns_1.isDate)(d) && d.toString() !== "Invalid Date";
81
+ }
82
+ exports.isValidDate = isValidDate;
@@ -117,6 +117,6 @@ function TextFieldBase(props) {
117
117
  // Reset focus to input element
118
118
  (_a = fieldRef.current) === null || _a === void 0 ? void 0 : _a.focus();
119
119
  } }, void 0)), !multiline && endAdornment && (0, jsx_runtime_1.jsx)("span", Object.assign({ css: Css_1.Css.df.aic.pl1.fs0.$ }, { children: endAdornment }), void 0)] }), void 0)),
120
- }), errorMsg && !compound && !errorInTooltip && ((0, jsx_runtime_1.jsx)(ErrorMessage_1.ErrorMessage, Object.assign({ id: errorMessageId, errorMsg: errorMsg }, tid.errorMsg), void 0)), helperText && !compound && (0, jsx_runtime_1.jsx)(HelperText_1.HelperText, Object.assign({ helperText: helperText }, tid.helperText), void 0)] }), void 0));
120
+ }), !compound && !inputProps.disabled && !inputProps.readOnly && ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [errorMsg && !errorInTooltip && (0, jsx_runtime_1.jsx)(ErrorMessage_1.ErrorMessage, Object.assign({ id: errorMessageId, errorMsg: errorMsg }, tid.errorMsg), void 0), helperText && (0, jsx_runtime_1.jsx)(HelperText_1.HelperText, Object.assign({ helperText: helperText }, tid.helperText), void 0)] }, void 0))] }), void 0));
121
121
  }
122
122
  exports.TextFieldBase = TextFieldBase;
@@ -1,7 +1,7 @@
1
1
  export * from "./Checkbox";
2
2
  export * from "./CheckboxGroup";
3
3
  export * from "./ChipSelectField";
4
- export * from "./DateField";
4
+ export * from "./DateFields";
5
5
  export * from "./MultiSelectField";
6
6
  export * from "./NumberField";
7
7
  export type { NumberFieldProps } from "./NumberField";
@@ -14,7 +14,7 @@ exports.RadioGroupField = void 0;
14
14
  __exportStar(require("./Checkbox"), exports);
15
15
  __exportStar(require("./CheckboxGroup"), exports);
16
16
  __exportStar(require("./ChipSelectField"), exports);
17
- __exportStar(require("./DateField"), exports);
17
+ __exportStar(require("./DateFields"), exports);
18
18
  __exportStar(require("./MultiSelectField"), exports);
19
19
  __exportStar(require("./NumberField"), exports);
20
20
  var RadioGroupField_1 = require("./RadioGroupField");
package/dist/types.d.ts CHANGED
@@ -1,3 +1,5 @@
1
+ import { DateRange as _DateRange } from "react-day-picker";
2
+ export type { _DateRange as DateRange };
1
3
  export declare type HasIdAndName<V = string> = {
2
4
  id: V;
3
5
  name: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@homebound/beam",
3
- "version": "2.141.2",
3
+ "version": "2.143.0",
4
4
  "author": "Homebound",
5
5
  "license": "MIT",
6
6
  "main": "dist/index.js",
@@ -43,7 +43,7 @@
43
43
  "framer-motion": "^4.1.11",
44
44
  "memoize-one": "^5.2.1",
45
45
  "react-aria": "^3.14.1",
46
- "react-day-picker": "^8.0.6",
46
+ "react-day-picker": "^8.0.7",
47
47
  "react-popper": "^2.2.5",
48
48
  "react-router": "^5.2.0",
49
49
  "react-router-dom": "^5.2.0",