@fibery/ui-kit 1.40.4 → 1.42.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 (143) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/eslint.config.mjs +16 -0
  3. package/package.json +10 -9
  4. package/src/a11y-color.test.ts +5 -24
  5. package/src/actions-menu/actions-menu-item.tsx +6 -9
  6. package/src/actions-menu/context-actions-menu.tsx +8 -3
  7. package/src/ai/model.tsx +0 -1
  8. package/src/ai/temperature.tsx +0 -1
  9. package/src/animated-height-container.tsx +3 -3
  10. package/src/antd/index.tsx +3 -0
  11. package/src/antd/input.tsx +0 -1
  12. package/src/antd/styles.ts +9 -9
  13. package/src/app-icon-with-fallback.tsx +5 -5
  14. package/src/app-icon-wrapper.tsx +2 -3
  15. package/src/app-icon.tsx +3 -3
  16. package/src/avatar.tsx +3 -3
  17. package/src/button/base-button.tsx +0 -1
  18. package/src/button/make-button-colors.ts +2 -2
  19. package/src/checkbox.tsx +1 -1
  20. package/src/collapsible-section.tsx +11 -1
  21. package/src/color-utils.test.ts +15 -25
  22. package/src/color-utils.ts +43 -8
  23. package/src/command-menu/index.tsx +1 -0
  24. package/src/context-menu/index.tsx +5 -5
  25. package/src/date-picker/contexts.ts +2 -2
  26. package/src/date-picker/date-range-picker-popup-content.tsx +1 -2
  27. package/src/date-picker/date-range-picker.tsx +29 -31
  28. package/src/date-picker/single-date-picker-popup-content.tsx +1 -2
  29. package/src/date-picker/single-date-picker.tsx +149 -124
  30. package/src/date-picker/types.ts +4 -4
  31. package/src/day-select/iso-week-day-select.tsx +2 -2
  32. package/src/day-select/week-day-select.tsx +2 -2
  33. package/src/delayed.tsx +0 -1
  34. package/src/design-system/alpha.test.ts +59 -0
  35. package/src/design-system/alpha.ts +41 -0
  36. package/src/design-system/animation.ts +10 -0
  37. package/src/design-system/colors-css.test.ts +39 -0
  38. package/src/design-system/colors-css.ts +25 -0
  39. package/src/design-system/colors-js.test.ts +232 -0
  40. package/src/design-system/colors-js.ts +107 -0
  41. package/src/design-system/colors.test.ts +74 -0
  42. package/src/{design-system.colors.ts → design-system/colors.ts} +133 -134
  43. package/src/design-system/date.ts +3 -0
  44. package/src/design-system/layout.ts +106 -0
  45. package/src/design-system/theme.test.ts +94 -0
  46. package/src/design-system/theme.ts +93 -0
  47. package/src/design-system/typography.ts +179 -0
  48. package/src/design-system/vars.test.ts +1679 -0
  49. package/src/design-system/vars.ts +52 -0
  50. package/src/design-system.test.ts +46 -303
  51. package/src/design-system.ts +25 -545
  52. package/src/dropdown-menu/index.tsx +5 -5
  53. package/src/emoji-picker/icon-emoji-picker.tsx +1 -1
  54. package/src/fibermoji-placeholder.tsx +3 -3
  55. package/src/field-container.tsx +11 -2
  56. package/src/file-item/file-icon.tsx +3 -3
  57. package/src/file-item-2.tsx +4 -10
  58. package/src/file-item.tsx +0 -1
  59. package/src/icons/ast/ChatBubble.ts +8 -0
  60. package/src/icons/ast/ChatFloat.ts +8 -0
  61. package/src/icons/ast/ChatSidebar.ts +8 -0
  62. package/src/icons/ast/FileOther.ts +8 -0
  63. package/src/icons/ast/NoBorder.ts +8 -0
  64. package/src/icons/ast/NoFill.ts +8 -0
  65. package/src/icons/ast/index.tsx +6 -0
  66. package/src/icons/react/ChatBubble.tsx +13 -0
  67. package/src/icons/react/ChatFloat.tsx +13 -0
  68. package/src/icons/react/ChatSidebar.tsx +13 -0
  69. package/src/icons/react/FileOther.tsx +13 -0
  70. package/src/icons/react/NoBorder.tsx +13 -0
  71. package/src/icons/react/NoFill.tsx +13 -0
  72. package/src/icons/react/index.tsx +6 -0
  73. package/src/icons/svg/chat-bubble.svg +4 -0
  74. package/src/icons/svg/chat-float.svg +4 -0
  75. package/src/icons/svg/chat-sidebar.svg +4 -0
  76. package/src/icons/svg/file-other.svg +3 -0
  77. package/src/icons/svg/no-border.svg +17 -0
  78. package/src/icons/svg/no-fill.svg +4 -0
  79. package/src/images-gallery/images-gallery.tsx +8 -6
  80. package/src/images-gallery/slide-buttons.tsx +2 -2
  81. package/src/is-iOS.ts +0 -1
  82. package/src/is-in-popup.ts +2 -1
  83. package/src/lists/actions-menu-row-surface.tsx +4 -4
  84. package/src/loading-sausage.tsx +2 -2
  85. package/src/media-query-utils.ts +1 -2
  86. package/src/mobile-keyboard-aware-popup.tsx +2 -2
  87. package/src/modal-menu/modal-menu-content.tsx +2 -2
  88. package/src/number-input/decimal.js +9 -7
  89. package/src/number-input/{number-inline-input-with-autosize.tsx → number-input-inline-with-autosize.tsx} +20 -41
  90. package/src/number-input/number-input-inline.tsx +118 -0
  91. package/src/number-input/{index.test.js → number-input.test.tsx} +38 -43
  92. package/src/number-input/number-input.tsx +63 -121
  93. package/src/number-input/types.ts +19 -0
  94. package/src/number-input/utils.ts +61 -0
  95. package/src/online-users.tsx +2 -2
  96. package/src/palette-generator.test.ts +24 -281
  97. package/src/palette-generator.ts +39 -45
  98. package/src/palettes/_.ts +72 -0
  99. package/src/palettes/slate-arch.colors-snapshot.test.ts +1689 -0
  100. package/src/palettes/slate-arch.ts +188 -0
  101. package/src/palettes/slate-user.colors-snapshot.test.ts +1689 -0
  102. package/src/palettes/slate-user.ts +187 -0
  103. package/src/palettes/warm-arch.colors-snapshot.test.ts +1689 -0
  104. package/src/palettes/warm-arch.ts +222 -0
  105. package/src/palettes/warm-user.colors-snapshot.test.ts +1689 -0
  106. package/src/palettes/warm-user.ts +222 -0
  107. package/src/popover/get-element-ref.ts +28 -0
  108. package/src/popover/index.tsx +232 -333
  109. package/src/popover/{mobile-popup-context.tsx → mobile-popover-context.tsx} +7 -7
  110. package/src/popover/mobile-popover.tsx +169 -0
  111. package/src/popover/modifiers.tsx +2 -2
  112. package/src/popover/popup-stack-context.tsx +8 -9
  113. package/src/root-theme-provider.test.tsx +114 -19
  114. package/src/scale-generator.ts +31 -22
  115. package/src/select/components/menu-list-virtualized.tsx +5 -3
  116. package/src/select/index.tsx +6 -5
  117. package/src/select/select.tsx +36 -38
  118. package/src/select/util.ts +1 -1
  119. package/src/static-palettes.ts +221 -11
  120. package/src/thematic-controls.tsx +6 -6
  121. package/src/thematic-scales.tsx +15 -15
  122. package/src/thematic-state.ts +57 -20
  123. package/src/thematic.tsx +36 -32
  124. package/src/theme-provider.test.tsx +31 -19
  125. package/src/theme-provider.tsx +41 -38
  126. package/src/theme-settings.ts +66 -11
  127. package/src/theme-styles.ts +53 -8
  128. package/src/toast/toast.tsx +1 -2
  129. package/src/toggle.tsx +2 -2
  130. package/src/tooltip.tsx +4 -3
  131. package/src/type-badge.tsx +4 -11
  132. package/src/unit/styles.ts +0 -23
  133. package/src/use-is-phone.tsx +7 -2
  134. package/src/use-on-screen-keyboard-data.tsx +2 -2
  135. package/src/with-data.tsx +4 -3
  136. package/src/workflow-progress-icon.tsx +2 -2
  137. package/.eslintignore +0 -3
  138. package/.eslintrc +0 -14
  139. package/src/__mocks__/createInlineTheme.js +0 -3
  140. package/src/__snapshots__/design-system.test.ts.snap +0 -7265
  141. package/src/create-inline-theme.ts +0 -67
  142. package/src/number-input/index.js +0 -191
  143. package/src/palette.ts +0 -253
