@gooddata/sdk-ui-filters 11.57.0-alpha.4 → 11.57.0-alpha.6
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/DateFilter/AbsoluteDateFilterForm/AbsoluteDateFilterForm.d.ts +12 -2
- package/esm/DateFilter/AbsoluteDateFilterForm/AbsoluteDateFilterForm.d.ts.map +1 -1
- package/esm/DateFilter/AbsoluteDateFilterForm/AbsoluteDateFilterForm.js +4 -4
- package/esm/DateFilter/AbsoluteDateFilterForm/conversions.d.ts +1 -0
- package/esm/DateFilter/AbsoluteDateFilterForm/conversions.d.ts.map +1 -1
- package/esm/DateFilter/AbsoluteDateFilterForm/conversions.js +8 -0
- package/esm/DateFilter/DateFilterBody/DateFilterBody.d.ts.map +1 -1
- package/esm/DateFilter/DateFilterBody/DateFilterBody.js +8 -3
- package/esm/DateFilter/DateFilterBody/DateFilterFormContent.d.ts +2 -1
- package/esm/DateFilter/DateFilterBody/DateFilterFormContent.d.ts.map +1 -1
- package/esm/DateFilter/DateFilterBody/DateFilterFormContent.js +22 -19
- package/esm/DateFilter/PeriodRangePicker/AccessibleFieldInput.d.ts +19 -0
- package/esm/DateFilter/PeriodRangePicker/AccessibleFieldInput.d.ts.map +1 -0
- package/esm/DateFilter/PeriodRangePicker/AccessibleFieldInput.js +91 -0
- package/esm/DateFilter/PeriodRangePicker/PeriodRangePickerImpl.d.ts +23 -3
- package/esm/DateFilter/PeriodRangePicker/PeriodRangePickerImpl.d.ts.map +1 -1
- package/esm/DateFilter/PeriodRangePicker/PeriodRangePickerImpl.js +349 -38
- package/esm/DateFilter/PeriodRangePicker/dateFnsRangePicker.d.ts +9 -0
- package/esm/DateFilter/PeriodRangePicker/dateFnsRangePicker.d.ts.map +1 -0
- package/esm/DateFilter/PeriodRangePicker/dateFnsRangePicker.js +79 -0
- package/esm/DateFilter/PeriodRangePicker/periodRangePickerAccessibility.d.ts +57 -0
- package/esm/DateFilter/PeriodRangePicker/periodRangePickerAccessibility.d.ts.map +1 -0
- package/esm/DateFilter/PeriodRangePicker/periodRangePickerAccessibility.js +47 -0
- package/esm/DateFilter/PeriodRangePicker/types.d.ts +12 -1
- package/esm/DateFilter/PeriodRangePicker/types.d.ts.map +1 -1
- package/esm/DateFilter/PeriodRangePicker/weekStartDateFnsLocale.d.ts +28 -0
- package/esm/DateFilter/PeriodRangePicker/weekStartDateFnsLocale.d.ts.map +1 -0
- package/esm/DateFilter/PeriodRangePicker/weekStartDateFnsLocale.js +47 -0
- package/esm/DateFilter/accessibility/keyboardNavigation.d.ts +6 -7
- package/esm/DateFilter/accessibility/keyboardNavigation.d.ts.map +1 -1
- package/esm/DateFilter/accessibility/keyboardNavigation.js +3 -2
- package/esm/DateFilter/constants/Platform.d.ts +1 -0
- package/esm/DateFilter/constants/Platform.d.ts.map +1 -1
- package/esm/DateFilter/constants/Platform.js +2 -0
- package/esm/DateFilter/utils/StaticPeriodConversions.d.ts +6 -0
- package/esm/DateFilter/utils/StaticPeriodConversions.d.ts.map +1 -1
- package/esm/DateFilter/utils/StaticPeriodConversions.js +13 -0
- package/esm/FilterGroup/FilterGroup.d.ts.map +1 -1
- package/esm/FilterGroup/FilterGroup.js +1 -4
- package/esm/sdk-ui-filters.d.ts +11 -1
- package/esm/shared/utils/domUtilities.d.ts +9 -0
- package/esm/shared/utils/domUtilities.d.ts.map +1 -0
- package/esm/shared/utils/domUtilities.js +12 -0
- package/package.json +16 -16
- package/styles/css/components/PeriodRangePicker.css +20 -42
- package/styles/css/components/PeriodRangePicker.css.map +1 -1
- package/styles/css/dateFilter.css +20 -42
- package/styles/css/dateFilter.css.map +1 -1
- package/styles/css/main.css +20 -42
- package/styles/css/main.css.map +1 -1
- package/styles/scss/components/PeriodRangePicker.scss +38 -49
- package/esm/DateFilter/PeriodRangePicker/momentRangePicker.d.ts +0 -9
- package/esm/DateFilter/PeriodRangePicker/momentRangePicker.d.ts.map +0 -1
- package/esm/DateFilter/PeriodRangePicker/momentRangePicker.js +0 -9
- package/esm/DateFilter/PeriodRangePicker/weekStartMomentLocale.d.ts +0 -16
- package/esm/DateFilter/PeriodRangePicker/weekStartMomentLocale.d.ts.map +0 -1
- package/esm/DateFilter/PeriodRangePicker/weekStartMomentLocale.js +0 -30
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type ReactNode } from "react";
|
|
1
|
+
import { type ReactNode, type RefObject } from "react";
|
|
2
2
|
import { type DateFilterGranularity, type WeekStart } from "@gooddata/sdk-model";
|
|
3
3
|
import { type IAccessibilityConfigBase } from "@gooddata/sdk-ui-kit";
|
|
4
4
|
import { type DateFilterOption, type IUiAbsoluteDateFilterForm } from "../interfaces/index.js";
|
|
@@ -26,6 +26,11 @@ export interface IAbsoluteDateFilterFormProps {
|
|
|
26
26
|
withoutApply?: boolean;
|
|
27
27
|
submitForm: () => void;
|
|
28
28
|
customRangeHint?: ReactNode;
|
|
29
|
+
/**
|
|
30
|
+
* Reports whether the `PeriodRangePicker` branch's fields currently form a submittable range - see
|
|
31
|
+
* `IPeriodRangePickerProps.onValidityChange`. Not called for the classic `DateRangePicker` branch.
|
|
32
|
+
*/
|
|
33
|
+
onPeriodRangeValidityChange?: (isValid: boolean) => void;
|
|
29
34
|
/**
|
|
30
35
|
* Enables Day/Week/Month/Quarter/Year granularity switching.
|
|
31
36
|
*
|
|
@@ -43,9 +48,14 @@ export interface IAbsoluteDateFilterFormProps {
|
|
|
43
48
|
* Accessibility configuration for the absolute date filter form.
|
|
44
49
|
*/
|
|
45
50
|
accessibilityConfig?: IAbsoluteDateFilterFormAccessibilityConfig;
|
|
51
|
+
/**
|
|
52
|
+
* Ref for the granularity tabs' wrapping element - used for keyboard navigation focus management.
|
|
53
|
+
* Only relevant while {@link IAbsoluteDateFilterFormProps.isGranularityEnabled} renders the tabs.
|
|
54
|
+
*/
|
|
55
|
+
granularityTabsRef?: RefObject<HTMLDivElement | null>;
|
|
46
56
|
}
|
|
47
57
|
/**
|
|
48
58
|
* @internal
|
|
49
59
|
*/
|
|
50
|
-
export declare function AbsoluteDateFilterForm({ dateFormat, isMobile, selectedFilterOption, isTimeEnabled, isSecondsEnabled, weekStart, shouldOverlayDatePicker, withoutApply, onSelectedFilterOptionChange, submitForm, customRangeHint, isGranularityEnabled, availableGranularities, accessibilityConfig, }: IAbsoluteDateFilterFormProps): import("react/jsx-runtime").JSX.Element;
|
|
60
|
+
export declare function AbsoluteDateFilterForm({ dateFormat, isMobile, selectedFilterOption, isTimeEnabled, isSecondsEnabled, weekStart, shouldOverlayDatePicker, withoutApply, onSelectedFilterOptionChange, submitForm, customRangeHint, onPeriodRangeValidityChange, isGranularityEnabled, availableGranularities, accessibilityConfig, granularityTabsRef, }: IAbsoluteDateFilterFormProps): import("react/jsx-runtime").JSX.Element;
|
|
51
61
|
//# sourceMappingURL=AbsoluteDateFilterForm.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AbsoluteDateFilterForm.d.ts","sourceRoot":"","sources":["../../../src/DateFilter/AbsoluteDateFilterForm/AbsoluteDateFilterForm.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"AbsoluteDateFilterForm.d.ts","sourceRoot":"","sources":["../../../src/DateFilter/AbsoluteDateFilterForm/AbsoluteDateFilterForm.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,SAAS,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAIvD,OAAO,EAEH,KAAK,qBAAqB,EAC1B,KAAK,SAAS,EACjB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,KAAK,wBAAwB,EAAE,MAAM,sBAAsB,CAAC;AAMrE,OAAO,EAAE,KAAK,gBAAgB,EAAE,KAAK,yBAAyB,EAAE,MAAM,wBAAwB,CAAC;AAW/F;;GAEG;AACH,MAAM,WAAW,0CAA2C,SAAQ,wBAAwB;IACxF;;OAEG;IACH,EAAE,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;GAEG;AACH,MAAM,WAAW,4BAA4B;IACzC,UAAU,EAAE,MAAM,CAAC;IACnB,oBAAoB,EAAE,yBAAyB,CAAC;IAChD,QAAQ,EAAE,OAAO,CAAC;IAClB,4BAA4B,EAAE,CAAC,MAAM,EAAE,gBAAgB,KAAK,IAAI,CAAC;IACjE,aAAa,EAAE,OAAO,CAAC;IACvB,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB,uBAAuB,CAAC,EAAE,OAAO,CAAC;IAClC,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,UAAU,EAAE,MAAM,IAAI,CAAC;IACvB,eAAe,CAAC,EAAE,SAAS,CAAC;IAC5B;;;OAGG;IACH,2BAA2B,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;IACzD;;;;;;;OAOG;IACH,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B;;OAEG;IACH,sBAAsB,EAAE,qBAAqB,EAAE,CAAC;IAChD;;OAEG;IACH,mBAAmB,CAAC,EAAE,0CAA0C,CAAC;IACjE;;;OAGG;IACH,kBAAkB,CAAC,EAAE,SAAS,CAAC,cAAc,GAAG,IAAI,CAAC,CAAC;CACzD;AAYD;;GAEG;AACH,wBAAgB,sBAAsB,CAAC,EACnC,UAAU,EACV,QAAQ,EACR,oBAAoB,EACpB,aAAa,EACb,gBAAwB,EACxB,SAAS,EACT,uBAAuB,EACvB,YAAY,EACZ,4BAA4B,EAC5B,UAAU,EACV,eAAe,EACf,2BAA2B,EAC3B,oBAA4B,EAC5B,sBAAsB,EACtB,mBAAmB,EACnB,kBAAkB,GACrB,EAAE,4BAA4B,2CAoG9B"}
|
|
@@ -4,7 +4,7 @@ import { DATE_FILTER_ABSOLUTE_GRANULARITY_TAB_ID } from "../accessibility/elemen
|
|
|
4
4
|
import { DateRangePicker } from "../DateRangePicker/DateRangePicker.js";
|
|
5
5
|
import { GranularityTabs } from "../GranularityTabs.js";
|
|
6
6
|
import { PeriodRangePicker } from "../PeriodRangePicker/PeriodRangePicker.js";
|
|
7
|
-
import { dateFilterValueToDateRange, dateRangeToDateFilterValue, periodRangeToDateFilterValue, } from "./conversions.js";
|
|
7
|
+
import { dateFilterValueToDateRange, dateFilterValueToPeriodRange, dateRangeToDateFilterValue, periodRangeToDateFilterValue, } from "./conversions.js";
|
|
8
8
|
const dayPickerProps = {
|
|
9
9
|
mode: "range",
|
|
10
10
|
weekStartsOn: 0, // Sunday, regardless of locale
|
|
@@ -13,7 +13,7 @@ const isPeriodPickerGranularity = (granularity) => DEFAULT_ABSOLUTE_DATE_FILTER_
|
|
|
13
13
|
/**
|
|
14
14
|
* @internal
|
|
15
15
|
*/
|
|
16
|
-
export function AbsoluteDateFilterForm({ dateFormat, isMobile, selectedFilterOption, isTimeEnabled, isSecondsEnabled = false, weekStart, shouldOverlayDatePicker, withoutApply, onSelectedFilterOptionChange, submitForm, customRangeHint, isGranularityEnabled = false, availableGranularities, accessibilityConfig, }) {
|
|
16
|
+
export function AbsoluteDateFilterForm({ dateFormat, isMobile, selectedFilterOption, isTimeEnabled, isSecondsEnabled = false, weekStart, shouldOverlayDatePicker, withoutApply, onSelectedFilterOptionChange, submitForm, customRangeHint, onPeriodRangeValidityChange, isGranularityEnabled = false, availableGranularities, accessibilityConfig, granularityTabsRef, }) {
|
|
17
17
|
const selectedGranularity = selectedFilterOption.granularity ?? availableGranularities[0];
|
|
18
18
|
const showGranularityTabs = isGranularityEnabled && availableGranularities.length > 0;
|
|
19
19
|
const handleRangeChange = (range) => {
|
|
@@ -44,6 +44,6 @@ export function AbsoluteDateFilterForm({ dateFormat, isMobile, selectedFilterOpt
|
|
|
44
44
|
// TODO MC-5322: time granularity is not supported in the new picker yet - the hour/minute/second can't be
|
|
45
45
|
// modified, so the selected range always spans the whole day (00:00-23:59[:59] once time is enabled).
|
|
46
46
|
// This will be added as part of MC-5322.
|
|
47
|
-
const picker = showGranularityTabs && isPeriodPickerGranularity(selectedGranularity) ? (_jsx(PeriodRangePicker, { granularity: selectedGranularity, range:
|
|
48
|
-
return (_jsxs(_Fragment, { children: [showGranularityTabs ? (_jsx(GranularityTabs, { availableGranularities: availableGranularities, selectedGranularity: selectedGranularity, onSelectedGranularityChange: handleGranularityChange, accessibilityConfig: { ariaControls: accessibilityConfig?.id }, className: "gd-absolute-filter-form-granularity-tabs s-absolute-filter-form-granularity-tabs", selectedTabId: DATE_FILTER_ABSOLUTE_GRANULARITY_TAB_ID })) : null, showGranularityTabs ? (_jsx("div", { id: accessibilityConfig?.id, role: "tabpanel", "aria-labelledby": DATE_FILTER_ABSOLUTE_GRANULARITY_TAB_ID, children: picker })) : (picker)] }));
|
|
47
|
+
const picker = showGranularityTabs && isPeriodPickerGranularity(selectedGranularity) ? (_jsx(PeriodRangePicker, { granularity: selectedGranularity, range: dateFilterValueToPeriodRange(selectedFilterOption), onRangeChange: handlePeriodRangeChange, isMobile: isMobile, weekStart: weekStart, withoutApply: withoutApply, submitForm: submitForm, dateFormat: dateFormat, customRangeHint: customRangeHint, onValidityChange: onPeriodRangeValidityChange }, selectedGranularity)) : (_jsx(DateRangePicker, { dateFormat: dateFormat, onRangeChange: handleRangeChange, range: dateFilterValueToDateRange(selectedFilterOption, isTimeEnabled, isSecondsEnabled), isMobile: isMobile, dayPickerProps: dayPickerProps, isTimeEnabled: isTimeEnabled, isSecondsEnabled: isSecondsEnabled, weekStart: weekStart, shouldOverlayDatePicker: shouldOverlayDatePicker, submitForm: submitForm, withoutApply: withoutApply, customRangeHint: customRangeHint }));
|
|
48
|
+
return (_jsxs(_Fragment, { children: [showGranularityTabs ? (_jsx("div", { ref: granularityTabsRef, children: _jsx(GranularityTabs, { availableGranularities: availableGranularities, selectedGranularity: selectedGranularity, onSelectedGranularityChange: handleGranularityChange, accessibilityConfig: { ariaControls: accessibilityConfig?.id }, className: "gd-absolute-filter-form-granularity-tabs s-absolute-filter-form-granularity-tabs", selectedTabId: DATE_FILTER_ABSOLUTE_GRANULARITY_TAB_ID }) })) : null, showGranularityTabs ? (_jsx("div", { id: accessibilityConfig?.id, role: "tabpanel", "aria-labelledby": DATE_FILTER_ABSOLUTE_GRANULARITY_TAB_ID, children: picker })) : (picker)] }));
|
|
49
49
|
}
|
|
@@ -4,6 +4,7 @@ import { type IUiAbsoluteDateFilterForm } from "../interfaces/index.js";
|
|
|
4
4
|
import { type IPeriodRange } from "../PeriodRangePicker/types.js";
|
|
5
5
|
export declare const dateRangeToDateFilterValue: (range: IDateRange, localIdentifier: string, isTimeForAbsoluteRangeEnabled: boolean, emptyValueHandling?: EmptyValues, isSecondsForAbsoluteRangeEnabled?: boolean) => IUiAbsoluteDateFilterForm;
|
|
6
6
|
export declare const dateFilterValueToDateRange: (value: IUiAbsoluteDateFilterForm, isTimeForAbsoluteRangeEnabled?: boolean, isSecondsForAbsoluteRangeEnabled?: boolean) => IDateRange;
|
|
7
|
+
export declare const dateFilterValueToPeriodRange: (value: IUiAbsoluteDateFilterForm) => IPeriodRange;
|
|
7
8
|
/**
|
|
8
9
|
* @internal
|
|
9
10
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"conversions.d.ts","sourceRoot":"","sources":["../../../src/DateFilter/AbsoluteDateFilterForm/conversions.ts"],"names":[],"mappings":"AAEA,OAAO,EAAmB,KAAK,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAWxE,OAAO,EAAE,KAAK,UAAU,EAAE,MAAM,6BAA6B,CAAC;AAC9D,OAAO,EAAE,KAAK,yBAAyB,EAAE,MAAM,wBAAwB,CAAC;AACxE,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAMlE,eAAO,MAAM,0BAA0B,UAC5B,UAAU,mBACA,MAAM,iCACQ,OAAO,uBACjB,WAAW,iDAEjC,yBAeF,CAAC;AAEF,eAAO,MAAM,0BAA0B,UAC5B,yBAAyB,0FAGjC,UAmBF,CAAC;AAEF;;GAEG;AACH,MAAM,WAAW,oCAAoC;IACjD,KAAK,EAAE,YAAY,CAAC;IACpB,eAAe,EAAE,MAAM,CAAC;IACxB,6BAA6B,EAAE,OAAO,CAAC;IACvC,kBAAkB,CAAC,EAAE,WAAW,CAAC;IACjC,gCAAgC,CAAC,EAAE,OAAO,CAAC;CAC9C;AAED;;;GAGG;AACH,eAAO,MAAM,4BAA4B,qHAMtC,oCAAoC,KAAG,yBAmBzC,CAAC"}
|
|
1
|
+
{"version":3,"file":"conversions.d.ts","sourceRoot":"","sources":["../../../src/DateFilter/AbsoluteDateFilterForm/conversions.ts"],"names":[],"mappings":"AAEA,OAAO,EAAmB,KAAK,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAWxE,OAAO,EAAE,KAAK,UAAU,EAAE,MAAM,6BAA6B,CAAC;AAC9D,OAAO,EAAE,KAAK,yBAAyB,EAAE,MAAM,wBAAwB,CAAC;AACxE,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAMlE,eAAO,MAAM,0BAA0B,UAC5B,UAAU,mBACA,MAAM,iCACQ,OAAO,uBACjB,WAAW,iDAEjC,yBAeF,CAAC;AAEF,eAAO,MAAM,0BAA0B,UAC5B,yBAAyB,0FAGjC,UAmBF,CAAC;AAEF,eAAO,MAAM,4BAA4B,UAAW,yBAAyB,KAAG,YAQ/E,CAAC;AAEF;;GAEG;AACH,MAAM,WAAW,oCAAoC;IACjD,KAAK,EAAE,YAAY,CAAC;IACpB,eAAe,EAAE,MAAM,CAAC;IACxB,6BAA6B,EAAE,OAAO,CAAC;IACvC,kBAAkB,CAAC,EAAE,WAAW,CAAC;IACjC,gCAAgC,CAAC,EAAE,OAAO,CAAC;CAC9C;AAED;;;GAGG;AACH,eAAO,MAAM,4BAA4B,qHAMtC,oCAAoC,KAAG,yBAmBzC,CAAC"}
|
|
@@ -33,6 +33,14 @@ export const dateFilterValueToDateRange = (value, isTimeForAbsoluteRangeEnabled
|
|
|
33
33
|
}
|
|
34
34
|
return { from, to };
|
|
35
35
|
};
|
|
36
|
+
export const dateFilterValueToPeriodRange = (value) => {
|
|
37
|
+
const from = convertPlatformDateStringToDate(value.from);
|
|
38
|
+
const to = convertPlatformDateStringToDate(value.to);
|
|
39
|
+
return {
|
|
40
|
+
from: convertDateToPlatformDateString(from, platformDateFormat) ?? undefined,
|
|
41
|
+
to: convertDateToPlatformDateString(to, platformDateFormat) ?? undefined,
|
|
42
|
+
};
|
|
43
|
+
};
|
|
36
44
|
/**
|
|
37
45
|
* Converts a resolved period-picker range into an absolute date filter value, extending it to the
|
|
38
46
|
* start/end of day when time-of-day is enabled.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DateFilterBody.d.ts","sourceRoot":"","sources":["../../../src/DateFilter/DateFilterBody/DateFilterBody.tsx"],"names":[],"mappings":"AAEA,OAAO,EAGH,KAAK,YAAY,EACjB,KAAK,SAAS,EAMjB,MAAM,OAAO,CAAC;AAMf,OAAO,EACH,KAAK,qBAAqB,EAC1B,KAAK,gBAAgB,EACrB,KAAK,SAAS,EAKjB,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"DateFilterBody.d.ts","sourceRoot":"","sources":["../../../src/DateFilter/DateFilterBody/DateFilterBody.tsx"],"names":[],"mappings":"AAEA,OAAO,EAGH,KAAK,YAAY,EACjB,KAAK,SAAS,EAMjB,MAAM,OAAO,CAAC;AAMf,OAAO,EACH,KAAK,qBAAqB,EAC1B,KAAK,gBAAgB,EACrB,KAAK,SAAS,EAKjB,MAAM,qBAAqB,CAAC;AAK7B,OAAO,EACH,KAAK,gBAAgB,EACrB,KAAK,wBAAwB,EAC7B,KAAK,yBAAyB,EAGjC,MAAM,wBAAwB,CAAC;AA4BhC,MAAM,WAAW,oBAAoB;IACjC,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,wBAAwB,CAAC;IACxC,oBAAoB,EAAE,gBAAgB,CAAC;IACvC,4BAA4B,EAAE,CAAC,MAAM,EAAE,gBAAgB,KAAK,IAAI,CAAC;IAEjE,oBAAoB,EAAE,OAAO,CAAC;IAC9B,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,6BAA6B,EAAE,OAAO,CAAC;IACvC,4BAA4B,EAAE,CAAC,UAAU,EAAE,OAAO,KAAK,IAAI,CAAC;IAC5D,6BAA6B,EAAE,OAAO,CAAC;IACvC,gCAAgC,CAAC,EAAE,OAAO,CAAC;IAE3C,sCAAsC,EAAE,OAAO,CAAC;IAEhD,sBAAsB,EAAE,qBAAqB,EAAE,CAAC;IAEhD,UAAU,EAAE,OAAO,CAAC;IACpB,QAAQ,EAAE,OAAO,CAAC;IAClB,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAE5B,YAAY,EAAE,MAAM,IAAI,CAAC;IACzB,aAAa,EAAE,MAAM,IAAI,CAAC;IAC1B,aAAa,EAAE,MAAM,IAAI,CAAC;IAE1B,MAAM,CAAC,EAAE,yBAAyB,CAAC;IACnC,gBAAgB,EAAE,YAAY,CAAC;IAE/B,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB,sBAAsB,CAAC,EAAE,OAAO,CAAC;IACjC,oBAAoB,EAAE,MAAM,IAAI,CAAC;IAEjC,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,EAAE,CAAC,EAAE,MAAM,CAAC;IAEZ;;;OAGG;IACH,eAAe,CAAC,EAAE,gBAAgB,CAAC;IAEnC;;;;OAIG;IACH,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAEhC;;;;OAIG;IACH,eAAe,CAAC,EAAE,SAAS,CAAC;CAC/B;AAED,eAAO,MAAM,cAAc,iHA0czB,CAAC"}
|
|
@@ -6,6 +6,7 @@ import { isEmpty } from "lodash-es";
|
|
|
6
6
|
import { useIntl } from "react-intl";
|
|
7
7
|
import { isAbsoluteDateFilterForm, isAllTimeDateFilterOption, isEmptyValuesDateFilterOption, isRelativeDateFilterForm, } from "@gooddata/sdk-model";
|
|
8
8
|
import { useIdPrefixed } from "@gooddata/sdk-ui-kit";
|
|
9
|
+
import { isEditableElement } from "../../shared/utils/domUtilities.js";
|
|
9
10
|
import { CheckboxSection } from "../CheckboxSection/CheckboxSection.js";
|
|
10
11
|
import { getDateFilterOptionGranularity } from "../utils/OptionUtils.js";
|
|
11
12
|
import { ensureCompatibleAbsoluteGranularity, ensureCompatibleGranularity, filterStandardGranularities, getDefaultCalendarTab, getFilteredGranularities, getFilteredPresets, getFiscalTabsConfig, } from "../utils/presetFilterUtils.js";
|
|
@@ -31,6 +32,10 @@ export const DateFilterBody = forwardRef((props, ref) => {
|
|
|
31
32
|
const rootRef = useRef(null);
|
|
32
33
|
const didResetMobileScroll = useRef(false);
|
|
33
34
|
const didSyncInitialMobileRoute = useRef(false);
|
|
35
|
+
// Gates Apply independently of `errors`: a garbled/emptied PeriodRangePicker field never reaches
|
|
36
|
+
// `onSelectedFilterOptionChange`, so `errors` alone would stay stale and leave Apply enabled - see
|
|
37
|
+
// `IPeriodRangePickerProps.onValidityChange`.
|
|
38
|
+
const [isPeriodRangeValid, setIsPeriodRangeValid] = useState(true);
|
|
34
39
|
const intl = useIntl();
|
|
35
40
|
const fiscalTabsConfig = getFiscalTabsConfig(props.filterOptions.relativePreset, props.activeCalendars);
|
|
36
41
|
const [selectedTab, setSelectedTab] = useState(() => getDefaultCalendarTab(props.activeCalendars, props.selectedFilterOption));
|
|
@@ -164,7 +169,7 @@ export const DateFilterBody = forwardRef((props, ref) => {
|
|
|
164
169
|
const hasFormOptions = !!(filterOptions.absoluteForm ||
|
|
165
170
|
(filterOptions.relativeForm && availableGranularities.length > 0));
|
|
166
171
|
const handleKeyDown = (e) => {
|
|
167
|
-
if (e.key === "ArrowLeft" && route) {
|
|
172
|
+
if (e.key === "ArrowLeft" && route && !isEditableElement(e.target)) {
|
|
168
173
|
e.preventDefault();
|
|
169
174
|
e.stopPropagation();
|
|
170
175
|
handleBackNavigation();
|
|
@@ -188,7 +193,7 @@ export const DateFilterBody = forwardRef((props, ref) => {
|
|
|
188
193
|
return (_jsxs("div", { ref: rootRef, className: cx(!isMobile && "gd-extended-date-filter-body-redesigned", "gd-extended-date-filter-body", "s-extended-date-filters-body", isMobile && "gd-extended-date-filter-body-mobile", route && "gd-active-form"), onKeyDown: handleKeyDown, onFocus: handleFocus, role: "dialog", id: formId, "aria-label": formLabel, children: [route === null && isMobile ? (_jsx("div", { className: "gd-extended-date-filter-mobile-header", onClick: () => {
|
|
189
194
|
onCancelClick();
|
|
190
195
|
closeDropdown();
|
|
191
|
-
}, children: dateFilterButton })) : null, route ? (_jsx("div", { className: "gd-extended-date-filter-form-wrapper", ref: ref, children: _jsx(DateFilterFormContent, { filterOptions: filterOptions, selectedFilterOption: selectedFilterOption, onSelectedFilterOptionChange: onSelectedFilterOptionChange, dateFormat: dateFormat, weekStart: weekStart, isTimeForAbsoluteRangeEnabled: isTimeForAbsoluteRangeEnabled, isSecondsForAbsoluteRangeEnabled: isSecondsForAbsoluteRangeEnabled, isAbsoluteDateFilterGranularityEnabled: props.isAbsoluteDateFilterGranularityEnabled, availableGranularities: filteredAvailableGranularities, absoluteAvailableGranularities: filteredAbsoluteAvailableGranularities, isMobile: isMobile, withoutApply: withoutApply, enableEmptyDateValues: props.enableEmptyDateValues, customRangeHint: props.customRangeHint, activeForm: route, onBackNavigation: handleBackNavigation, onClose: closeDropdown, submitForm: () => {
|
|
196
|
+
}, children: dateFilterButton })) : null, route ? (_jsx("div", { className: "gd-extended-date-filter-form-wrapper", ref: ref, children: _jsx(DateFilterFormContent, { filterOptions: filterOptions, selectedFilterOption: selectedFilterOption, onSelectedFilterOptionChange: onSelectedFilterOptionChange, dateFormat: dateFormat, weekStart: weekStart, isTimeForAbsoluteRangeEnabled: isTimeForAbsoluteRangeEnabled, isSecondsForAbsoluteRangeEnabled: isSecondsForAbsoluteRangeEnabled, isAbsoluteDateFilterGranularityEnabled: props.isAbsoluteDateFilterGranularityEnabled, availableGranularities: filteredAvailableGranularities, absoluteAvailableGranularities: filteredAbsoluteAvailableGranularities, isMobile: isMobile, withoutApply: withoutApply, enableEmptyDateValues: props.enableEmptyDateValues, customRangeHint: props.customRangeHint, onPeriodRangeValidityChange: setIsPeriodRangeValid, activeForm: route, onBackNavigation: handleBackNavigation, onClose: closeDropdown, submitForm: () => {
|
|
192
197
|
onApplyClick();
|
|
193
198
|
if (!withoutApply) {
|
|
194
199
|
closeDropdown();
|
|
@@ -224,7 +229,7 @@ export const DateFilterBody = forwardRef((props, ref) => {
|
|
|
224
229
|
: undefined }), _jsxs("div", { role: "group", className: cx("gd-extended-date-filter-actions"), children: [_jsx("div", { className: "gd-extended-date-filter-actions-left-content", children: isConfigurationEnabled ? (_jsx(DateFilterConfigurationButton, { onConfiguration: onConfigurationClick })) : null }), _jsxs("div", { className: "gd-extended-date-filter-actions-buttons", children: [_jsx(DateFilterBodyButton, { messageId: withoutApply ? "close" : "cancel", className: cx("gd-button-secondary", isMobile ? "gd-button-medium" : "gd-button-small", withoutApply ? "s-date-filter-close" : "s-date-filter-cancel"), onClick: () => {
|
|
225
230
|
onCancelClick();
|
|
226
231
|
closeDropdown();
|
|
227
|
-
} }), !withoutApply && (_jsx(DateFilterBodyButton, { messageId: "apply", className: cx("gd-button-action", isMobile ? "gd-button-medium" : "gd-button-small", "s-date-filter-apply"), disabled: !isEmpty(errors), onClick: () => {
|
|
232
|
+
} }), !withoutApply && (_jsx(DateFilterBodyButton, { messageId: "apply", className: cx("gd-button-action", isMobile ? "gd-button-medium" : "gd-button-small", "s-date-filter-apply"), disabled: !isEmpty(errors) || !isPeriodRangeValid, onClick: () => {
|
|
228
233
|
onApplyClick();
|
|
229
234
|
closeDropdown();
|
|
230
235
|
}, describedByFromValidation: true }))] })] })] }));
|
|
@@ -17,6 +17,7 @@ export interface IDateFilterFormContentProps {
|
|
|
17
17
|
withoutApply?: boolean;
|
|
18
18
|
enableEmptyDateValues?: boolean;
|
|
19
19
|
customRangeHint?: ReactNode;
|
|
20
|
+
onPeriodRangeValidityChange?: (isValid: boolean) => void;
|
|
20
21
|
activeForm: DateFilterRoute;
|
|
21
22
|
onBackNavigation: () => void;
|
|
22
23
|
onClose: () => void;
|
|
@@ -29,5 +30,5 @@ export interface IDateFilterFormContentProps {
|
|
|
29
30
|
*
|
|
30
31
|
* @internal
|
|
31
32
|
*/
|
|
32
|
-
export declare function DateFilterFormContent({ filterOptions, selectedFilterOption, onSelectedFilterOptionChange, dateFormat, weekStart, isTimeForAbsoluteRangeEnabled, isSecondsForAbsoluteRangeEnabled, isAbsoluteDateFilterGranularityEnabled, availableGranularities, absoluteAvailableGranularities, isMobile, withoutApply, enableEmptyDateValues, customRangeHint, activeForm, onBackNavigation, onClose, submitForm, errors, }: IDateFilterFormContentProps): import("react/jsx-runtime").JSX.Element;
|
|
33
|
+
export declare function DateFilterFormContent({ filterOptions, selectedFilterOption, onSelectedFilterOptionChange, dateFormat, weekStart, isTimeForAbsoluteRangeEnabled, isSecondsForAbsoluteRangeEnabled, isAbsoluteDateFilterGranularityEnabled, availableGranularities, absoluteAvailableGranularities, isMobile, withoutApply, enableEmptyDateValues, customRangeHint, onPeriodRangeValidityChange, activeForm, onBackNavigation, onClose, submitForm, errors, }: IDateFilterFormContentProps): import("react/jsx-runtime").JSX.Element;
|
|
33
34
|
//# sourceMappingURL=DateFilterFormContent.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DateFilterFormContent.d.ts","sourceRoot":"","sources":["../../../src/DateFilter/DateFilterBody/DateFilterFormContent.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAsB,KAAK,SAAS,
|
|
1
|
+
{"version":3,"file":"DateFilterFormContent.d.ts","sourceRoot":"","sources":["../../../src/DateFilter/DateFilterBody/DateFilterFormContent.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAsB,KAAK,SAAS,EAAuC,MAAM,OAAO,CAAC;AAKhG,OAAO,EACH,KAAK,qBAAqB,EAC1B,KAAK,SAAS,EAKjB,MAAM,qBAAqB,CAAC;AAU7B,OAAO,EACH,KAAK,gBAAgB,EACrB,KAAK,wBAAwB,EAC7B,KAAK,yBAAyB,EAGjC,MAAM,wBAAwB,CAAC;AAIhC,OAAO,EAAE,KAAK,eAAe,EAAE,MAAM,YAAY,CAAC;AAElD,MAAM,WAAW,2BAA2B;IACxC,aAAa,EAAE,wBAAwB,CAAC;IACxC,oBAAoB,EAAE,gBAAgB,CAAC;IACvC,4BAA4B,EAAE,CAAC,MAAM,EAAE,gBAAgB,KAAK,IAAI,CAAC;IAEjE,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,SAAS,CAAC;IACrB,6BAA6B,EAAE,OAAO,CAAC;IACvC,gCAAgC,CAAC,EAAE,OAAO,CAAC;IAC3C,sCAAsC,EAAE,OAAO,CAAC;IAChD,sBAAsB,EAAE,qBAAqB,EAAE,CAAC;IAChD,8BAA8B,EAAE,qBAAqB,EAAE,CAAC;IAExD,QAAQ,EAAE,OAAO,CAAC;IAClB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAChC,eAAe,CAAC,EAAE,SAAS,CAAC;IAC5B,2BAA2B,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;IAEzD,UAAU,EAAE,eAAe,CAAC;IAC5B,gBAAgB,EAAE,MAAM,IAAI,CAAC;IAC7B,OAAO,EAAE,MAAM,IAAI,CAAC;IAEpB,UAAU,EAAE,MAAM,IAAI,CAAC;IACvB,MAAM,CAAC,EAAE,yBAAyB,CAAC;CACtC;AAkBD;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,EAClC,aAAa,EACb,oBAAoB,EACpB,4BAA4B,EAC5B,UAAU,EACV,SAAS,EACT,6BAA6B,EAC7B,gCAAgC,EAChC,sCAAsC,EACtC,sBAAsB,EACtB,8BAA8B,EAC9B,QAAQ,EACR,YAAY,EACZ,qBAAqB,EACrB,eAAe,EACf,2BAA2B,EAC3B,UAAU,EACV,gBAAgB,EAChB,OAAO,EACP,UAAU,EACV,MAAM,GACT,EAAE,2BAA2B,2CA4I7B"}
|
|
@@ -6,18 +6,27 @@ import { useIntl } from "react-intl";
|
|
|
6
6
|
import { isAbsoluteDateFilterForm, isAllTimeDateFilterOption, isEmptyValuesDateFilterOption, isRelativeDateFilterForm, } from "@gooddata/sdk-model";
|
|
7
7
|
import { useId } from "@gooddata/sdk-ui-kit";
|
|
8
8
|
import { AbsoluteDateFilterForm } from "../AbsoluteDateFilterForm/AbsoluteDateFilterForm.js";
|
|
9
|
-
import {
|
|
9
|
+
import { createGranularityTabsKeyboardHandler, submitRelativeDateFilterForm, } from "../accessibility/keyboardNavigation.js";
|
|
10
10
|
import { DateFilterFormWrapper } from "../DateFilterFormWrapper/DateFilterFormWrapper.js";
|
|
11
11
|
import { EmptyValuesHandlingToggle } from "../EmptyValuesHandlingToggle/EmptyValuesHandlingToggle.js";
|
|
12
12
|
import { RelativeDateFilterForm } from "../RelativeDateFilterForm/RelativeDateFilterForm.js";
|
|
13
13
|
import { DateFilterFormNavigationWrapper } from "./DateFilterFormNavigationWrapper.js";
|
|
14
|
+
/**
|
|
15
|
+
* Builds the keydown handler bound to a granularity tabs container, shared by the absolute and relative
|
|
16
|
+
* form's wrapper `<div>`s below - the only two consumers, hence a local hook rather than a shared export.
|
|
17
|
+
*/
|
|
18
|
+
function useGranularityTabsKeydownHandler(tabGranularityRef, closeDropdown) {
|
|
19
|
+
return useCallback((event) => {
|
|
20
|
+
createGranularityTabsKeyboardHandler({ tabGranularityRef, closeDropdown })(event);
|
|
21
|
+
}, [tabGranularityRef, closeDropdown]);
|
|
22
|
+
}
|
|
14
23
|
/**
|
|
15
24
|
* Component that renders the form content (absolute or relative) for date filter.
|
|
16
25
|
* This component is purely presentational and doesn't manage any navigation state.
|
|
17
26
|
*
|
|
18
27
|
* @internal
|
|
19
28
|
*/
|
|
20
|
-
export function DateFilterFormContent({ filterOptions, selectedFilterOption, onSelectedFilterOptionChange, dateFormat, weekStart, isTimeForAbsoluteRangeEnabled, isSecondsForAbsoluteRangeEnabled, isAbsoluteDateFilterGranularityEnabled, availableGranularities, absoluteAvailableGranularities, isMobile, withoutApply, enableEmptyDateValues, customRangeHint, activeForm, onBackNavigation, onClose, submitForm, errors, }) {
|
|
29
|
+
export function DateFilterFormContent({ filterOptions, selectedFilterOption, onSelectedFilterOptionChange, dateFormat, weekStart, isTimeForAbsoluteRangeEnabled, isSecondsForAbsoluteRangeEnabled, isAbsoluteDateFilterGranularityEnabled, availableGranularities, absoluteAvailableGranularities, isMobile, withoutApply, enableEmptyDateValues, customRangeHint, onPeriodRangeValidityChange, activeForm, onBackNavigation, onClose, submitForm, errors, }) {
|
|
21
30
|
const showStaticForm = activeForm === "absoluteForm" && filterOptions.absoluteForm;
|
|
22
31
|
const showRelativeForm = activeForm === "relativeForm" && filterOptions.relativeForm && availableGranularities.length > 0;
|
|
23
32
|
const absoluteSelectedFilterOption = filterOptions.absoluteForm && isAbsoluteDateFilterForm(selectedFilterOption)
|
|
@@ -27,8 +36,8 @@ export function DateFilterFormContent({ filterOptions, selectedFilterOption, onS
|
|
|
27
36
|
? selectedFilterOption
|
|
28
37
|
: filterOptions.relativeForm;
|
|
29
38
|
const intl = useIntl();
|
|
30
|
-
const relativeDateFilterRef = useRef(null);
|
|
31
39
|
const tabGranularityRef = useRef(null);
|
|
40
|
+
const absoluteTabGranularityRef = useRef(null);
|
|
32
41
|
const relativeDateFilterId = useId();
|
|
33
42
|
const absoluteDateFilterId = useId();
|
|
34
43
|
const shouldRenderEmptyValuesHandling = !!enableEmptyDateValues &&
|
|
@@ -37,25 +46,19 @@ export function DateFilterFormContent({ filterOptions, selectedFilterOption, onS
|
|
|
37
46
|
selectedFilterOption.emptyValueHandling !== "only";
|
|
38
47
|
const effectiveEmptyValueHandling = selectedFilterOption.emptyValueHandling ?? "exclude";
|
|
39
48
|
const emptyValueHandlingToggleChecked = effectiveEmptyValueHandling === "include";
|
|
40
|
-
const handleRelativeDateFilterKeydown =
|
|
41
|
-
|
|
42
|
-
relativeDateFilterRef,
|
|
43
|
-
tabGranularityRef,
|
|
44
|
-
closeDropdown,
|
|
45
|
-
});
|
|
46
|
-
keyboardHandler(event);
|
|
47
|
-
}, [relativeDateFilterRef, tabGranularityRef]);
|
|
49
|
+
const handleRelativeDateFilterKeydown = useGranularityTabsKeydownHandler(tabGranularityRef, onClose);
|
|
50
|
+
const handleAbsoluteDateFilterKeydown = useGranularityTabsKeydownHandler(absoluteTabGranularityRef, onClose);
|
|
48
51
|
return (_jsxs("div", { className: "gd-date-filter-form-content", children: [showStaticForm ? (_jsx(DateFilterFormNavigationWrapper, { title: filterOptions.absoluteForm?.name
|
|
49
52
|
? filterOptions.absoluteForm.name
|
|
50
|
-
: intl.formatMessage({ id: "filters.staticPeriod" }), onBack: onBackNavigation, backLabel: intl.formatMessage({ id: "menu.back" }), isMobile: isMobile, children: _jsxs(DateFilterFormWrapper, { isMobile: isMobile, children: [_jsx(AbsoluteDateFilterForm, { dateFormat: dateFormat, onSelectedFilterOptionChange: onSelectedFilterOptionChange, selectedFilterOption: absoluteSelectedFilterOption, isMobile: isMobile, isTimeEnabled: isTimeForAbsoluteRangeEnabled, isSecondsEnabled: isSecondsForAbsoluteRangeEnabled, isGranularityEnabled: isAbsoluteDateFilterGranularityEnabled, availableGranularities: absoluteAvailableGranularities, accessibilityConfig: { id: absoluteDateFilterId }, weekStart: weekStart, submitForm: submitForm, withoutApply: withoutApply, customRangeHint: customRangeHint }), shouldRenderEmptyValuesHandling ? (_jsx(EmptyValuesHandlingToggle, { mode: "include", className: "gd-date-filter-empty-values-handling-toggle", checked: emptyValueHandlingToggleChecked, onChange: (checked) => {
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
53
|
+
: intl.formatMessage({ id: "filters.staticPeriod" }), onBack: onBackNavigation, backLabel: intl.formatMessage({ id: "menu.back" }), isMobile: isMobile, children: _jsx("div", { onKeyDown: handleAbsoluteDateFilterKeydown, children: _jsxs(DateFilterFormWrapper, { isMobile: isMobile, children: [_jsx(AbsoluteDateFilterForm, { dateFormat: dateFormat, onSelectedFilterOptionChange: onSelectedFilterOptionChange, selectedFilterOption: absoluteSelectedFilterOption, isMobile: isMobile, isTimeEnabled: isTimeForAbsoluteRangeEnabled, isSecondsEnabled: isSecondsForAbsoluteRangeEnabled, isGranularityEnabled: isAbsoluteDateFilterGranularityEnabled, availableGranularities: absoluteAvailableGranularities, accessibilityConfig: { id: absoluteDateFilterId }, weekStart: weekStart, submitForm: submitForm, withoutApply: withoutApply, customRangeHint: customRangeHint, onPeriodRangeValidityChange: onPeriodRangeValidityChange, granularityTabsRef: absoluteTabGranularityRef }), shouldRenderEmptyValuesHandling ? (_jsx(EmptyValuesHandlingToggle, { mode: "include", className: "gd-date-filter-empty-values-handling-toggle", checked: emptyValueHandlingToggleChecked, onChange: (checked) => {
|
|
54
|
+
const emptyValueHandling = checked ? "include" : undefined;
|
|
55
|
+
onSelectedFilterOptionChange({
|
|
56
|
+
...absoluteSelectedFilterOption,
|
|
57
|
+
emptyValueHandling,
|
|
58
|
+
});
|
|
59
|
+
} })) : null] }) }) })) : null, showRelativeForm ? (_jsx(DateFilterFormNavigationWrapper, { title: filterOptions.relativeForm?.name
|
|
57
60
|
? filterOptions.relativeForm.name
|
|
58
|
-
: intl.formatMessage({ id: "filters.floatingRange" }), onBack: onBackNavigation, backLabel: intl.formatMessage({ id: "menu.back" }), isMobile: isMobile, children: _jsx("div", {
|
|
61
|
+
: intl.formatMessage({ id: "filters.floatingRange" }), onBack: onBackNavigation, backLabel: intl.formatMessage({ id: "menu.back" }), isMobile: isMobile, children: _jsx("div", { onKeyDown: handleRelativeDateFilterKeydown, children: _jsxs(DateFilterFormWrapper, { isMobile: isMobile, children: [_jsx(RelativeDateFilterForm, { onSelectedFilterOptionChange: onSelectedFilterOptionChange, selectedFilterOption: relativeSelectedFilterOption, availableGranularities: availableGranularities, isMobile: isMobile, ref: tabGranularityRef, relativeDateFilterId: relativeDateFilterId, onKeyDown: (event) => submitRelativeDateFilterForm(event, isEmpty(errors), withoutApply ?? false, onClose, submitForm) }), shouldRenderEmptyValuesHandling ? (_jsx(EmptyValuesHandlingToggle, { mode: "include", className: "gd-date-filter-empty-values-handling-toggle", checked: emptyValueHandlingToggleChecked, onChange: (checked) => {
|
|
59
62
|
const emptyValueHandling = checked ? "include" : undefined;
|
|
60
63
|
onSelectedFilterOptionChange({
|
|
61
64
|
...relativeSelectedFilterOption,
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { type InputHTMLAttributes } from "react";
|
|
2
|
+
interface IAccessibleFieldInputProps extends InputHTMLAttributes<HTMLInputElement> {
|
|
3
|
+
"date-range"?: "start" | "end";
|
|
4
|
+
}
|
|
5
|
+
/**
|
|
6
|
+
* A drop-in replacement for the plain `<input>` rc-picker renders for each half of the date range,
|
|
7
|
+
* used only to layer on the accessibility attributes our a11y model needs - a label, an invalid
|
|
8
|
+
* state, and a description pointing at either a format hint or an error message. Typing, masking,
|
|
9
|
+
* and focus behavior all still belong to rc-picker; this component just decorates the props it's handed.
|
|
10
|
+
*
|
|
11
|
+
* @remarks
|
|
12
|
+
* rc-picker exposes two facts only this component can observe directly: whether the typed text failed to
|
|
13
|
+
* parse (as this input's own invalid state) and whether the field is currently blank (its own live displayed
|
|
14
|
+
* text, which updates on every keystroke including a clear). Both are reported upward, raw and unresolved, via
|
|
15
|
+
* an effect - the surrounding picker owns everything else needed to turn them into an error kind or message.
|
|
16
|
+
*/
|
|
17
|
+
export declare const AccessibleFieldInput: import("react").ForwardRefExoticComponent<IAccessibleFieldInputProps & import("react").RefAttributes<HTMLInputElement>>;
|
|
18
|
+
export {};
|
|
19
|
+
//# sourceMappingURL=AccessibleFieldInput.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AccessibleFieldInput.d.ts","sourceRoot":"","sources":["../../../src/DateFilter/PeriodRangePicker/AccessibleFieldInput.tsx"],"names":[],"mappings":"AAEA,OAAO,EACH,KAAK,mBAAmB,EAM3B,MAAM,OAAO,CAAC;AAMf,UAAU,0BAA2B,SAAQ,mBAAmB,CAAC,gBAAgB,CAAC;IAC9E,YAAY,CAAC,EAAE,OAAO,GAAG,KAAK,CAAC;CAClC;AAED;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,oBAAoB,yHAgG/B,CAAC"}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
// (C) 2026 GoodData Corporation
|
|
3
|
+
import { forwardRef, useCallback, useContext, useEffect, } from "react";
|
|
4
|
+
import { isArrowDownKey, isArrowKey } from "@gooddata/sdk-ui-kit";
|
|
5
|
+
import { PeriodRangeAccessibilityContext } from "./periodRangePickerAccessibility.js";
|
|
6
|
+
/**
|
|
7
|
+
* A drop-in replacement for the plain `<input>` rc-picker renders for each half of the date range,
|
|
8
|
+
* used only to layer on the accessibility attributes our a11y model needs - a label, an invalid
|
|
9
|
+
* state, and a description pointing at either a format hint or an error message. Typing, masking,
|
|
10
|
+
* and focus behavior all still belong to rc-picker; this component just decorates the props it's handed.
|
|
11
|
+
*
|
|
12
|
+
* @remarks
|
|
13
|
+
* rc-picker exposes two facts only this component can observe directly: whether the typed text failed to
|
|
14
|
+
* parse (as this input's own invalid state) and whether the field is currently blank (its own live displayed
|
|
15
|
+
* text, which updates on every keystroke including a clear). Both are reported upward, raw and unresolved, via
|
|
16
|
+
* an effect - the surrounding picker owns everything else needed to turn them into an error kind or message.
|
|
17
|
+
*/
|
|
18
|
+
export const AccessibleFieldInput = forwardRef((props, ref) => {
|
|
19
|
+
const { "date-range": side, "aria-invalid": rcPickerInvalid, onKeyDown, ...restProps } = props;
|
|
20
|
+
const accessibility = useContext(PeriodRangeAccessibilityContext);
|
|
21
|
+
const field = side ? accessibility?.[side] : undefined;
|
|
22
|
+
const isCalendarOpen = accessibility?.isCalendarOpen ?? false;
|
|
23
|
+
const onRequestOpen = accessibility?.onRequestOpen;
|
|
24
|
+
const enterCommitRef = accessibility?.enterCommitRef;
|
|
25
|
+
const onEnterCommit = accessibility?.onEnterCommit;
|
|
26
|
+
const ignoreEnter = accessibility?.ignoreEnter ?? false;
|
|
27
|
+
const hasParseError = rcPickerInvalid === true;
|
|
28
|
+
const isBlank = !props.value;
|
|
29
|
+
useEffect(() => {
|
|
30
|
+
if (side) {
|
|
31
|
+
accessibility?.onFieldStateChange(side, { hasParseError, isBlank });
|
|
32
|
+
}
|
|
33
|
+
}, [accessibility, side, hasParseError, isBlank]);
|
|
34
|
+
// rc-picker's own Enter/Escape field-confirmation logic (forwarded as onKeyDown) must still run first;
|
|
35
|
+
// stopping propagation afterwards for arrow/Home/End keys - without preventDefault - lets the browser move
|
|
36
|
+
// the caret normally instead of DateFilterBody/DateFilterCore treating it as back/roving-focus navigation.
|
|
37
|
+
const handleKeyDown = useCallback((e) => {
|
|
38
|
+
// rc-picker confirms the field inside the handler forwarded below (its `onSharedKeyDown` calls
|
|
39
|
+
// `onSubmit()`), but both the resulting `onChange` (when the round completes) and its own
|
|
40
|
+
// deactivation `onBlur` (rc-picker's `useFocusEvents`, which defers via a microtask so that
|
|
41
|
+
// tabbing between this picker's own two fields isn't briefly seen as blurring the whole thing)
|
|
42
|
+
// land one microtask later, not synchronously within this call. The flag has to outlive that
|
|
43
|
+
// microtask too, so the reset below is deferred with `queueMicrotask` rather than done
|
|
44
|
+
// immediately - an immediate reset would already have flipped back to false by the time either
|
|
45
|
+
// callback runs, defeating the guards in handleChange/handleFieldBlur. `finally` still matters
|
|
46
|
+
// for scheduling the reset even if `onKeyDown`/`onEnterCommit` throws.
|
|
47
|
+
const isEnter = e.key === "Enter";
|
|
48
|
+
if (isEnter && ignoreEnter) {
|
|
49
|
+
// In ALL_AT_ONCE mode the caret has to stay where the user is typing, and
|
|
50
|
+
// blur is the only commit point.
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
if (isEnter && enterCommitRef) {
|
|
54
|
+
enterCommitRef.current = true;
|
|
55
|
+
}
|
|
56
|
+
try {
|
|
57
|
+
onKeyDown?.(e);
|
|
58
|
+
if (isEnter) {
|
|
59
|
+
onEnterCommit?.();
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
finally {
|
|
63
|
+
if (isEnter && enterCommitRef) {
|
|
64
|
+
queueMicrotask(() => {
|
|
65
|
+
enterCommitRef.current = false;
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
if (isArrowKey(e) || e.key === "Home" || e.key === "End") {
|
|
70
|
+
e.stopPropagation();
|
|
71
|
+
}
|
|
72
|
+
// rc-picker already closes its own calendar on Escape internally; without this, the event keeps
|
|
73
|
+
// bubbling up to DateFilterFormContent's outer keydown handler, whose `makeLinearKeyboardNavigation`
|
|
74
|
+
// maps only Escape to closing the whole dropdown. The Tab branch below is not mirroring that
|
|
75
|
+
// mapping - it's a deliberate extra guard so Tab-ing between the two fields, which the browser
|
|
76
|
+
// handles natively, never also reaches that outer handler's own key routing.
|
|
77
|
+
if (isCalendarOpen && (e.key === "Escape" || e.key === "Tab")) {
|
|
78
|
+
e.stopPropagation();
|
|
79
|
+
}
|
|
80
|
+
// rc-picker silently swallows every "open" request while the field is being typed into, so opening
|
|
81
|
+
// the calendar via keyboard has to be detected explicitly here rather than relying on rc-picker's
|
|
82
|
+
// own onOpenChange. Alt+ArrowDown rather than plain ArrowDown: it matches the ARIA combobox pattern's
|
|
83
|
+
// "open the popup without moving focus" binding, and leaves bare ArrowUp/ArrowDown free to move
|
|
84
|
+
// the caret inside the field, which is what the stopPropagation above is there to preserve.
|
|
85
|
+
if (!isCalendarOpen && e.altKey && isArrowDownKey(e)) {
|
|
86
|
+
onRequestOpen?.();
|
|
87
|
+
}
|
|
88
|
+
}, [onKeyDown, isCalendarOpen, onRequestOpen, enterCommitRef, onEnterCommit, ignoreEnter]);
|
|
89
|
+
return (_jsx("input", { ref: ref, ...restProps, "date-range": side, onKeyDown: handleKeyDown, "aria-label": field?.ariaLabel, "aria-invalid": field ? hasParseError || field.errorKind !== undefined : rcPickerInvalid, "aria-describedby": field ? (field.errorKind === undefined ? field.hintId : field.errorId) : undefined }));
|
|
90
|
+
});
|
|
91
|
+
AccessibleFieldInput.displayName = "AccessibleFieldInput";
|
|
@@ -1,5 +1,20 @@
|
|
|
1
|
-
import { type
|
|
1
|
+
import { type PeriodRangeSide } from "./periodRangePickerAccessibility.js";
|
|
2
2
|
import { type IPeriodRange, type IPeriodRangePickerProps, type PeriodRangePickerGranularity } from "./types.js";
|
|
3
|
+
export declare const DATE_FNS_PICKER_FORMATS: {
|
|
4
|
+
readonly fieldDateFormat: "yyyy-MM-dd";
|
|
5
|
+
readonly fieldWeekFormat: "Y-ww";
|
|
6
|
+
readonly fieldMonthFormat: "yyyy-MM";
|
|
7
|
+
readonly fieldQuarterFormat: "yyyy-QQQ";
|
|
8
|
+
readonly fieldYearFormat: "yyyy";
|
|
9
|
+
readonly fieldDateTimeFormat: "yyyy-MM-dd HH:mm";
|
|
10
|
+
readonly fieldTimeFormat: "HH:mm";
|
|
11
|
+
readonly yearFormat: "yyyy";
|
|
12
|
+
readonly cellYearFormat: "yyyy";
|
|
13
|
+
readonly cellQuarterFormat: "QQQ";
|
|
14
|
+
readonly cellDateFormat: "d";
|
|
15
|
+
readonly dayFormat: "d";
|
|
16
|
+
readonly cellMeridiemFormat: "a";
|
|
17
|
+
};
|
|
3
18
|
/**
|
|
4
19
|
* Resolves the picker's raw selected [start, end] into the exact day-level range this component reports.
|
|
5
20
|
*
|
|
@@ -9,7 +24,12 @@ import { type IPeriodRange, type IPeriodRangePickerProps, type PeriodRangePicker
|
|
|
9
24
|
* within the period" for either bound, so a start-of-unit anchor works as input either way. Day needs no expansion,
|
|
10
25
|
* and `resolvePeriodBoundaries` handles it as a no-op period (start/end of day), so it's routed through uniformly.
|
|
11
26
|
*/
|
|
12
|
-
export declare function resolveSelectedRange(granularity: PeriodRangePickerGranularity, start:
|
|
27
|
+
export declare function resolveSelectedRange(granularity: PeriodRangePickerGranularity, start: Date, end: Date, weekStart: NonNullable<IPeriodRangePickerProps["weekStart"]>): IPeriodRange;
|
|
28
|
+
/**
|
|
29
|
+
* Single-sided counterpart to {@link resolveSelectedRange}, used by the blur handler which commits
|
|
30
|
+
* one field at a time.
|
|
31
|
+
*/
|
|
32
|
+
export declare function resolveSelectedBoundary(granularity: PeriodRangePickerGranularity, date: Date, side: PeriodRangeSide, weekStart: NonNullable<IPeriodRangePickerProps["weekStart"]>): string;
|
|
13
33
|
/**
|
|
14
34
|
* A grid picker for selecting a Week/Month/Quarter/Year period range. Renders the rc-picker panel matching
|
|
15
35
|
* {@link IPeriodRangePickerProps.granularity} and reports the resolved day-level range via `onRangeChange`.
|
|
@@ -18,5 +38,5 @@ export declare function resolveSelectedRange(granularity: PeriodRangePickerGranu
|
|
|
18
38
|
* Loaded lazily by `PeriodRangePicker`, which is the public entry point - this module has to stay out of the
|
|
19
39
|
* package's eager module graph, see the note in PeriodRangePicker.tsx. Import it directly only from tests.
|
|
20
40
|
*/
|
|
21
|
-
export declare function PeriodRangePickerImpl({ granularity, range, onRangeChange, isMobile, weekStart, withoutApply, submitForm, }: IPeriodRangePickerProps): import("react/jsx-runtime").JSX.Element;
|
|
41
|
+
export declare function PeriodRangePickerImpl({ granularity, range, onRangeChange, isMobile, weekStart, withoutApply, submitForm, dateFormat, customRangeHint, onValidityChange, }: IPeriodRangePickerProps): import("react/jsx-runtime").JSX.Element;
|
|
22
42
|
//# sourceMappingURL=PeriodRangePickerImpl.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PeriodRangePickerImpl.d.ts","sourceRoot":"","sources":["../../../src/DateFilter/PeriodRangePicker/PeriodRangePickerImpl.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"PeriodRangePickerImpl.d.ts","sourceRoot":"","sources":["../../../src/DateFilter/PeriodRangePicker/PeriodRangePickerImpl.tsx"],"names":[],"mappings":"AAgDA,OAAO,EAKH,KAAK,eAAe,EAGvB,MAAM,qCAAqC,CAAC;AAC7C,OAAO,EACH,KAAK,YAAY,EACjB,KAAK,uBAAuB,EAC5B,KAAK,4BAA4B,EACpC,MAAM,YAAY,CAAC;AAgBpB,eAAO,MAAM,uBAAuB;aAChC,eAAe,EAAE,YAAY;aAI7B,eAAe,EAAE,MAAM;aACvB,gBAAgB,EAAE,SAAS;aAC3B,kBAAkB,EAAE,UAAU;aAC9B,eAAe,EAAE,MAAM;aAEvB,mBAAmB,EAAE,kBAAkB;aACvC,eAAe,EAAE,OAAO;aACxB,UAAU,EAAE,MAAM;aAClB,cAAc,EAAE,MAAM;aACtB,iBAAiB,EAAE,KAAK;aACxB,cAAc,EAAE,GAAG;aACnB,SAAS,EAAE,GAAG;aACd,kBAAkB,EAAE,GAAG;CACjB,CAAC;AAkHX;;;;;;;;GAQG;AACH,wBAAgB,oBAAoB,CAChC,WAAW,EAAE,4BAA4B,EACzC,KAAK,EAAE,IAAI,EACX,GAAG,EAAE,IAAI,EACT,SAAS,EAAE,WAAW,CAAC,uBAAuB,CAAC,WAAW,CAAC,CAAC,GAC7D,YAAY,CAOd;AAED;;;GAGG;AACH,wBAAgB,uBAAuB,CACnC,WAAW,EAAE,4BAA4B,EACzC,IAAI,EAAE,IAAI,EACV,IAAI,EAAE,eAAe,EACrB,SAAS,EAAE,WAAW,CAAC,uBAAuB,CAAC,WAAW,CAAC,CAAC,GAC7D,MAAM,CAER;AAED;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CAAC,EAClC,WAAW,EACX,KAAK,EACL,aAAa,EACb,QAAQ,EACR,SAAoB,EACpB,YAAoB,EACpB,UAAU,EACV,UAAU,EACV,eAAe,EACf,gBAAgB,GACnB,EAAE,uBAAuB,2CAiXzB"}
|