@fibery/ui-kit 1.40.4 → 1.41.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 (141) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/eslint.config.mjs +16 -0
  3. package/package.json +8 -7
  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.tsx +3 -4
  27. package/src/date-picker/single-date-picker.tsx +147 -119
  28. package/src/date-picker/types.ts +4 -3
  29. package/src/day-select/iso-week-day-select.tsx +2 -2
  30. package/src/day-select/week-day-select.tsx +2 -2
  31. package/src/delayed.tsx +0 -1
  32. package/src/design-system/alpha.test.ts +59 -0
  33. package/src/design-system/alpha.ts +41 -0
  34. package/src/design-system/animation.ts +10 -0
  35. package/src/design-system/colors-css.test.ts +39 -0
  36. package/src/design-system/colors-css.ts +25 -0
  37. package/src/design-system/colors-js.test.ts +232 -0
  38. package/src/design-system/colors-js.ts +107 -0
  39. package/src/design-system/colors.test.ts +74 -0
  40. package/src/{design-system.colors.ts → design-system/colors.ts} +133 -134
  41. package/src/design-system/date.ts +3 -0
  42. package/src/design-system/layout.ts +106 -0
  43. package/src/design-system/theme.test.ts +94 -0
  44. package/src/design-system/theme.ts +93 -0
  45. package/src/design-system/typography.ts +179 -0
  46. package/src/design-system/vars.test.ts +1679 -0
  47. package/src/design-system/vars.ts +52 -0
  48. package/src/design-system.test.ts +46 -303
  49. package/src/design-system.ts +25 -545
  50. package/src/dropdown-menu/index.tsx +5 -5
  51. package/src/emoji-picker/icon-emoji-picker.tsx +1 -1
  52. package/src/fibermoji-placeholder.tsx +3 -3
  53. package/src/field-container.tsx +11 -2
  54. package/src/file-item/file-icon.tsx +3 -3
  55. package/src/file-item-2.tsx +4 -10
  56. package/src/file-item.tsx +0 -1
  57. package/src/icons/ast/ChatBubble.ts +8 -0
  58. package/src/icons/ast/ChatFloat.ts +8 -0
  59. package/src/icons/ast/ChatSidebar.ts +8 -0
  60. package/src/icons/ast/FileOther.ts +8 -0
  61. package/src/icons/ast/NoBorder.ts +8 -0
  62. package/src/icons/ast/NoFill.ts +8 -0
  63. package/src/icons/ast/index.tsx +6 -0
  64. package/src/icons/react/ChatBubble.tsx +13 -0
  65. package/src/icons/react/ChatFloat.tsx +13 -0
  66. package/src/icons/react/ChatSidebar.tsx +13 -0
  67. package/src/icons/react/FileOther.tsx +13 -0
  68. package/src/icons/react/NoBorder.tsx +13 -0
  69. package/src/icons/react/NoFill.tsx +13 -0
  70. package/src/icons/react/index.tsx +6 -0
  71. package/src/icons/svg/chat-bubble.svg +4 -0
  72. package/src/icons/svg/chat-float.svg +4 -0
  73. package/src/icons/svg/chat-sidebar.svg +4 -0
  74. package/src/icons/svg/file-other.svg +3 -0
  75. package/src/icons/svg/no-border.svg +17 -0
  76. package/src/icons/svg/no-fill.svg +4 -0
  77. package/src/images-gallery/images-gallery.tsx +8 -6
  78. package/src/images-gallery/slide-buttons.tsx +2 -2
  79. package/src/is-iOS.ts +0 -1
  80. package/src/is-in-popup.ts +2 -1
  81. package/src/lists/actions-menu-row-surface.tsx +4 -4
  82. package/src/loading-sausage.tsx +2 -2
  83. package/src/media-query-utils.ts +1 -2
  84. package/src/mobile-keyboard-aware-popup.tsx +2 -2
  85. package/src/modal-menu/modal-menu-content.tsx +2 -2
  86. package/src/number-input/decimal.js +9 -7
  87. package/src/number-input/{number-inline-input-with-autosize.tsx → number-input-inline-with-autosize.tsx} +20 -41
  88. package/src/number-input/number-input-inline.tsx +118 -0
  89. package/src/number-input/{index.test.js → number-input.test.tsx} +38 -43
  90. package/src/number-input/number-input.tsx +63 -121
  91. package/src/number-input/types.ts +19 -0
  92. package/src/number-input/utils.ts +61 -0
  93. package/src/online-users.tsx +2 -2
  94. package/src/palette-generator.test.ts +24 -281
  95. package/src/palette-generator.ts +39 -45
  96. package/src/palettes/_.ts +72 -0
  97. package/src/palettes/slate-arch.colors-snapshot.test.ts +1689 -0
  98. package/src/palettes/slate-arch.ts +188 -0
  99. package/src/palettes/slate-user.colors-snapshot.test.ts +1689 -0
  100. package/src/palettes/slate-user.ts +187 -0
  101. package/src/palettes/warm-arch.colors-snapshot.test.ts +1689 -0
  102. package/src/palettes/warm-arch.ts +222 -0
  103. package/src/palettes/warm-user.colors-snapshot.test.ts +1689 -0
  104. package/src/palettes/warm-user.ts +222 -0
  105. package/src/popover/get-element-ref.ts +28 -0
  106. package/src/popover/index.tsx +232 -333
  107. package/src/popover/{mobile-popup-context.tsx → mobile-popover-context.tsx} +7 -7
  108. package/src/popover/mobile-popover.tsx +169 -0
  109. package/src/popover/modifiers.tsx +2 -2
  110. package/src/popover/popup-stack-context.tsx +8 -9
  111. package/src/root-theme-provider.test.tsx +114 -19
  112. package/src/scale-generator.ts +31 -22
  113. package/src/select/components/menu-list-virtualized.tsx +5 -3
  114. package/src/select/index.tsx +6 -5
  115. package/src/select/select.tsx +36 -38
  116. package/src/select/util.ts +1 -1
  117. package/src/static-palettes.ts +221 -11
  118. package/src/thematic-controls.tsx +6 -6
  119. package/src/thematic-scales.tsx +15 -15
  120. package/src/thematic-state.ts +57 -20
  121. package/src/thematic.tsx +36 -32
  122. package/src/theme-provider.test.tsx +31 -19
  123. package/src/theme-provider.tsx +41 -38
  124. package/src/theme-settings.ts +66 -11
  125. package/src/theme-styles.ts +53 -8
  126. package/src/toast/toast.tsx +1 -2
  127. package/src/toggle.tsx +2 -2
  128. package/src/tooltip.tsx +4 -3
  129. package/src/type-badge.tsx +4 -11
  130. package/src/unit/styles.ts +0 -23
  131. package/src/use-is-phone.tsx +7 -2
  132. package/src/use-on-screen-keyboard-data.tsx +2 -2
  133. package/src/with-data.tsx +4 -3
  134. package/src/workflow-progress-icon.tsx +2 -2
  135. package/.eslintignore +0 -3
  136. package/.eslintrc +0 -14
  137. package/src/__mocks__/createInlineTheme.js +0 -3
  138. package/src/__snapshots__/design-system.test.ts.snap +0 -7265
  139. package/src/create-inline-theme.ts +0 -67
  140. package/src/number-input/index.js +0 -191
  141. 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
  });