@@ -1,4 +1,4 @@
1
- import type {ColorConstructor, Coords, PlainColorObject} from "colorjs.io/fn";
1
+ import type {Coords, PlainColorObject} from "colorjs.io/fn";
2
2
  import {
3
3
  ColorSpace,
4
4
  contrastWCAG21,
@@ -25,13 +25,22 @@ ColorSpace.register(LCH);
25
25
  ColorSpace.register(OKLCH);
26
26
  ColorSpace.register(P3);
27
27
 
28
- type Color = PlainColorObject | ColorConstructor;
28
+ type Color = PlainColorObject;
29
29
 
30
- function colorSafe(color: string, fallback = "#4978D4"): Color {
30
+ // FIXME consolidate as common util
31
+ const isFlagPresent = (flag: string) => globalThis.window && new RegExp(`[?&]${flag}\\b`).test(window.location.search);
32
+
33
+ const defaultColorSpace = isFlagPresent("oklch") ? OKLCH : sRGB;
34
+
35
+ function colorSafe(
36
+ color: string,
37
+ fallback = "hsl(220, 62%, 56%)" /* formerly brandColor.blue, currently accent[9] */,
38
+ space: ColorSpace = defaultColorSpace
39
+ ): Color {
31
40
  try {
32
- return parse(color);
41
+ return to(color, space);
33
42
  } catch {
34
- return parse(fallback);
43
+ return to(fallback, space);
35
44
  }
36
45
  }
37
46
 
@@ -51,8 +60,12 @@ function serializesRGB(color: Color): string {
51
60
 
52
61
  type ColorTransform = (color: PlainColorObject) => PlainColorObject | void;
53
62
 
54
- export function produceColor(color: string, transforms: ColorTransform | ColorTransform[], space?: ColorSpace): string {
55
- let c = to(colorSafe(color), sRGB);
63
+ export function produceColor(
64
+ color: string,
65
+ transforms: ColorTransform | ColorTransform[],
66
+ space: ColorSpace = defaultColorSpace
67
+ ): string {
68
+ let c = colorSafe(color);
56
69
  for (const transform of Array.isArray(transforms) ? transforms : [transforms]) {
57
70
  const result = transform(c);
58
71
  if (result !== undefined) {
@@ -61,7 +74,7 @@ export function produceColor(color: string, transforms: ColorTransform | ColorTr
61
74
  }
62
75
  // TODO make sRGB default space and apply colorjs.io outputs CSS Level 4 format (rgb(100% 0% 0%))
63
76
  // instead of compatible format (rgb(255,0,0))
64
- if (space === undefined) {
77
+ if (space === sRGB) {
65
78
  return serializesRGB(c);
66
79
  }
67
80
  return serialize(to(c, space));
@@ -161,6 +174,10 @@ export function toOKLCH(color: string) {
161
174
  return produceColor(color, [], OKLCH);
162
175
  }
163
176
 
177
+ export function toRGB(color: string) {
178
+ return produceColor(color, [], sRGB);
179
+ }
180
+
164
181
  export function getHsl(color: string): [number, number, number] {
165
182
  const c = to(colorSafe(color), HSL);
166
183
  return [c.coords[0] || 0, (c.coords[1] || 0) / 100, (c.coords[2] || 0) / 100];
@@ -177,4 +194,22 @@ export function toCss(color: string): string {
177
194
  return produceColor(color, []);
178
195
  }
179
196
 
197
+ /**
198
+ * @deprecated use toCss instead
199
+ */
200
+ export function toHex(color: string): string {
201
+ const c = toGamut(to(colorSafe(color), sRGB), {space: sRGB});
202
+ const r = Math.round(clamp01(c.coords[0]) * 255);
203
+ const g = Math.round(clamp01(c.coords[1]) * 255);
204
+ const b = Math.round(clamp01(c.coords[2]) * 255);
205
+ const a = c.alpha ?? 1;
206
+ const hex = "#" + [r, g, b].map((v) => v.toString(16).padStart(2, "0")).join("");
207
+ return a < 1
208
+ ? hex +
209
+ Math.round(a * 255)
210
+ .toString(16)
211
+ .padStart(2, "0")
212
+ : hex;
213
+ }
214
+
180
215
  export {ColorSpace, mix, OKLCH, parse, set, sRGB, to, HSL, Lab, LCH};
@@ -124,6 +124,7 @@ export const commandItemCss = css`
124
124
  min-height: ${layoutVars.menuItemHeight};
125
125
  margin: 0 ${space.s4}px;
126
126
  border-radius: ${border.radius6}px;
127
+ color: ${themeVars.textColor};
127
128
 
128
129
  &[data-selected="true"] {
129
130
  margin: 0 4px;
@@ -4,7 +4,7 @@ import * as ContextMenuPrimitive from "@radix-ui/react-context-menu";
4
4
  import {forwardRef} from "react";
5
5
  import {border, layout, space, textStyles, themeVars} from "../design-system";
6
6
  import {mobileRootSelector} from "../mobile-styles";
7
- import {ThemeProvider} from "../theme-provider";
7
+ import {RadixPortalThemeProvider} from "../theme-provider";
8
8
 
9
9
  export const Root = (contextMenuProps: ContextMenuPrimitive.ContextMenuProps) => (
10
10
  <ContextMenuPrimitive.Root dir="ltr" {...contextMenuProps} />
@@ -95,14 +95,14 @@ export type ContentProps = ContextMenuPrimitive.ContextMenuContentProps;
95
95
  export const Content = forwardRef<HTMLDivElement, ContentProps>(function ContextMenuContent({className, ...rest}, ref) {
96
96
  return (
97
97
  <ContextMenuPrimitive.Portal>
98
- <ThemeProvider portal>
98
+ <RadixPortalThemeProvider>
99
99
  <ContextMenuPrimitive.Content
100
100
  ref={ref}
101
101
  className={cx(dropdownMenuContentStyles, className)}
102
102
  collisionPadding={space.s12 + space.s8}
103
103
  {...rest}
104
104
  />
105
- </ThemeProvider>
105
+ </RadixPortalThemeProvider>
106
106
  </ContextMenuPrimitive.Portal>
107
107
  );
108
108
  });
@@ -135,9 +135,9 @@ export const SubContent = forwardRef<HTMLDivElement, ContextMenuPrimitive.Contex
135
135
  function DropdownMenuSubContent({className, ...rest}, ref) {
136
136
  return (
137
137
  <ContextMenuPrimitive.Portal>
138
- <ThemeProvider portal>
138
+ <RadixPortalThemeProvider>
139
139
  <ContextMenuPrimitive.SubContent ref={ref} className={cx(dropdownMenuContentStyles, className)} {...rest} />
140
- </ThemeProvider>
140
+ </RadixPortalThemeProvider>
141
141
  </ContextMenuPrimitive.Portal>
142
142
  );
143
143
  }
@@ -1,7 +1,7 @@
1
1
  import {createContext} from "react";
2
- import _ from "lodash";
2
+ import noop from "lodash/noop";
3
3
 
4
4
  export const StartEndFocusContext = createContext({
5
5
  focusOnStart: true,
6
- setFocusOnStart: _.noop,
6
+ setFocusOnStart: noop,
7
7
  });
@@ -41,7 +41,6 @@ export const DateRangePickerPopupContent = forwardRef<
41
41
  timeFormat,
42
42
  dateTimeFormat,
43
43
  header,
44
- bypassedRef,
45
44
  onKeyDown,
46
45
  weekStartsOn,
47
46
  weekends,
@@ -148,7 +147,7 @@ export const DateRangePickerPopupContent = forwardRef<
148
147
  const weekendsForMonth = useMemo(() => getWeekendsForMonth(month, weekends), [month, weekends]);
149
148
 
150
149
  return (
151
- <div className={datePickerStylesOverrideClassName} ref={bypassedRef} onKeyDown={onKeyDown}>
150
+ <div className={datePickerStylesOverrideClassName} onKeyDown={onKeyDown}>
152
151
  {header}
153
152
  {showInput && (
154
153
  <DateRangeInput
@@ -1,5 +1,5 @@
1
1
  import {ControlledDatePickerProps, DatePickerCommonProps, MomentDateRangeProps} from "./types";
2
- import {PopoverOld} from "../popover";
2
+ import {Popover} from "../popover";
3
3
  import {space} from "../design-system";
4
4
  import {withPopupControl} from "./with-popup-control";
5
5
  import {DateRangePickerPopupContent} from "./date-range-picker-popup-content";
@@ -7,7 +7,7 @@ import {css} from "@linaria/core";
7
7
  import "react-day-picker/dist/style.css";
8
8
  import {stopPropagation} from "@fibery/react/src/stop-propagation";
9
9
  import {forwardRef, useCallback, useRef} from "react";
10
- import _ from "lodash";
10
+ import omit from "lodash/omit";
11
11
  import moment from "moment";
12
12
  import {FakeDateInputWrapper} from "./fake-date-input";
13
13
  import {formatDateRangeInputValue} from "./utils";
@@ -24,10 +24,8 @@ export const DateRangePicker = forwardRef<
24
24
  onOpen,
25
25
  onClose,
26
26
  children,
27
- bypassedRef,
28
27
  value,
29
28
  disabled = false,
30
- renderInPortal = true,
31
29
  onChange,
32
30
  showTime = false,
33
31
  dateFormat,
@@ -90,36 +88,36 @@ export const DateRangePicker = forwardRef<
90
88
  }
91
89
 
92
90
  return (
93
- <div ref={bypassedRef}>
94
- <PopoverOld
95
- title={title}
96
- offset={[0, space.s6]}
97
- trigger={
91
+ <div>
92
+ <Popover.Root open={open} onOpen={onOpen} onClose={onClose}>
93
+ <Popover.Trigger>
98
94
  <div ref={fakeWrapperRef} onClick={stopPropagation}>
99
95
  {pickerValue}
100
96
  </div>
101
- }
102
- supportMobile
103
- placement="bottom-start"
104
- open={open}
105
- onOpen={onOpen}
106
- onClose={onClose}
107
- popupContainerClassName={css`
108
- z-index: 10001;
109
- `}
110
- renderInPortal={renderInPortal}
111
- preventOverflowOptions={{
112
- altAxis: true,
113
- }}
114
- >
115
- <DateRangePickerPopupContent
116
- ref={ref}
117
- {..._.omit(props, ["onChange", "value"])}
118
- onChange={onDatesChange}
119
- value={dateValue}
120
- onKeyDown={onDatePickerKeyDown}
121
- />
122
- </PopoverOld>
97
+ </Popover.Trigger>
98
+ <Popover.Portal>
99
+ <Popover.Content
100
+ title={title}
101
+ offset={[0, space.s6]}
102
+ supportMobile
103
+ placement="bottom-start"
104
+ popupContainerClassName={css`
105
+ z-index: 10001;
106
+ `}
107
+ preventOverflowOptions={{
108
+ altAxis: true,
109
+ }}
110
+ >
111
+ <DateRangePickerPopupContent
112
+ ref={ref}
113
+ {...omit(props, ["onChange", "value"])}
114
+ onChange={onDatesChange}
115
+ value={dateValue}
116
+ onKeyDown={onDatePickerKeyDown}
117
+ />
118
+ </Popover.Content>
119
+ </Popover.Portal>
120
+ </Popover.Root>
123
121
  </div>
124
122
  );
125
123
  });
@@ -28,7 +28,6 @@ export const SingleDatePickerPopupContent = forwardRef<
28
28
  timeFormat,
29
29
  dateTimeFormat,
30
30
  onKeyDown,
31
- bypassedRef,
32
31
  weekStartsOn,
33
32
  weekends,
34
33
  } = props;
@@ -47,7 +46,7 @@ export const SingleDatePickerPopupContent = forwardRef<
47
46
  const weekendsForMonth = useMemo(() => getWeekendsForMonth(month, weekends), [month, weekends]);
48
47
 
49
48
  return (
50
- <div className={datePickerStylesOverrideClassName} ref={bypassedRef} onKeyDown={onKeyDown}>
49
+ <div className={datePickerStylesOverrideClassName} onKeyDown={onKeyDown}>
51
50
  <SingleDateInput
52
51
  ref={ref}
53
52
  value={dateValue}
@@ -1,17 +1,22 @@
1
- import {ControlledDatePickerProps, RelativeDateValue, SingleDatePickerProps} from "./types";
1
+ import {
2
+ ControlledDatePickerProps,
3
+ RelativeDateValue,
4
+ SingleDatePickerPopoverContentProps,
5
+ SingleDatePickerProps,
6
+ } from "./types";
2
7
  import {FakeDateInputWrapper} from "./fake-date-input";
3
8
  import {space, themeVars} from "../design-system";
4
9
  import {withPopupControl} from "./with-popup-control";
5
- import {css} from "@linaria/core";
10
+ import {css, cx} from "@linaria/core";
6
11
  import "react-day-picker/dist/style.css";
7
12
  import {SingleDatePickerPopupContent} from "./single-date-picker-popup-content";
8
13
  import {stopPropagation} from "@fibery/react/src/stop-propagation";
9
14
  import {forwardRef, useCallback, useRef, useState} from "react";
10
15
  import moment, {Moment} from "moment";
11
- import _ from "lodash";
16
+ import omit from "lodash/omit";
12
17
  import {EmptyValue} from "../empty-value";
13
18
  import {formatDateInputValue} from "./utils";
14
- import {PopoverOld} from "../popover";
19
+ import {Popover} from "../popover";
15
20
  import {focusable} from "tabbable";
16
21
  import {TabNavLink, TabNavList, TabNavRoot} from "../tab-nav/tab-nav";
17
22
  import {RelativeDatePicker} from "./relative-date-picker";
@@ -69,43 +74,18 @@ interface ControlledSingleDatePickerWithForwardRefType extends React.FC<Uncontro
69
74
  >;
70
75
  }
71
76
 
72
- export const SingleDatePicker: SingleDatePickerWithForwardRefType = forwardRef<
73
- {
74
- setValue: (value: string) => void;
75
- },
76
- SingleDatePickerProps<boolean>
77
+ type DatePickerRef = {
78
+ setValue: (value: string) => void;
79
+ };
80
+
81
+ export const SingleDatePickerPopoverContent = forwardRef<
82
+ DatePickerRef,
83
+ {className?: string} & SingleDatePickerPopoverContentProps<boolean>
77
84
  >((props, ref) => {
78
- const {
79
- title,
80
- open,
81
- onOpen,
82
- onClose,
83
- children,
84
- bypassedRef,
85
- value,
86
- disabled = false,
87
- placeholder,
88
- renderInPortal = true,
89
- onChange,
90
- showTime = false,
91
- dateFormat,
92
- dateTimeFormat,
93
- onKeyDown,
94
- allowRelativeDate = false,
95
- relativeDateToExactDate,
96
- } = props;
85
+ const {className, value, onChange, onKeyDown, allowRelativeDate = false, relativeDateToExactDate} = props;
97
86
 
98
87
  const isRelativeValue = allowRelativeDate ? isRelativeDatePlaceholder(value) : false;
99
88
 
100
- const dateValueFormatted = isRelativeValue
101
- ? formatRelativeDate(value as RelativeDateValue)
102
- : value
103
- ? formatDateInputValue((value as Moment).toDate(), {
104
- showTime,
105
- dateFormat,
106
- dateTimeFormat,
107
- })
108
- : null;
109
89
  const onDateChange = useCallback(
110
90
  (value: Date | null) => {
111
91
  // @ts-expect-error fix types
@@ -124,12 +104,6 @@ export const SingleDatePicker: SingleDatePickerWithForwardRefType = forwardRef<
124
104
 
125
105
  const fakeWrapperRef = useRef<HTMLDivElement>(null);
126
106
 
127
- const pickerValue = children || (
128
- <FakeDateInputWrapper disabled={disabled} isPickerOpen={open}>
129
- {!dateValueFormatted ? <EmptyValue>{placeholder}</EmptyValue> : <>{dateValueFormatted}</>}
130
- </FakeDateInputWrapper>
131
- );
132
-
133
107
  const onDatePickerKeyDown = useCallback(
134
108
  (e: React.KeyboardEvent<HTMLInputElement>) => {
135
109
  if (e.key === "Tab" || e.key === "Enter") {
@@ -151,96 +125,147 @@ export const SingleDatePicker: SingleDatePickerWithForwardRefType = forwardRef<
151
125
  allowRelativeDate && (isRelativeValue || value === null) ? "relative" : "exact"
152
126
  );
153
127
 
154
- if (disabled) {
155
- return pickerValue;
156
- }
157
-
158
128
  return (
159
- <div ref={bypassedRef}>
160
- <PopoverOld
161
- title={title}
162
- offset={[0, space.s6]}
163
- trigger={
164
- <div ref={fakeWrapperRef} onClick={stopPropagation}>
165
- {pickerValue}
166
- </div>
167
- }
168
- placement="bottom-start"
169
- open={open}
170
- onOpen={onOpen}
171
- onClose={onClose}
172
- supportMobile
173
- popupContainerClassName={css`
174
- z-index: 10001;
175
- `}
176
- renderInPortal={renderInPortal}
177
- preventOverflowOptions={{
178
- altAxis: true,
179
- }}
180
- >
181
- {allowRelativeDate ? (
182
- <div
183
- className={css`
184
- border-bottom: ${themeVars.separators.opacity5};
185
- `}
186
- >
187
- <TabNavRoot>
188
- <TabNavList
189
- className={css`
190
- padding-left: ${space.s12}px;
191
- padding-right: ${space.s12}px;
192
- padding-top: ${space.s6}px;
193
- display: flex;
194
- width: 100%;
195
- justify-content: space-evenly;
196
- `}
197
- >
198
- <TabNavLink
199
- className={tabNavLinkClassName}
200
- itemClassName={tabItemClassName}
201
- active={activeButton === "relative"}
202
- onSelect={() => setActiveButton("relative")}
203
- >
204
- Relative
205
- </TabNavLink>
206
- <TabNavLink
207
- className={tabNavLinkClassName}
208
- itemClassName={tabItemClassName}
209
- active={activeButton === "exact"}
210
- onSelect={() => setActiveButton("exact")}
211
- >
212
- Exact
213
- </TabNavLink>
214
- </TabNavList>
215
- </TabNavRoot>
216
- </div>
217
- ) : null}
129
+ <div
130
+ className={cx(
131
+ css`
132
+ display: flex;
133
+ flex-direction: column;
134
+ `,
135
+ allowRelativeDate &&
136
+ css`
137
+ min-width: 320px;
138
+ `,
139
+ className
140
+ )}
141
+ >
142
+ {allowRelativeDate ? (
218
143
  <div
219
- style={allowRelativeDate ? {minWidth: 320} : undefined}
220
144
  className={css`
221
- width: 100%;
145
+ border-bottom: ${themeVars.separators.opacity5};
222
146
  `}
223
147
  >
224
- {!allowRelativeDate || activeButton === "exact" ? (
225
- <SingleDatePickerPopupContent
226
- ref={ref}
227
- {..._.omit(props, ["onChange", "value"])}
228
- onChange={onDateChange}
229
- value={!isRelativeValue && value ? (value as Moment).toDate() : null}
230
- onKeyDown={onDatePickerKeyDown}
231
- />
232
- ) : (
233
- <RelativeDatePicker
234
- value={isRelativeValue ? (value as RelativeDateValue) : null}
235
- onChange={onRelativeDateChange}
236
- relativeDateToExactDate={relativeDateToExactDate}
237
- />
238
- )}
148
+ <TabNavRoot>
149
+ <TabNavList
150
+ className={css`
151
+ padding-left: ${space.s12}px;
152
+ padding-right: ${space.s12}px;
153
+ padding-top: ${space.s6}px;
154
+ display: flex;
155
+ width: 100%;
156
+ justify-content: space-evenly;
157
+ `}
158
+ >
159
+ <TabNavLink
160
+ className={tabNavLinkClassName}
161
+ itemClassName={tabItemClassName}
162
+ active={activeButton === "relative"}
163
+ onSelect={() => setActiveButton("relative")}
164
+ >
165
+ Relative
166
+ </TabNavLink>
167
+ <TabNavLink
168
+ className={tabNavLinkClassName}
169
+ itemClassName={tabItemClassName}
170
+ active={activeButton === "exact"}
171
+ onSelect={() => setActiveButton("exact")}
172
+ >
173
+ Exact
174
+ </TabNavLink>
175
+ </TabNavList>
176
+ </TabNavRoot>
239
177
  </div>
240
- </PopoverOld>
178
+ ) : null}
179
+ <div>
180
+ {!allowRelativeDate || activeButton === "exact" ? (
181
+ <SingleDatePickerPopupContent
182
+ ref={ref}
183
+ {...omit(props, ["onChange", "value"])}
184
+ onChange={onDateChange}
185
+ value={!isRelativeValue && value ? (value as Moment).toDate() : null}
186
+ onKeyDown={onDatePickerKeyDown}
187
+ />
188
+ ) : (
189
+ <RelativeDatePicker
190
+ value={isRelativeValue ? (value as RelativeDateValue) : null}
191
+ onChange={onRelativeDateChange}
192
+ relativeDateToExactDate={relativeDateToExactDate}
193
+ />
194
+ )}
195
+ </div>
241
196
  </div>
242
197
  );
243
198
  });
244
199
 
200
+ export const SingleDatePicker: SingleDatePickerWithForwardRefType = forwardRef<
201
+ DatePickerRef,
202
+ SingleDatePickerProps<boolean>
203
+ >((props, ref) => {
204
+ const {
205
+ title,
206
+ open,
207
+ onOpen,
208
+ onClose,
209
+ children,
210
+ value,
211
+ disabled = false,
212
+ placeholder,
213
+ showTime = false,
214
+ dateFormat,
215
+ dateTimeFormat,
216
+ allowRelativeDate = false,
217
+ } = props;
218
+
219
+ const isRelativeValue = allowRelativeDate ? isRelativeDatePlaceholder(value) : false;
220
+
221
+ const dateValueFormatted = isRelativeValue
222
+ ? formatRelativeDate(value as RelativeDateValue)
223
+ : value
224
+ ? formatDateInputValue((value as Moment).toDate(), {
225
+ showTime,
226
+ dateFormat,
227
+ dateTimeFormat,
228
+ })
229
+ : null;
230
+
231
+ const fakeWrapperRef = useRef<HTMLDivElement>(null);
232
+
233
+ const pickerValue = children || (
234
+ <FakeDateInputWrapper disabled={disabled} isPickerOpen={open}>
235
+ {!dateValueFormatted ? <EmptyValue>{placeholder}</EmptyValue> : <>{dateValueFormatted}</>}
236
+ </FakeDateInputWrapper>
237
+ );
238
+
239
+ if (disabled) {
240
+ return pickerValue;
241
+ }
242
+
243
+ return (
244
+ <Popover.Root open={open} onOpen={onOpen} onClose={onClose}>
245
+ <Popover.Trigger>
246
+ <div ref={fakeWrapperRef} onClick={stopPropagation}>
247
+ {pickerValue}
248
+ </div>
249
+ </Popover.Trigger>
250
+ <Popover.Portal>
251
+ <Popover.Content
252
+ title={title}
253
+ offset={[0, space.s6]}
254
+ placement="bottom-start"
255
+ supportMobile
256
+ popupContainerClassName={css`
257
+ z-index: 10001;
258
+ `}
259
+ preventOverflowOptions={{
260
+ altAxis: true,
261
+ }}
262
+ >
263
+ <SingleDatePickerPopoverContent ref={ref} {...props} />
264
+ </Popover.Content>
265
+ </Popover.Portal>
266
+ </Popover.Root>
267
+ );
268
+ });
269
+
245
270
  export const ControlledSingleDatePicker: ControlledSingleDatePickerWithForwardRefType =
246
271
  withPopupControl(SingleDatePicker);
@@ -25,9 +25,7 @@ export type DatePickerCommonProps = {
25
25
  header?: ReactNode;
26
26
  children?: JSX.Element;
27
27
  allowClear?: boolean;
28
- bypassedRef?: React.Ref<$TSFixMe>;
29
28
  disabled?: boolean;
30
- renderInPortal?: boolean;
31
29
  onKeyDown?: React.KeyboardEventHandler<$TSFixMe>;
32
30
  placeholder: string;
33
31
  weekStartsOn?: 0 | 1 | 2 | 3 | 4 | 5 | 6 | undefined;
@@ -49,10 +47,12 @@ export type NativeDateRangePickerProps = {
49
47
 
50
48
  export type ControlledDatePickerProps = {open: boolean; onOpen: () => void; onClose: () => void};
51
49
 
52
- export type SingleDatePickerProps<IsRelativeDate extends boolean = false> = DatePickerCommonProps &
53
- ControlledDatePickerProps &
50
+ export type SingleDatePickerPopoverContentProps<IsRelativeDate extends boolean = false> = DatePickerCommonProps &
54
51
  MomentSingleDateProps<IsRelativeDate> & {
55
52
  allowRelativeDate?: IsRelativeDate;
56
53
  } & (IsRelativeDate extends true
57
54
  ? {relativeDateToExactDate?: (value: RelativeDateValue) => string} // Required if IsRelativeDate is true
58
55
  : {relativeDateToExactDate?: never}); // Undefined if IsRelativeDate is false;
56
+
57
+ export type SingleDatePickerProps<IsRelativeDate extends boolean = false> = ControlledDatePickerProps &
58
+ SingleDatePickerPopoverContentProps<IsRelativeDate>;
@@ -1,8 +1,8 @@
1
- import _ from "lodash";
1
+ import range from "lodash/range";
2
2
  import {DaySelect, Props} from "./day-select";
3
3
  import moment from "moment";
4
4
 
5
- const isoWeekDays = _.range(1, 8).map((day) => {
5
+ const isoWeekDays = range(1, 8).map((day) => {
6
6
  return {
7
7
  key: String(day),
8
8
  title: moment().isoWeekday(day).format("dd").charAt(0),
@@ -1,4 +1,4 @@
1
- import _ from "lodash";
1
+ import memoize from "lodash/memoize";
2
2
  import {DaySelect, Props} from "./day-select";
3
3
 
4
4
  export enum Days {
@@ -21,7 +21,7 @@ const WeekDayMap = {
21
21
  SU: Days.SU,
22
22
  };
23
23
 
24
- export const getDays = _.memoize((firstDay) => {
24
+ export const getDays = memoize((firstDay) => {
25
25
  const entries = Object.entries(WeekDayMap);
26
26
  const firstDayIndex = entries.findIndex((entry) => entry[1] === firstDay);
27
27
  const partA = entries.slice(firstDayIndex);
package/src/delayed.tsx CHANGED
@@ -7,7 +7,6 @@ export const Delayed: React.FC<React.PropsWithChildren<{delayMs: number}>> = ({c
7
7
 
8
8
  useEffect(() => {
9
9
  if (!delayMs) {
10
- // eslint-disable-next-line @typescript-eslint/no-empty-function
11
10
  return () => {};
12
11
  }
13
12