@gooddata/sdk-ui-kit 11.52.0-alpha.5 → 11.52.0-alpha.7
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/esm/@ui/UiAddGranteeDialog/UiAddGranteeDialogCard.d.ts +8 -1
- package/esm/@ui/UiAddGranteeDialog/UiAddGranteeDialogCard.d.ts.map +1 -1
- package/esm/@ui/UiAddGranteeDialog/UiAddGranteeDialogCard.js +3 -3
- package/esm/@ui/UiAddGranteeDialog/useGranteeSelection.d.ts +2 -0
- package/esm/@ui/UiAddGranteeDialog/useGranteeSelection.d.ts.map +1 -1
- package/esm/@ui/UiAddGranteeDialog/useGranteeSelection.js +4 -1
- package/esm/@ui/UiCombobox/UiComboboxInput.d.ts +2 -0
- package/esm/@ui/UiCombobox/UiComboboxInput.d.ts.map +1 -1
- package/esm/@ui/UiCombobox/UiComboboxInput.js +2 -2
- package/esm/@ui/UiGranteeAsyncPicker/UiGranteeAsyncPicker.d.ts +18 -1
- package/esm/@ui/UiGranteeAsyncPicker/UiGranteeAsyncPicker.d.ts.map +1 -1
- package/esm/@ui/UiGranteeAsyncPicker/UiGranteeAsyncPicker.js +7 -2
- package/esm/@ui/UiGranteeRowControls/UiGranteeRowControls.d.ts +14 -5
- package/esm/@ui/UiGranteeRowControls/UiGranteeRowControls.d.ts.map +1 -1
- package/esm/@ui/UiGranteeRowControls/UiGranteeRowControls.js +8 -7
- package/esm/@ui/UiMenu/components/defaults/DefaultUiMenuInteractiveItem.d.ts.map +1 -1
- package/esm/@ui/UiMenu/components/defaults/DefaultUiMenuInteractiveItem.js +25 -22
- package/esm/@ui/UiMenu/types.d.ts +1 -0
- package/esm/@ui/UiMenu/types.d.ts.map +1 -1
- package/esm/@ui/UiPermissionMenu/UiPermissionMenu.d.ts +9 -1
- package/esm/@ui/UiPermissionMenu/UiPermissionMenu.d.ts.map +1 -1
- package/esm/@ui/UiPermissionMenu/UiPermissionMenu.js +8 -4
- package/esm/@ui/UiTextInput/UiTextInput.d.ts +3 -1
- package/esm/@ui/UiTextInput/UiTextInput.d.ts.map +1 -1
- package/esm/@ui/UiTextInput/UiTextInput.js +2 -2
- package/esm/ChartSorting/ChartSorting.d.ts +2 -14
- package/esm/ChartSorting/ChartSorting.d.ts.map +1 -1
- package/esm/ChartSorting/ChartSorting.js +4 -7
- package/esm/Datepicker/Datepicker.d.ts +5 -56
- package/esm/Datepicker/Datepicker.d.ts.map +1 -1
- package/esm/Datepicker/Datepicker.js +145 -183
- package/esm/Form/InputWithNumberFormat.d.ts +0 -1
- package/esm/Form/InputWithNumberFormat.d.ts.map +1 -1
- package/esm/Form/InputWithNumberFormat.js +12 -18
- package/esm/index.d.ts +2 -2
- package/esm/index.d.ts.map +1 -1
- package/esm/index.js +1 -1
- package/esm/locales.d.ts +3 -0
- package/esm/locales.d.ts.map +1 -1
- package/esm/locales.js +1 -0
- package/esm/sdk-ui-kit.d.ts +57 -28
- package/package.json +11 -11
- package/src/@ui/UiMenu/UiMenu.scss +1 -1
- package/src/@ui/UiTextInput/UiTextInput.scss +7 -0
- package/styles/css/main.css +4 -1
- package/styles/css/main.css.map +1 -1
|
@@ -2,12 +2,13 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
2
2
|
// (C) 2022-2026 GoodData Corporation
|
|
3
3
|
import { useCallback, useMemo, useState } from "react";
|
|
4
4
|
import { isEqual } from "lodash-es";
|
|
5
|
-
import { FormattedMessage,
|
|
5
|
+
import { FormattedMessage, useIntl } from "react-intl";
|
|
6
6
|
import { IntlWrapper } from "@gooddata/sdk-ui";
|
|
7
7
|
import { Button } from "../Button/Button.js";
|
|
8
8
|
import { ChartSortingDropdown } from "./ChartSortingDropdown.js";
|
|
9
9
|
import { ChartSortingDropdownBody } from "./ChartSortingDropdownBody.js";
|
|
10
|
-
function ChartSorting({ currentSort, availableSorts,
|
|
10
|
+
function ChartSorting({ currentSort, availableSorts, bucketItems, buttonNode, onCancel, onApply, }) {
|
|
11
|
+
const intl = useIntl();
|
|
11
12
|
const [currentSelectedSort, setCurrentSort] = useState(currentSort);
|
|
12
13
|
const handleApply = useCallback(() => {
|
|
13
14
|
onApply(currentSelectedSort);
|
|
@@ -22,13 +23,9 @@ function ChartSorting({ currentSort, availableSorts, intl, bucketItems, buttonNo
|
|
|
22
23
|
] })
|
|
23
24
|
] }));
|
|
24
25
|
}
|
|
25
|
-
/**
|
|
26
|
-
* @internal
|
|
27
|
-
*/
|
|
28
|
-
export const ChartSortingWithIntl = injectIntl(ChartSorting);
|
|
29
26
|
/**
|
|
30
27
|
* @internal
|
|
31
28
|
*/
|
|
32
29
|
export function ChartSortingDialog(props) {
|
|
33
|
-
return (_jsx(IntlWrapper, { locale: props.locale, children: _jsx(
|
|
30
|
+
return (_jsx(IntlWrapper, { locale: props.locale, children: _jsx(ChartSorting, { ...props }) }));
|
|
34
31
|
}
|
|
@@ -1,12 +1,11 @@
|
|
|
1
|
-
import { PureComponent, type KeyboardEvent as ReactKeyboardEvent
|
|
2
|
-
import { type WrappedComponentProps } from "react-intl";
|
|
1
|
+
import { PureComponent, type KeyboardEvent as ReactKeyboardEvent } from "react";
|
|
3
2
|
import { type WeekStart } from "@gooddata/sdk-model";
|
|
4
3
|
import { type IAccessibilityConfigBase } from "../typings/accessibility.js";
|
|
5
4
|
import { type IAlignPoint } from "../typings/positioning.js";
|
|
6
5
|
/**
|
|
7
6
|
* @internal
|
|
8
7
|
*/
|
|
9
|
-
export interface
|
|
8
|
+
export interface IDatePickerProps {
|
|
10
9
|
accessibilityConfig?: IAccessibilityConfigBase;
|
|
11
10
|
date?: Date;
|
|
12
11
|
className?: string;
|
|
@@ -24,63 +23,13 @@ export interface IDatePickerOwnProps {
|
|
|
24
23
|
weekStart?: WeekStart;
|
|
25
24
|
onDateInputKeyDown?: (e: ReactKeyboardEvent<HTMLInputElement>) => void;
|
|
26
25
|
}
|
|
27
|
-
export type DatePickerProps = IDatePickerOwnProps & WrappedComponentProps;
|
|
28
|
-
interface IDatePickerState {
|
|
29
|
-
align: string;
|
|
30
|
-
selectedDate: Date | undefined;
|
|
31
|
-
monthDate: Date | undefined;
|
|
32
|
-
isOpen: boolean;
|
|
33
|
-
inputValue: string;
|
|
34
|
-
}
|
|
35
26
|
export declare function parseDate(str: string, dateFormat: string): Date | undefined;
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
private datePickerContainerRef;
|
|
39
|
-
private inputRef;
|
|
40
|
-
private datePickerId;
|
|
41
|
-
static defaultProps: {
|
|
42
|
-
className: string;
|
|
43
|
-
date: Date;
|
|
44
|
-
placeholder: string;
|
|
45
|
-
onChange: () => void;
|
|
46
|
-
onBlur: () => void;
|
|
47
|
-
resetOnInvalidValue: boolean;
|
|
48
|
-
size: string;
|
|
49
|
-
tabIndex: number;
|
|
50
|
-
alignPoints: {
|
|
51
|
-
align: string;
|
|
52
|
-
}[];
|
|
53
|
-
onAlign: () => void;
|
|
54
|
-
dateFormat: string;
|
|
55
|
-
weekStart: "Sunday";
|
|
56
|
-
};
|
|
57
|
-
constructor(props: DatePickerProps);
|
|
58
|
-
componentDidMount(): void;
|
|
59
|
-
UNSAFE_componentWillReceiveProps(nextProps: DatePickerProps): void;
|
|
60
|
-
componentWillUnmount(): void;
|
|
61
|
-
private handleClickOutside;
|
|
62
|
-
componentDidUpdate(_prevProps: DatePickerProps, prevState: IDatePickerState): void;
|
|
63
|
-
private setComponentRef;
|
|
64
|
-
private getInputClasses;
|
|
65
|
-
private getComponentClasses;
|
|
66
|
-
private getOverlayWrapperClasses;
|
|
67
|
-
resizeHandler: import("lodash-es").DebouncedFunc<() => void>;
|
|
68
|
-
private updateDate;
|
|
69
|
-
private handleInputBlur;
|
|
70
|
-
private handleInputChanged;
|
|
71
|
-
private handleDayChanged;
|
|
72
|
-
private handleMonthChanged;
|
|
73
|
-
private handleCustomDayClick;
|
|
74
|
-
private normalizeDate;
|
|
75
|
-
private alignDatePicker;
|
|
76
|
-
private onKeyDown;
|
|
77
|
-
private handleWrapperClick;
|
|
78
|
-
render(): ReactNode;
|
|
79
|
-
}
|
|
27
|
+
declare function WrappedDatePickerCore({ accessibilityConfig, date: dateProp, className, placeholder, onChange, onBlur, onValidateInput, resetOnInvalidValue, size, tabIndex, alignPoints: alignPointsProp, onAlign, dateFormat: dateFormatProp, weekStart: weekStartProp, onDateInputKeyDown }: IDatePickerProps): import("react/jsx-runtime").JSX.Element;
|
|
28
|
+
export declare const WrappedDatePicker: import("react").MemoExoticComponent<typeof WrappedDatePickerCore>;
|
|
80
29
|
/**
|
|
81
30
|
* @internal
|
|
82
31
|
*/
|
|
83
|
-
export declare class Datepicker extends PureComponent<
|
|
32
|
+
export declare class Datepicker extends PureComponent<IDatePickerProps> {
|
|
84
33
|
render(): import("react/jsx-runtime").JSX.Element;
|
|
85
34
|
}
|
|
86
35
|
export {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Datepicker.d.ts","sourceRoot":"","sources":["../../src/Datepicker/Datepicker.tsx"],"names":[],"mappings":"AAEA,OAAO,EAGH,aAAa,EACb,KAAK,aAAa,IAAI,kBAAkB,
|
|
1
|
+
{"version":3,"file":"Datepicker.d.ts","sourceRoot":"","sources":["../../src/Datepicker/Datepicker.tsx"],"names":[],"mappings":"AAEA,OAAO,EAGH,aAAa,EACb,KAAK,aAAa,IAAI,kBAAkB,EAS3C,MAAM,OAAO,CAAC;AAkCf,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAIrD,OAAO,EAAE,KAAK,wBAAwB,EAAE,MAAM,6BAA6B,CAAC;AAC5E,OAAO,EAAE,KAAK,WAAW,EAAE,MAAM,2BAA2B,CAAC;AAO7D;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC7B,mBAAmB,CAAC,EAAE,wBAAwB,CAAC;IAC/C,IAAI,CAAC,EAAE,IAAI,CAAC;IACZ,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,CAAC,YAAY,EAAE,IAAI,KAAK,IAAI,CAAC;IACxC,MAAM,CAAC,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC,eAAe,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAC1C,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,WAAW,EAAE,CAAC;IAC5B,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB,kBAAkB,CAAC,EAAE,CAAC,CAAC,EAAE,kBAAkB,CAAC,gBAAgB,CAAC,KAAK,IAAI,CAAC;CAC1E;AAuCD,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAuB3E;AA2BD,iBAAS,qBAAqB,CAAC,EAC3B,mBAAmB,EACnB,IAAI,EAAE,QAAQ,EACd,SAAc,EACd,WAAgB,EAChB,QAAQ,EACR,MAAM,EACN,eAAe,EACf,mBAA2B,EAC3B,IAAS,EACT,QAAY,EACZ,WAAW,EAAE,eAAe,EAC5B,OAAO,EACP,UAAU,EAAE,cAAc,EAC1B,SAAS,EAAE,aAAa,EACxB,kBAAkB,EACrB,EAAE,gBAAgB,2CAuQlB;AAED,eAAO,MAAM,iBAAiB,mEAA8B,CAAC;AAG7D;;GAEG;AACH,qBAAa,UAAW,SAAQ,aAAa,CAAC,gBAAgB,CAAC;IAC3C,MAAM,4CAMrB;CACJ"}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
// (C) 2020-2026 GoodData Corporation
|
|
3
|
-
import { PureComponent,
|
|
3
|
+
import { PureComponent, memo, useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState, } from "react";
|
|
4
4
|
import classNames from "classnames";
|
|
5
5
|
import { format, isSameDay, isValid, parse } from "date-fns";
|
|
6
6
|
import { de, enAU, enGB, enUS, es, fi, fr, frCA, id, it, ja, ko, nl, pl, pt, ptBR, ru, sl, th, tr, uk, vi, zhCN, } from "date-fns/locale";
|
|
7
7
|
import { debounce } from "lodash-es";
|
|
8
8
|
import { DayPicker } from "react-day-picker";
|
|
9
|
-
import {
|
|
9
|
+
import { useIntl } from "react-intl";
|
|
10
10
|
import { v4 as uuid } from "uuid";
|
|
11
11
|
import { IntlWrapper } from "@gooddata/sdk-ui";
|
|
12
12
|
import { DEFAULT_DATE_FORMAT } from "../constants/platform.js";
|
|
@@ -81,191 +81,148 @@ function convertWeekStart(weekStart) {
|
|
|
81
81
|
throw new Error(`Unknown week start ${weekStart}`);
|
|
82
82
|
}
|
|
83
83
|
}
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
this.handleClickOutside = this.handleClickOutside.bind(this);
|
|
121
|
-
this.onKeyDown = this.onKeyDown.bind(this);
|
|
122
|
-
this.handleCustomDayClick = this.handleCustomDayClick.bind(this);
|
|
123
|
-
}
|
|
124
|
-
componentDidMount() {
|
|
125
|
-
const { date, dateFormat } = this.props;
|
|
126
|
-
this.setState({ selectedDate: this.updateDate(date || new Date()) });
|
|
127
|
-
this.setState({ inputValue: formatDate(date || new Date(), dateFormat ?? DEFAULT_DATE_FORMAT) });
|
|
128
|
-
window.addEventListener("resize", this.resizeHandler);
|
|
129
|
-
document.addEventListener("mousedown", this.handleClickOutside);
|
|
130
|
-
}
|
|
131
|
-
UNSAFE_componentWillReceiveProps(nextProps) {
|
|
132
|
-
const { props } = this;
|
|
133
|
-
const propsDate = props.date?.getTime() ?? 0;
|
|
134
|
-
const nextPropsDate = nextProps.date?.getTime() ?? 0;
|
|
135
|
-
if (propsDate !== nextPropsDate) {
|
|
136
|
-
const selectedDate = this.updateDate(nextProps.date || new Date());
|
|
137
|
-
this.setState({ selectedDate });
|
|
138
|
-
this.setState({ monthDate: selectedDate });
|
|
139
|
-
this.setState({ inputValue: formatDate(selectedDate, props.dateFormat ?? DEFAULT_DATE_FORMAT) });
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
componentWillUnmount() {
|
|
143
|
-
window.removeEventListener("resize", this.resizeHandler);
|
|
144
|
-
document.removeEventListener("mousedown", this.handleClickOutside);
|
|
84
|
+
function normalizeDate(date) {
|
|
85
|
+
return new Date(date.getFullYear(), date.getMonth(), date.getDate());
|
|
86
|
+
}
|
|
87
|
+
const DEFAULT_ALIGN_POINTS = [
|
|
88
|
+
{ align: "bl tl" },
|
|
89
|
+
{ align: "br tr" },
|
|
90
|
+
{ align: "tl bl" },
|
|
91
|
+
{ align: "tr br" },
|
|
92
|
+
];
|
|
93
|
+
// evaluated once per module load, mirroring the original static defaultProps
|
|
94
|
+
const DEFAULT_DATE = new Date();
|
|
95
|
+
function WrappedDatePickerCore({ accessibilityConfig, date: dateProp, className = "", placeholder = "", onChange, onBlur, onValidateInput, resetOnInvalidValue = false, size = "", tabIndex = 0, alignPoints: alignPointsProp, onAlign, dateFormat: dateFormatProp, weekStart: weekStartProp, onDateInputKeyDown, }) {
|
|
96
|
+
const intl = useIntl();
|
|
97
|
+
// these props are nullable at runtime (untyped callers do pass null explicitly), so plain default
|
|
98
|
+
// values are not enough - the class component guarded every usage with `||`, `??` or optional calls
|
|
99
|
+
const date = dateProp || DEFAULT_DATE;
|
|
100
|
+
const alignPoints = alignPointsProp ?? DEFAULT_ALIGN_POINTS;
|
|
101
|
+
const dateFormat = dateFormatProp ?? DEFAULT_DATE_FORMAT;
|
|
102
|
+
const weekStart = weekStartProp ?? "Sunday";
|
|
103
|
+
const rootRef = useRef(null);
|
|
104
|
+
const datePickerContainerRef = useRef(null);
|
|
105
|
+
const inputRef = useRef(null);
|
|
106
|
+
const datePickerId = useMemo(() => uuid(), []);
|
|
107
|
+
const [align, setAlign] = useState(alignPoints[0]?.align ?? "bl tl");
|
|
108
|
+
const [selectedDate, setSelectedDate] = useState(() => normalizeDate(date));
|
|
109
|
+
const [monthDate, setMonthDate] = useState(date);
|
|
110
|
+
const [inputValue, setInputValue] = useState(() => formatDate(date, dateFormat));
|
|
111
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
112
|
+
// resync the derived state whenever the date coming from the props changes
|
|
113
|
+
const [prevDateTime, setPrevDateTime] = useState(date.getTime());
|
|
114
|
+
if (date.getTime() !== prevDateTime) {
|
|
115
|
+
const newlySelectedDate = normalizeDate(date);
|
|
116
|
+
setPrevDateTime(date.getTime());
|
|
117
|
+
setSelectedDate(newlySelectedDate);
|
|
118
|
+
setMonthDate(newlySelectedDate);
|
|
119
|
+
setInputValue(formatDate(newlySelectedDate, dateFormat));
|
|
145
120
|
}
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
!this.inputRef.current.contains(event.target)) {
|
|
151
|
-
this.setState({ isOpen: false });
|
|
121
|
+
const alignDatePicker = useCallback(() => {
|
|
122
|
+
const container = datePickerContainerRef.current?.parentElement;
|
|
123
|
+
if (!alignPoints || !container || !rootRef.current) {
|
|
124
|
+
return;
|
|
152
125
|
}
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
126
|
+
const optimalAlignment = getOptimalAlignment({
|
|
127
|
+
targetRegion: elementRegion(rootRef.current),
|
|
128
|
+
selfRegion: elementRegion(container),
|
|
129
|
+
alignPoints,
|
|
130
|
+
});
|
|
131
|
+
const { align: optimalAlign } = optimalAlignment.alignment;
|
|
132
|
+
setAlign(optimalAlign);
|
|
133
|
+
onAlign?.(optimalAlign);
|
|
134
|
+
}, [alignPoints, onAlign]);
|
|
135
|
+
// keeps the debounced resize handler and the "just opened" effect stable while still
|
|
136
|
+
// calling the up-to-date alignment logic, the same way the class instance method did
|
|
137
|
+
const alignDatePickerRef = useRef(alignDatePicker);
|
|
138
|
+
// must run before the "just opened" layout effect below, hence useLayoutEffect
|
|
139
|
+
useLayoutEffect(() => {
|
|
140
|
+
alignDatePickerRef.current = alignDatePicker;
|
|
141
|
+
}, [alignDatePicker]);
|
|
142
|
+
const resizeHandler = useMemo(() => debounce(() => alignDatePickerRef.current(), 100), []);
|
|
143
|
+
useEffect(() => {
|
|
144
|
+
window.addEventListener("resize", resizeHandler);
|
|
145
|
+
return () => {
|
|
146
|
+
resizeHandler.cancel();
|
|
147
|
+
window.removeEventListener("resize", resizeHandler);
|
|
148
|
+
};
|
|
149
|
+
}, [resizeHandler]);
|
|
150
|
+
useEffect(() => {
|
|
151
|
+
const handleClickOutside = (event) => {
|
|
152
|
+
if (datePickerContainerRef.current &&
|
|
153
|
+
!datePickerContainerRef.current.contains(event.target) &&
|
|
154
|
+
inputRef.current &&
|
|
155
|
+
!inputRef.current.contains(event.target)) {
|
|
156
|
+
setIsOpen(false);
|
|
157
|
+
}
|
|
158
|
+
};
|
|
159
|
+
document.addEventListener("mousedown", handleClickOutside);
|
|
160
|
+
return () => {
|
|
161
|
+
document.removeEventListener("mousedown", handleClickOutside);
|
|
162
|
+
};
|
|
163
|
+
}, []);
|
|
164
|
+
useLayoutEffect(() => {
|
|
165
|
+
if (isOpen) {
|
|
166
|
+
alignDatePickerRef.current();
|
|
157
167
|
}
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
return classNames("input-text", "small-12", this.props.size, `gd-datepicker-input-${this.datePickerId}`);
|
|
164
|
-
}
|
|
165
|
-
getComponentClasses() {
|
|
166
|
-
return classNames("gd-datepicker", this.props.className, this.props.size, "gd-datepicker-input", this.state.isOpen ? "gd-datepicker-focused" : "");
|
|
167
|
-
}
|
|
168
|
-
getOverlayWrapperClasses() {
|
|
169
|
-
const [inputAnchorPoint, pickerAnchorPoint] = this.state.align.split(" ");
|
|
170
|
-
return classNames("gd-datepicker-picker", "gd-datepicker-OverlayWrapper", `gd-datepicker-OverlayWrapper-${inputAnchorPoint}-xx`, `gd-datepicker-OverlayWrapper-xx-${pickerAnchorPoint}`);
|
|
171
|
-
}
|
|
172
|
-
resizeHandler = debounce(() => this.alignDatePicker(), 100);
|
|
173
|
-
updateDate(date) {
|
|
174
|
-
return this.normalizeDate(date);
|
|
175
|
-
}
|
|
176
|
-
handleInputBlur(e) {
|
|
177
|
-
this.props.onBlur?.(e.target.value);
|
|
178
|
-
}
|
|
179
|
-
handleInputChanged(e) {
|
|
168
|
+
}, [isOpen]);
|
|
169
|
+
const handleInputBlur = useCallback((e) => {
|
|
170
|
+
onBlur?.(e.target.value);
|
|
171
|
+
}, [onBlur]);
|
|
172
|
+
const handleInputChanged = useCallback((e) => {
|
|
180
173
|
const { value } = e.target;
|
|
181
|
-
const parsedDate = parseDate(value,
|
|
182
|
-
|
|
183
|
-
|
|
174
|
+
const parsedDate = parseDate(value, dateFormat);
|
|
175
|
+
onValidateInput?.(value);
|
|
176
|
+
setInputValue(value);
|
|
184
177
|
if (parsedDate) {
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
if (this.state.selectedDate) {
|
|
190
|
-
this.props.onChange?.(this.state.selectedDate);
|
|
191
|
-
}
|
|
192
|
-
});
|
|
178
|
+
setSelectedDate(parsedDate);
|
|
179
|
+
setMonthDate(parsedDate);
|
|
180
|
+
onChange?.(parsedDate);
|
|
181
|
+
return;
|
|
193
182
|
}
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
selectedDate: this.state.selectedDate,
|
|
198
|
-
monthDate: this.state.selectedDate,
|
|
199
|
-
});
|
|
200
|
-
return;
|
|
201
|
-
}
|
|
202
|
-
this.setState({
|
|
203
|
-
selectedDate: undefined,
|
|
204
|
-
monthDate: undefined,
|
|
205
|
-
}, () => {
|
|
206
|
-
// Signal invalid state by passing null
|
|
207
|
-
this.props.onChange?.(null);
|
|
208
|
-
});
|
|
183
|
+
if (resetOnInvalidValue) {
|
|
184
|
+
setMonthDate(selectedDate);
|
|
185
|
+
return;
|
|
209
186
|
}
|
|
210
|
-
|
|
211
|
-
|
|
187
|
+
setSelectedDate(undefined);
|
|
188
|
+
setMonthDate(undefined);
|
|
189
|
+
// Signal invalid state by passing null
|
|
190
|
+
onChange?.(null);
|
|
191
|
+
}, [dateFormat, onChange, onValidateInput, resetOnInvalidValue, selectedDate]);
|
|
192
|
+
const handleDayChanged = useCallback((newlySelectedDate) => {
|
|
212
193
|
if (!newlySelectedDate) {
|
|
213
|
-
|
|
194
|
+
setIsOpen(false);
|
|
214
195
|
return;
|
|
215
196
|
}
|
|
216
|
-
if (
|
|
217
|
-
|
|
197
|
+
if (selectedDate && isSameDay(selectedDate, newlySelectedDate)) {
|
|
198
|
+
setIsOpen(false);
|
|
218
199
|
return;
|
|
219
200
|
}
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
this.setState({ monthDate: month });
|
|
234
|
-
}
|
|
235
|
-
handleCustomDayClick = (day, _modifiers) => {
|
|
201
|
+
inputRef.current?.focus();
|
|
202
|
+
onValidateInput?.(formatDate(newlySelectedDate, dateFormat));
|
|
203
|
+
setSelectedDate(newlySelectedDate);
|
|
204
|
+
setMonthDate(newlySelectedDate);
|
|
205
|
+
setInputValue(formatDate(newlySelectedDate, dateFormat));
|
|
206
|
+
setIsOpen(false);
|
|
207
|
+
onChange?.(newlySelectedDate);
|
|
208
|
+
}, [dateFormat, onChange, onValidateInput, selectedDate]);
|
|
209
|
+
const handleMonthChanged = useCallback((month) => {
|
|
210
|
+
inputRef.current?.focus();
|
|
211
|
+
setMonthDate(month);
|
|
212
|
+
}, []);
|
|
213
|
+
const handleCustomDayClick = useCallback((day, _modifiers) => {
|
|
236
214
|
// Handle all day clicks, including outside days
|
|
237
|
-
|
|
238
|
-
};
|
|
239
|
-
|
|
240
|
-
return new Date(date.getFullYear(), date.getMonth(), date.getDate());
|
|
241
|
-
}
|
|
242
|
-
alignDatePicker() {
|
|
243
|
-
const { alignPoints } = this.props;
|
|
244
|
-
const container = this.datePickerContainerRef.current?.parentElement;
|
|
245
|
-
if (!alignPoints || !container || !this.rootRef) {
|
|
246
|
-
return;
|
|
247
|
-
}
|
|
248
|
-
const optimalAlignment = getOptimalAlignment({
|
|
249
|
-
targetRegion: elementRegion(this.rootRef),
|
|
250
|
-
selfRegion: elementRegion(container),
|
|
251
|
-
alignPoints,
|
|
252
|
-
});
|
|
253
|
-
const { align } = optimalAlignment.alignment;
|
|
254
|
-
this.setState({
|
|
255
|
-
align,
|
|
256
|
-
}, () => {
|
|
257
|
-
this.props.onAlign?.(align);
|
|
258
|
-
});
|
|
259
|
-
}
|
|
260
|
-
onKeyDown(e) {
|
|
215
|
+
handleDayChanged(day);
|
|
216
|
+
}, [handleDayChanged]);
|
|
217
|
+
const handleKeyDown = useCallback((e) => {
|
|
261
218
|
if (e.key === "Escape" || e.key === "Tab") {
|
|
262
|
-
|
|
219
|
+
setIsOpen(false);
|
|
263
220
|
}
|
|
264
221
|
if (isEnterKey(e)) {
|
|
265
|
-
|
|
222
|
+
onDateInputKeyDown?.(e);
|
|
266
223
|
}
|
|
267
|
-
}
|
|
268
|
-
handleWrapperClick(e) {
|
|
224
|
+
}, [onDateInputKeyDown]);
|
|
225
|
+
const handleWrapperClick = useCallback((e) => {
|
|
269
226
|
const { classList } = e.target;
|
|
270
227
|
/**
|
|
271
228
|
* Prevent default fixes bug BB-332 but prevents in closing other dropdowns (Bug BB-1102)
|
|
@@ -274,25 +231,30 @@ export class WrappedDatePicker extends PureComponent {
|
|
|
274
231
|
if (e.target && classList?.contains(DATEPICKER_OUTSIDE_DAY_SELECTOR)) {
|
|
275
232
|
e.preventDefault();
|
|
276
233
|
}
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
234
|
+
}, []);
|
|
235
|
+
const handleInputClick = useCallback(() => {
|
|
236
|
+
setIsOpen(true);
|
|
237
|
+
}, []);
|
|
238
|
+
const dayPickerClassNames = useMemo(() => {
|
|
239
|
+
const [inputAnchorPoint, pickerAnchorPoint] = align.split(" ");
|
|
240
|
+
return {
|
|
241
|
+
root: classNames("gd-datepicker-picker", "gd-datepicker-OverlayWrapper", `gd-datepicker-OverlayWrapper-${inputAnchorPoint}-xx`, `gd-datepicker-OverlayWrapper-xx-${pickerAnchorPoint}`),
|
|
283
242
|
};
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
243
|
+
}, [align]);
|
|
244
|
+
const componentClasses = classNames("gd-datepicker", className, size, "gd-datepicker-input", isOpen ? "gd-datepicker-focused" : "");
|
|
245
|
+
const inputClasses = classNames("input-text", "small-12", size, `gd-datepicker-input-${datePickerId}`);
|
|
246
|
+
return (_jsxs("div", { "data-testid": "datepicker", className: componentClasses, ref: rootRef, onClick: handleWrapperClick, children: [
|
|
247
|
+
_jsx("input", { autoComplete: "off", "aria-labelledby": accessibilityConfig?.ariaLabelledBy, "aria-label": accessibilityConfig?.ariaLabel ||
|
|
248
|
+
intl.formatMessage({ id: "datePicker.accessibility.label" }), "aria-describedby": accessibilityConfig?.ariaDescribedBy, onKeyDown: handleKeyDown, tabIndex: tabIndex, onClick: handleInputClick, ref: inputRef, value: inputValue, className: inputClasses, placeholder: placeholder, onChange: handleInputChanged, onBlur: handleInputBlur }), isOpen ? (_jsx("div", { id: `datepicker-popup-${datePickerId}`, role: "dialog", ref: datePickerContainerRef, children: _jsx(DayPicker, { classNames: dayPickerClassNames, locale: convertLocale(intl.locale), showOutsideDays: true, mode: "single", selected: selectedDate, month: monthDate, onMonthChange: handleMonthChanged, weekStartsOn: convertWeekStart(weekStart), onDayClick: handleCustomDayClick }) })) : null, _jsx("span", { className: "gd-datepicker-icon gd-icon-calendar" })
|
|
249
|
+
] }));
|
|
289
250
|
}
|
|
290
|
-
const
|
|
251
|
+
export const WrappedDatePicker = memo(WrappedDatePickerCore);
|
|
252
|
+
WrappedDatePicker.displayName = "WrappedDatePicker";
|
|
291
253
|
/**
|
|
292
254
|
* @internal
|
|
293
255
|
*/
|
|
294
256
|
export class Datepicker extends PureComponent {
|
|
295
257
|
render() {
|
|
296
|
-
return (_jsx(IntlWrapper, { locale: this.props.locale, children: _jsx(
|
|
258
|
+
return (_jsx(IntlWrapper, { locale: this.props.locale, children: _jsx(WrappedDatePicker, { ...this.props }) }));
|
|
297
259
|
}
|
|
298
260
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"InputWithNumberFormat.d.ts","sourceRoot":"","sources":["../../src/Form/InputWithNumberFormat.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,WAAW,EAAsD,MAAM,OAAO,CAAC;AAI7F,OAAO,EAAE,KAAK,eAAe,EAAa,MAAM,gBAAgB,CAAC;AAEjE,OAAO,EAAE,KAAK,UAAU,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"InputWithNumberFormat.d.ts","sourceRoot":"","sources":["../../src/Form/InputWithNumberFormat.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,WAAW,EAAsD,MAAM,OAAO,CAAC;AAI7F,OAAO,EAAE,KAAK,eAAe,EAAa,MAAM,gBAAgB,CAAC;AAEjE,OAAO,EAAE,KAAK,UAAU,EAAE,MAAM,cAAc,CAAC;AAmD/C;;GAEG;AACH,MAAM,WAAW,8BAA8B;IAC3C,UAAU,CAAC,EAAE,UAAU,CAAC;CAC3B;AAED;;GAEG;AAEH,MAAM,WAAW,2BAA2B;IACxC,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,OAAO,CAAC;CACtB;AAED;;GAEG;AAEH,MAAM,WAAW,2BACb,SAAQ,8BAA8B,EAAE,IAAI,CAAC,eAAe,EAAE,UAAU,CAAC;IACzE,qGAAqG;IACrG,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,EAAE,CAAC,CAAC,EAAE,WAAW,CAAC,gBAAgB,CAAC,KAAK,IAAI,CAAC;CAChF;AAUD;;GAEG;AACH,eAAO,MAAM,qBAAqB,mEAsEhC,CAAC"}
|
|
@@ -4,20 +4,9 @@ import { memo, useEffect, useRef, useState } from "react";
|
|
|
4
4
|
import { memoize } from "lodash-es";
|
|
5
5
|
import { InputPure } from "./InputPure.js";
|
|
6
6
|
import { DEFAULT_SEPARATORS, formatNumberWithSeparators } from "./numberFormat.js";
|
|
7
|
-
// Highest number (BIGINT) according to gooddata documentation help.gooddata.com object-datatypes
|
|
8
|
-
export const MAX_NUMBER = 10 ** 15;
|
|
9
|
-
// Max number of digits right to decimal point according to gooddata documentation help.gooddata.com object-datatypes
|
|
10
|
-
const MAX_DECIMAL_POINT_NUMBERS = 6;
|
|
11
7
|
const getDanglingDecimalPointRegExp = memoize((decimal) => new RegExp(`\\${decimal}$`));
|
|
12
|
-
|
|
13
|
-
const
|
|
14
|
-
const belowDecimal = numberString.split(".")[1];
|
|
15
|
-
const roundedNumberString = belowDecimal && belowDecimal.length >= MAX_DECIMAL_POINT_NUMBERS
|
|
16
|
-
? parseFloat(numberString).toFixed(MAX_DECIMAL_POINT_NUMBERS)
|
|
17
|
-
: numberString;
|
|
18
|
-
const number = parseFloat(roundedNumberString);
|
|
19
|
-
return number === 0 ? 0 : number;
|
|
20
|
-
};
|
|
8
|
+
// A half-typed exponent ("1e", "1e+") stays valid so it can be entered one character at a time.
|
|
9
|
+
const buildValidationRegExp = ({ thousand, decimal }) => new RegExp(`^-?(\\d|\\${thousand})*(\\${decimal}\\d*)?([eE][-+]?\\d*)?$`);
|
|
21
10
|
// Removes thousand separators while keeping the decimal separator intact, so the value can be
|
|
22
11
|
// edited as plain digits (no separators popping in/out) while the input is focused.
|
|
23
12
|
const removeThousandSeparators = (value, { thousand } = DEFAULT_SEPARATORS) => value.split(thousand).join("");
|
|
@@ -27,7 +16,7 @@ const convertFormattedStringToStandard = (formattedString, { thousand, decimal }
|
|
|
27
16
|
const withStandardDecimalPoint = withoutDanglingDecimalPoint.split(decimal).join(".");
|
|
28
17
|
return withStandardDecimalPoint.length > 0 ? withStandardDecimalPoint : null;
|
|
29
18
|
};
|
|
30
|
-
const parse = (value, separators
|
|
19
|
+
const parse = (value, separators) => {
|
|
31
20
|
if (value === null || value === "" || value === "-") {
|
|
32
21
|
return null;
|
|
33
22
|
}
|
|
@@ -35,11 +24,16 @@ const parse = (value, separators = DEFAULT_SEPARATORS) => {
|
|
|
35
24
|
if (numberString === null) {
|
|
36
25
|
return null;
|
|
37
26
|
}
|
|
38
|
-
|
|
27
|
+
const number = parseFloat(numberString);
|
|
28
|
+
return number === 0 ? 0 : number;
|
|
39
29
|
};
|
|
40
|
-
|
|
30
|
+
// The wire layer draws the same line: it throws on Infinity/NaN.
|
|
31
|
+
const isValid = (value, separators) => {
|
|
32
|
+
if (!buildValidationRegExp(separators).test(value)) {
|
|
33
|
+
return false;
|
|
34
|
+
}
|
|
41
35
|
const parsed = parse(value, separators);
|
|
42
|
-
return
|
|
36
|
+
return parsed === null || Number.isFinite(parsed);
|
|
43
37
|
};
|
|
44
38
|
// Coerces input value to number for formatting (handles string/number/null/undefined)
|
|
45
39
|
const toNumberValue = (value) => {
|
|
@@ -51,7 +45,7 @@ const toNumberValue = (value) => {
|
|
|
51
45
|
/**
|
|
52
46
|
* @internal
|
|
53
47
|
*/
|
|
54
|
-
export const InputWithNumberFormat = memo(function InputWithNumberFormat({ separators, value: propValue, onChange, onFocus, onBlur, ...restProps }) {
|
|
48
|
+
export const InputWithNumberFormat = memo(function InputWithNumberFormat({ separators = DEFAULT_SEPARATORS, value: propValue, onChange, onFocus, onBlur, ...restProps }) {
|
|
55
49
|
const inputRef = useRef(null);
|
|
56
50
|
const [value, setValue] = useState(() => formatNumberWithSeparators(toNumberValue(propValue), separators));
|
|
57
51
|
const [isFocused, setIsFocused] = useState(false);
|
package/esm/index.d.ts
CHANGED
|
@@ -34,7 +34,7 @@ export { type IYamlEditorProps, YamlEditor } from "./syntaxHighlightingInput/Yam
|
|
|
34
34
|
export { type IYamlPosition, type YamlCompletionSource, yamlPositionAt, } from "./syntaxHighlightingInput/yamlPosition.js";
|
|
35
35
|
export type { IDropdownButtonAccessibilityConfig, IButtonAccessibilityConfig, IButtonProps, } from "./Button/typings.js";
|
|
36
36
|
export { Button } from "./Button/Button.js";
|
|
37
|
-
export { Datepicker, type
|
|
37
|
+
export { Datepicker, type IDatePickerProps } from "./Datepicker/Datepicker.js";
|
|
38
38
|
export type { Separators, LabelSize } from "./Form/typings.js";
|
|
39
39
|
export { Input, type IInputState } from "./Form/Input.js";
|
|
40
40
|
export { InputPure, type IInputPureProps, type IInputPureAccessibilityConfig } from "./Form/InputPure.js";
|
|
@@ -305,7 +305,7 @@ export type { OnOpenedChange, IOnOpenedChangeParams, IMenuPositionConfig, MenuAl
|
|
|
305
305
|
export type { IMenuStateProps, IMenuStateConfig } from "./Menu/MenuState.js";
|
|
306
306
|
export type { IScrollGradientProps } from "./ScrollGradient/typings.js";
|
|
307
307
|
export { ScrollGradient } from "./ScrollGradient/ScrollGradient.js";
|
|
308
|
-
export { ChartSortingDialog,
|
|
308
|
+
export { ChartSortingDialog, type IChartSortingProps } from "./ChartSorting/ChartSorting.js";
|
|
309
309
|
export { SORT_TARGET_TYPE, type IAvailableSortsGroup, type MeasureSortSuggestion, type ISortTypeItem, type IBucketItemDescriptor, type IBucketItemDescriptors, } from "./ChartSorting/types.js";
|
|
310
310
|
export { StylingSettingWidget, type IStylingSettingWidgetProps, } from "./SettingWidget/StylingSettingWidget/StylingSettingWidget.js";
|
|
311
311
|
export { defaultThemeMetadataObject, defaultColorPaletteMetadataObject, getColorsPreviewFromTheme, getColorsPreviewFromColorPalette, } from "./SettingWidget/StylingSettingWidget/utils.js";
|