@@ -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";
@@ -27,7 +27,6 @@ export const DateRangePicker = forwardRef<
27
27
  bypassedRef,
28
28
  value,
29
29
  disabled = false,
30
- renderInPortal = true,
31
30
  onChange,
32
31
  showTime = false,
33
32
  dateFormat,
@@ -107,14 +106,14 @@ export const DateRangePicker = forwardRef<
107
106
  popupContainerClassName={css`
108
107
  z-index: 10001;
109
108
  `}
110
- renderInPortal={renderInPortal}
109
+ renderInPortal={true}
111
110
  preventOverflowOptions={{
112
111
  altAxis: true,
113
112
  }}
114
113
  >
115
114
  <DateRangePickerPopupContent
116
115
  ref={ref}
117
- {..._.omit(props, ["onChange", "value"])}
116
+ {...omit(props, ["onChange", "value"])}
118
117
  onChange={onDatesChange}
119
118
  value={dateValue}
120
119
  onKeyDown={onDatePickerKeyDown}
@@ -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,93 +125,147 @@ export const SingleDatePicker: SingleDatePickerWithForwardRefType = forwardRef<
151
125
  allowRelativeDate && (isRelativeValue || value === null) ? "relative" : "exact"
152
126
  );
153
127
 
128
+ return (
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 ? (
143
+ <div
144
+ className={css`
145
+ border-bottom: ${themeVars.separators.opacity5};
146
+ `}
147
+ >
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>
177
+ </div>
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>
196
+ </div>
197
+ );
198
+ });
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
+ bypassedRef,
211
+ value,
212
+ disabled = false,
213
+ placeholder,
214
+ showTime = false,
215
+ dateFormat,
216
+ dateTimeFormat,
217
+ allowRelativeDate = false,
218
+ } = props;
219
+
220
+ const isRelativeValue = allowRelativeDate ? isRelativeDatePlaceholder(value) : false;
221
+
222
+ const dateValueFormatted = isRelativeValue
223
+ ? formatRelativeDate(value as RelativeDateValue)
224
+ : value
225
+ ? formatDateInputValue((value as Moment).toDate(), {
226
+ showTime,
227
+ dateFormat,
228
+ dateTimeFormat,
229
+ })
230
+ : null;
231
+
232
+ const fakeWrapperRef = useRef<HTMLDivElement>(null);
233
+
234
+ const pickerValue = children || (
235
+ <FakeDateInputWrapper disabled={disabled} isPickerOpen={open}>
236
+ {!dateValueFormatted ? <EmptyValue>{placeholder}</EmptyValue> : <>{dateValueFormatted}</>}
237
+ </FakeDateInputWrapper>
238
+ );
239
+
154
240
  if (disabled) {
155
241
  return pickerValue;
156
242
  }
