@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.
- package/CHANGELOG.md +18 -0
- package/eslint.config.mjs +16 -0
- package/package.json +10 -9
- package/src/a11y-color.test.ts +5 -24
- package/src/actions-menu/actions-menu-item.tsx +6 -9
- package/src/actions-menu/context-actions-menu.tsx +8 -3
- package/src/ai/model.tsx +0 -1
- package/src/ai/temperature.tsx +0 -1
- package/src/animated-height-container.tsx +3 -3
- package/src/antd/index.tsx +3 -0
- package/src/antd/input.tsx +0 -1
- package/src/antd/styles.ts +9 -9
- package/src/app-icon-with-fallback.tsx +5 -5
- package/src/app-icon-wrapper.tsx +2 -3
- package/src/app-icon.tsx +3 -3
- package/src/avatar.tsx +3 -3
- package/src/button/base-button.tsx +0 -1
- package/src/button/make-button-colors.ts +2 -2
- package/src/checkbox.tsx +1 -1
- package/src/collapsible-section.tsx +11 -1
- package/src/color-utils.test.ts +15 -25
- package/src/color-utils.ts +43 -8
- package/src/command-menu/index.tsx +1 -0
- package/src/context-menu/index.tsx +5 -5
- package/src/date-picker/contexts.ts +2 -2
- package/src/date-picker/date-range-picker-popup-content.tsx +1 -2
- package/src/date-picker/date-range-picker.tsx +29 -31
- package/src/date-picker/single-date-picker-popup-content.tsx +1 -2
- package/src/date-picker/single-date-picker.tsx +149 -124
- package/src/date-picker/types.ts +4 -4
- package/src/day-select/iso-week-day-select.tsx +2 -2
- package/src/day-select/week-day-select.tsx +2 -2
- package/src/delayed.tsx +0 -1
- package/src/design-system/alpha.test.ts +59 -0
- package/src/design-system/alpha.ts +41 -0
- package/src/design-system/animation.ts +10 -0
- package/src/design-system/colors-css.test.ts +39 -0
- package/src/design-system/colors-css.ts +25 -0
- package/src/design-system/colors-js.test.ts +232 -0
- package/src/design-system/colors-js.ts +107 -0
- package/src/design-system/colors.test.ts +74 -0
- package/src/{design-system.colors.ts → design-system/colors.ts} +133 -134
- package/src/design-system/date.ts +3 -0
- package/src/design-system/layout.ts +106 -0
- package/src/design-system/theme.test.ts +94 -0
- package/src/design-system/theme.ts +93 -0
- package/src/design-system/typography.ts +179 -0
- package/src/design-system/vars.test.ts +1679 -0
- package/src/design-system/vars.ts +52 -0
- package/src/design-system.test.ts +46 -303
- package/src/design-system.ts +25 -545
- package/src/dropdown-menu/index.tsx +5 -5
- package/src/emoji-picker/icon-emoji-picker.tsx +1 -1
- package/src/fibermoji-placeholder.tsx +3 -3
- package/src/field-container.tsx +11 -2
- package/src/file-item/file-icon.tsx +3 -3
- package/src/file-item-2.tsx +4 -10
- package/src/file-item.tsx +0 -1
- package/src/icons/ast/ChatBubble.ts +8 -0
- package/src/icons/ast/ChatFloat.ts +8 -0
- package/src/icons/ast/ChatSidebar.ts +8 -0
- package/src/icons/ast/FileOther.ts +8 -0
- package/src/icons/ast/NoBorder.ts +8 -0
- package/src/icons/ast/NoFill.ts +8 -0
- package/src/icons/ast/index.tsx +6 -0
- package/src/icons/react/ChatBubble.tsx +13 -0
- package/src/icons/react/ChatFloat.tsx +13 -0
- package/src/icons/react/ChatSidebar.tsx +13 -0
- package/src/icons/react/FileOther.tsx +13 -0
- package/src/icons/react/NoBorder.tsx +13 -0
- package/src/icons/react/NoFill.tsx +13 -0
- package/src/icons/react/index.tsx +6 -0
- package/src/icons/svg/chat-bubble.svg +4 -0
- package/src/icons/svg/chat-float.svg +4 -0
- package/src/icons/svg/chat-sidebar.svg +4 -0
- package/src/icons/svg/file-other.svg +3 -0
- package/src/icons/svg/no-border.svg +17 -0
- package/src/icons/svg/no-fill.svg +4 -0
- package/src/images-gallery/images-gallery.tsx +8 -6
- package/src/images-gallery/slide-buttons.tsx +2 -2
- package/src/is-iOS.ts +0 -1
- package/src/is-in-popup.ts +2 -1
- package/src/lists/actions-menu-row-surface.tsx +4 -4
- package/src/loading-sausage.tsx +2 -2
- package/src/media-query-utils.ts +1 -2
- package/src/mobile-keyboard-aware-popup.tsx +2 -2
- package/src/modal-menu/modal-menu-content.tsx +2 -2
- package/src/number-input/decimal.js +9 -7
- package/src/number-input/{number-inline-input-with-autosize.tsx → number-input-inline-with-autosize.tsx} +20 -41
- package/src/number-input/number-input-inline.tsx +118 -0
- package/src/number-input/{index.test.js → number-input.test.tsx} +38 -43
- package/src/number-input/number-input.tsx +63 -121
- package/src/number-input/types.ts +19 -0
- package/src/number-input/utils.ts +61 -0
- package/src/online-users.tsx +2 -2
- package/src/palette-generator.test.ts +24 -281
- package/src/palette-generator.ts +39 -45
- package/src/palettes/_.ts +72 -0
- package/src/palettes/slate-arch.colors-snapshot.test.ts +1689 -0
- package/src/palettes/slate-arch.ts +188 -0
- package/src/palettes/slate-user.colors-snapshot.test.ts +1689 -0
- package/src/palettes/slate-user.ts +187 -0
- package/src/palettes/warm-arch.colors-snapshot.test.ts +1689 -0
- package/src/palettes/warm-arch.ts +222 -0
- package/src/palettes/warm-user.colors-snapshot.test.ts +1689 -0
- package/src/palettes/warm-user.ts +222 -0
- package/src/popover/get-element-ref.ts +28 -0
- package/src/popover/index.tsx +232 -333
- package/src/popover/{mobile-popup-context.tsx → mobile-popover-context.tsx} +7 -7
- package/src/popover/mobile-popover.tsx +169 -0
- package/src/popover/modifiers.tsx +2 -2
- package/src/popover/popup-stack-context.tsx +8 -9
- package/src/root-theme-provider.test.tsx +114 -19
- package/src/scale-generator.ts +31 -22
- package/src/select/components/menu-list-virtualized.tsx +5 -3
- package/src/select/index.tsx +6 -5
- package/src/select/select.tsx +36 -38
- package/src/select/util.ts +1 -1
- package/src/static-palettes.ts +221 -11
- package/src/thematic-controls.tsx +6 -6
- package/src/thematic-scales.tsx +15 -15
- package/src/thematic-state.ts +57 -20
- package/src/thematic.tsx +36 -32
- package/src/theme-provider.test.tsx +31 -19
- package/src/theme-provider.tsx +41 -38
- package/src/theme-settings.ts +66 -11
- package/src/theme-styles.ts +53 -8
- package/src/toast/toast.tsx +1 -2
- package/src/toggle.tsx +2 -2
- package/src/tooltip.tsx +4 -3
- package/src/type-badge.tsx +4 -11
- package/src/unit/styles.ts +0 -23
- package/src/use-is-phone.tsx +7 -2
- package/src/use-on-screen-keyboard-data.tsx +2 -2
- package/src/with-data.tsx +4 -3
- package/src/workflow-progress-icon.tsx +2 -2
- package/.eslintignore +0 -3
- package/.eslintrc +0 -14
- package/src/__mocks__/createInlineTheme.js +0 -3
- package/src/__snapshots__/design-system.test.ts.snap +0 -7265
- package/src/create-inline-theme.ts +0 -67
- package/src/number-input/index.js +0 -191
- package/src/palette.ts +0 -253
package/src/color-utils.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
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
|
|
28
|
+
type Color = PlainColorObject;
|
|
29
29
|
|
|
30
|
-
|
|
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
|
|
41
|
+
return to(color, space);
|
|
33
42
|
} catch {
|
|
34
|
-
return
|
|
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(
|
|
55
|
-
|
|
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 ===
|
|
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};
|
|
@@ -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 {
|
|
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
|
-
<
|
|
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
|
-
</
|
|
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
|
-
<
|
|
138
|
+
<RadixPortalThemeProvider>
|
|
139
139
|
<ContextMenuPrimitive.SubContent ref={ref} className={cx(dropdownMenuContentStyles, className)} {...rest} />
|
|
140
|
-
</
|
|
140
|
+
</RadixPortalThemeProvider>
|
|
141
141
|
</ContextMenuPrimitive.Portal>
|
|
142
142
|
);
|
|
143
143
|
}
|
|
@@ -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}
|
|
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 {
|
|
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
|
|
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
|
|
94
|
-
<
|
|
95
|
-
|
|
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
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
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}
|
|
49
|
+
<div className={datePickerStylesOverrideClassName} onKeyDown={onKeyDown}>
|
|
51
50
|
<SingleDateInput
|
|
52
51
|
ref={ref}
|
|
53
52
|
value={dateValue}
|
|
@@ -1,17 +1,22 @@
|
|
|
1
|
-
import {
|
|
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
|
|
16
|
+
import omit from "lodash/omit";
|
|
12
17
|
import {EmptyValue} from "../empty-value";
|
|
13
18
|
import {formatDateInputValue} from "./utils";
|
|
14
|
-
import {
|
|
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
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
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
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
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
|
-
|
|
145
|
+
border-bottom: ${themeVars.separators.opacity5};
|
|
222
146
|
`}
|
|
223
147
|
>
|
|
224
|
-
|
|
225
|
-
<
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
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
|
-
|
|
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);
|
package/src/date-picker/types.ts
CHANGED
|
@@ -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
|
|
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
|
|
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 =
|
|
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
|
|
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 =
|
|
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);
|