157
243
 
158
244
  return (
159
245
  <div ref={bypassedRef}>
160
- <PopoverOld
161
- title={title}
162
- offset={[0, space.s6]}
163
- trigger={
246
+ <Popover.Root open={open} onOpen={onOpen} onClose={onClose}>
247
+ <Popover.Trigger>
164
248
  <div ref={fakeWrapperRef} onClick={stopPropagation}>
165
249
  {pickerValue}
166
250
  </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};
251
+ </Popover.Trigger>
252
+ <Popover.Portal>
253
+ <Popover.Content
254
+ title={title}
255
+ offset={[0, space.s6]}
256
+ placement="bottom-start"
257
+ supportMobile
258
+ popupContainerClassName={css`
259
+ z-index: 10001;
185
260
  `}
261
+ preventOverflowOptions={{
262
+ altAxis: true,
263
+ }}
186
264
  >
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}
218
- <div
219
- style={allowRelativeDate ? {minWidth: 320} : undefined}
220
- className={css`
221
- width: 100%;
222
- `}
223
- >
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
- )}
239
- </div>
240
- </PopoverOld>
265
+ <SingleDatePickerPopoverContent ref={ref} {...props} />
266
+ </Popover.Content>
267
+ </Popover.Portal>
268
+ </Popover.Root>
241
269
  </div>
242
270
  );
243
271
  });
@@ -27,7 +27,6 @@ export type DatePickerCommonProps = {
27
27
  allowClear?: boolean;
28
28
  bypassedRef?: React.Ref<$TSFixMe>;
29
29
  disabled?: boolean;
30
- renderInPortal?: boolean;
31
30
  onKeyDown?: React.KeyboardEventHandler<$TSFixMe>;
32
31
  placeholder: string;
33
32
  weekStartsOn?: 0 | 1 | 2 | 3 | 4 | 5 | 6 | undefined;
@@ -49,10 +48,12 @@ export type NativeDateRangePickerProps = {
49
48
 
50
49
  export type ControlledDatePickerProps = {open: boolean; onOpen: () => void; onClose: () => void};
51
50
 
52
- export type SingleDatePickerProps<IsRelativeDate extends boolean = false> = DatePickerCommonProps &
53
- ControlledDatePickerProps &
51
+ export type SingleDatePickerPopoverContentProps<IsRelativeDate extends boolean = false> = DatePickerCommonProps &
54
52
  MomentSingleDateProps<IsRelativeDate> & {
55
53
  allowRelativeDate?: IsRelativeDate;
56
54
  } & (IsRelativeDate extends true
57
55
  ? {relativeDateToExactDate?: (value: RelativeDateValue) => string} // Required if IsRelativeDate is true
58
56
  : {relativeDateToExactDate?: never}); // Undefined if IsRelativeDate is false;
57
+
58
+ export type SingleDatePickerProps<IsRelativeDate extends boolean = false> = ControlledDatePickerProps &
59
+ 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
 
@@ -0,0 +1,59 @@
1
+ import {getOpacities, transparent} from "./alpha";
2
+
3
+ describe("getOpacities", () => {
4
+ test("color maps to alphas", () => {
5
+ expect(getOpacities("#f00")).toMatchInlineSnapshot(`
6
+ {
7
+ "opacity0": "rgba(255,0,0,0)",
8
+ "opacity10": "rgba(255,0,0,0.1)",
9
+ "opacity100": "rgb(255,0,0)",
10
+ "opacity15": "rgba(255,0,0,0.15)",
11
+ "opacity20": "rgba(255,0,0,0.2)",
12
+ "opacity25": "rgba(255,0,0,0.25)",
13
+ "opacity30": "rgba(255,0,0,0.3)",
14
+ "opacity35": "rgba(255,0,0,0.35)",
15
+ "opacity40": "rgba(255,0,0,0.4)",
16
+ "opacity45": "rgba(255,0,0,0.45)",
17
+ "opacity5": "rgba(255,0,0,0.05)",
18
+ "opacity50": "rgba(255,0,0,0.5)",
19
+ "opacity55": "rgba(255,0,0,0.55)",
20
+ "opacity60": "rgba(255,0,0,0.6)",
21
+ "opacity65": "rgba(255,0,0,0.65)",
22
+ "opacity70": "rgba(255,0,0,0.7)",
23
+ "opacity75": "rgba(255,0,0,0.75)",
24
+ "opacity80": "rgba(255,0,0,0.8)",
25
+ "opacity85": "rgba(255,0,0,0.85)",
26
+ "opacity90": "rgba(255,0,0,0.9)",
27
+ "opacity95": "rgba(255,0,0,0.95)",
28
+ }
29
+ `);
30
+ });
31
+
32
+ test("transparent is identity map", () => {
33
+ expect(getOpacities(transparent)).toMatchInlineSnapshot(`
34
+ {
35
+ "opacity0": "rgba(255, 255, 255, 0)",
36
+ "opacity10": "rgba(255, 255, 255, 0)",
37
+ "opacity100": "rgba(255, 255, 255, 0)",
38
+ "opacity15": "rgba(255, 255, 255, 0)",
39
+ "opacity20": "rgba(255, 255, 255, 0)",
40
+ "opacity25": "rgba(255, 255, 255, 0)",
41
+ "opacity30": "rgba(255, 255, 255, 0)",
42
+ "opacity35": "rgba(255, 255, 255, 0)",
43
+ "opacity40": "rgba(255, 255, 255, 0)",
44
+ "opacity45": "rgba(255, 255, 255, 0)",
45
+ "opacity5": "rgba(255, 255, 255, 0)",
46
+ "opacity50": "rgba(255, 255, 255, 0)",
47
+ "opacity55": "rgba(255, 255, 255, 0)",
48
+ "opacity60": "rgba(255, 255, 255, 0)",
49
+ "opacity65": "rgba(255, 255, 255, 0)",
50
+ "opacity70": "rgba(255, 255, 255, 0)",
51
+ "opacity75": "rgba(255, 255, 255, 0)",
52
+ "opacity80": "rgba(255, 255, 255, 0)",
53
+ "opacity85": "rgba(255, 255, 255, 0)",
54
+ "opacity90": "rgba(255, 255, 255, 0)",
55
+ "opacity95": "rgba(255, 255, 255, 0)",
56
+ }
57
+ `);
58
+ });
59
+ });
@@ -0,0 +1,41 @@
1
+ import {produceColor, setAlpha} from "../color-utils";
2
+ import mapValues from "lodash/mapValues";
3
+ import memoize from "lodash/memoize";
4
+ export const transparent = "rgba(255, 255, 255, 0)";
5
+
6
+ export const opacity = {
7
+ opacity100: 1,
8
+ opacity95: 0.95,
9
+ opacity90: 0.9,
10
+ opacity85: 0.85,
11
+ opacity80: 0.8,
12
+ opacity75: 0.75,
13
+ opacity70: 0.7,
14
+ opacity65: 0.65,
15
+ opacity60: 0.6,
16
+ opacity55: 0.55,
17
+ opacity50: 0.5,
18
+ opacity45: 0.45,
19
+ opacity40: 0.4,
20
+ opacity35: 0.35,
21
+ opacity30: 0.3,
22
+ opacity25: 0.25,
23
+ opacity20: 0.2,
24
+ opacity15: 0.15,
25
+ opacity10: 0.1,
26
+ opacity5: 0.05,
27
+ opacity0: 0,
28
+ } as const;
29
+
30
+ /**
31
+ * @deprecated I would think thrice on semantic value of this wrapper before one more usage
32
+ * maybe you will come up with something better
33
+ */
34
+ export const getOpacities = memoize((color: string) =>
35
+ mapValues(opacity, (opacityValue) => {
36
+ if (color === transparent) {
37
+ return transparent;
38
+ }
39
+ return produceColor(color, (c) => setAlpha(c, opacityValue));
40
+ })
41
+ );
@@ -0,0 +1,10 @@
1
+ export const duration = 120;
2
+
3
+ export const easing = "ease-in-out";
4
+
5
+ export const transition = `${duration}ms ${easing}`;
6
+
7
+ export const tooltipDelay = {
8
+ enter: 500,
9
+ leave: 0,
10
+ } as const;