From 2cad21afb1aa34e829deca2e3e714bfdcc74b867 Mon Sep 17 00:00:00 2001
From: Diana Petcheva
Date: Tue, 2 Sep 2025 15:10:53 +0300
Subject: [PATCH 1/2] docs(ui5-dynamic-date-range): add custom option sample
---
packages/main/src/bundle.esm.ts | 1 +
.../dynamic-date-range-options/TodayFromTo.ts | 96 +++++++++++++++++++
.../TodayFromToTemplate.tsx | 55 +++++++++++
.../main/test/pages/DynamicDateRange.html | 2 +-
.../main/DynamicDateRange.mdx | 6 +-
.../CustomOption/CustomOption.md | 4 +
.../CustomOption/TodayFromTo.ts | 96 +++++++++++++++++++
.../CustomOption/TodayFromToTemplate.tsx | 55 +++++++++++
.../DynamicDateRange/CustomOption/main.js | 6 ++
.../DynamicDateRange/CustomOption/sample.html | 22 +++++
10 files changed, 341 insertions(+), 2 deletions(-)
create mode 100644 packages/main/src/dynamic-date-range-options/TodayFromTo.ts
create mode 100644 packages/main/src/dynamic-date-range-options/TodayFromToTemplate.tsx
create mode 100644 packages/website/docs/_samples/main/DynamicDateRange/CustomOption/CustomOption.md
create mode 100644 packages/website/docs/_samples/main/DynamicDateRange/CustomOption/TodayFromTo.ts
create mode 100644 packages/website/docs/_samples/main/DynamicDateRange/CustomOption/TodayFromToTemplate.tsx
create mode 100644 packages/website/docs/_samples/main/DynamicDateRange/CustomOption/main.js
create mode 100644 packages/website/docs/_samples/main/DynamicDateRange/CustomOption/sample.html
diff --git a/packages/main/src/bundle.esm.ts b/packages/main/src/bundle.esm.ts
index 7b3688bd8d82..cda14faafb94 100644
--- a/packages/main/src/bundle.esm.ts
+++ b/packages/main/src/bundle.esm.ts
@@ -52,6 +52,7 @@ import DateTimePicker from "./DateTimePicker.js";
import Dialog from "./Dialog.js";
import DynamicDateRange from "./DynamicDateRange.js";
import Today from "./dynamic-date-range-options/Today.js";
+import TodayFromTo from "./dynamic-date-range-options/TodayFromTo.js";
import Yesterday from "./dynamic-date-range-options/Yesterday.js";
import Tomorrow from "./dynamic-date-range-options/Tomorrow.js";
import SingleDate from "./dynamic-date-range-options/SingleDate.js";
diff --git a/packages/main/src/dynamic-date-range-options/TodayFromTo.ts b/packages/main/src/dynamic-date-range-options/TodayFromTo.ts
new file mode 100644
index 000000000000..a0cbc5175794
--- /dev/null
+++ b/packages/main/src/dynamic-date-range-options/TodayFromTo.ts
@@ -0,0 +1,96 @@
+import DateFormat from "@ui5/webcomponents-localization/dist/DateFormat.js";
+import UI5Date from "@ui5/webcomponents-localization/dist/dates/UI5Date.js";
+import type { DynamicDateRangeValue, IDynamicDateRangeOption } from "../DynamicDateRange.js";
+import DynamicDateRange from "../DynamicDateRange.js";
+import TodayFromToTemplate from "./TodayFromToTemplate.js";
+import type { JsxTemplate } from "@ui5/webcomponents-base/dist/index.js";
+
+/**
+ * @class
+ * @constructor
+ * @public
+ */
+class TodayFromToDays implements IDynamicDateRangeOption {
+ template: JsxTemplate;
+
+ constructor() {
+ this.template = TodayFromToTemplate;
+ }
+
+ parse(value: string): DynamicDateRangeValue {
+ const match = value.match(/Today -(\d+)\/\+(\d+) days/);
+
+ if (match) {
+ const x = parseInt(match[1]);
+ const y = parseInt(match[2]);
+ return { operator: this.operator, values: [x, y] };
+ }
+
+ return { operator: this.operator, values: [0, 0] };
+ }
+
+ format(value: DynamicDateRangeValue) {
+ if (!value.values || value.values.length !== 2) {
+ value.values = [0, 0];
+ }
+
+ // Format values in a date range
+ if (value.values[0] instanceof Date) {
+ const dateValues = value.values as Array;
+ return this.getFormat().format(dateValues);
+ }
+
+ // Format values in the pattern "Today -X/+Y days"
+ const x = value.values[0];
+ const y = value.values[1] as number;
+
+ return `Today -${x}/+${y} days`;
+ }
+
+ toDates(value: DynamicDateRangeValue): Array {
+ if (!value.values || value.values.length !== 2) {
+ return [];
+ }
+ const x = value.values[0] as number;
+ const y = value.values[1] as number;
+ const today = UI5Date.getInstance();
+
+ const startDate = x ? UI5Date.getInstance(today.getFullYear(), today.getMonth(), today.getDate() - x) : UI5Date.getInstance();
+ const endDate = y ? UI5Date.getInstance(today.getFullYear(), today.getMonth(), today.getDate() + y) : UI5Date.getInstance();
+
+ startDate?.setHours(0, 0, 0, 0);
+ endDate?.setHours(23, 59, 59, 999);
+
+ return [startDate, endDate];
+ }
+
+ isValidString(value: string): boolean {
+ const pattern = this.text.replace(/[.*+?^${}()|[\]\\/-]/g, "\\$&").replace("X", "\\d+").replace("Y", "\\d+");
+ const regex = new RegExp(`^${pattern}$`, "i");
+ return regex.test(value);
+ }
+
+ get text() {
+ return "Today -X/+Y days";
+ }
+
+ get operator() {
+ return "TODAYFROMTO";
+ }
+
+ get icon() {
+ return "check-availability";
+ }
+
+ getFormat(): DateFormat {
+ return DateFormat.getDateInstance({
+ strictParsing: true,
+ interval: true,
+ intervalDelimiter: " - ",
+ });
+ }
+}
+
+DynamicDateRange.register("TODAYFROMTO", TodayFromToDays);
+
+export default TodayFromToDays;
diff --git a/packages/main/src/dynamic-date-range-options/TodayFromToTemplate.tsx b/packages/main/src/dynamic-date-range-options/TodayFromToTemplate.tsx
new file mode 100644
index 000000000000..5feb2f6947fe
--- /dev/null
+++ b/packages/main/src/dynamic-date-range-options/TodayFromToTemplate.tsx
@@ -0,0 +1,55 @@
+import type DynamicDateRange from "../DynamicDateRange.js";
+import Label from "../Label.js";
+import StepInput from "../StepInput.js";
+
+export default function TodayFromToTemplate(this: DynamicDateRange) {
+ const currentValues = this.currentValue?.values;
+
+ const xValue = currentValues ? currentValues[0] as number : 0;
+ const yValue = currentValues ? currentValues[1] as number : 0;
+
+ const handleNumberChange = (e: CustomEvent) => {
+ const target = e.target as StepInput;
+ const input = target.id;
+ const newValue = Number(target.value);
+
+ // Get current values, defaulting to existing values or 0
+ let newXValue = xValue;
+ let newYValue = yValue;
+
+ // Update the appropriate value based on which input changed
+ if (input === "x-input") {
+ newXValue = newValue;
+ } else if (input === "y-input") {
+ newYValue = newValue;
+ }
+
+ // Update currentValue with both values
+ this.currentValue = {
+ operator: "TODAYFROMTO",
+ values: [newXValue, newYValue],
+ };
+ };
+ return (
+
+
+
+
+
+
+
+
+ );
+}
diff --git a/packages/main/test/pages/DynamicDateRange.html b/packages/main/test/pages/DynamicDateRange.html
index 91bb340c456c..7f11a5945fa6 100644
--- a/packages/main/test/pages/DynamicDateRange.html
+++ b/packages/main/test/pages/DynamicDateRange.html
@@ -26,7 +26,7 @@ Basic Options
diff --git a/packages/website/docs/_components_pages/main/DynamicDateRange.mdx b/packages/website/docs/_components_pages/main/DynamicDateRange.mdx
index 338287cdc0e5..3a22f3619edc 100644
--- a/packages/website/docs/_components_pages/main/DynamicDateRange.mdx
+++ b/packages/website/docs/_components_pages/main/DynamicDateRange.mdx
@@ -3,6 +3,7 @@ sidebar_class_name: newComponentBadge
---
import Basic from "../../_samples/main/DynamicDateRange/Basic/Basic.md";
+import DynamicDateRangeCustomSample from "../../_samples/main/DynamicDateRange/CustomOption/CustomOption.md";
import DynamicDateRangeValueSample from "../../_samples/main/DynamicDateRange/DynamicDateRangeValueSample/DynamicDateRangeValueSample.md";
<%COMPONENT_OVERVIEW%>
@@ -15,4 +16,7 @@ import DynamicDateRangeValueSample from "../../_samples/main/DynamicDateRange/Dy
## More Samples
### DynamicDateRangeValueSample
-
\ No newline at end of file
+
+
+### CustomOption
+
\ No newline at end of file
diff --git a/packages/website/docs/_samples/main/DynamicDateRange/CustomOption/CustomOption.md b/packages/website/docs/_samples/main/DynamicDateRange/CustomOption/CustomOption.md
new file mode 100644
index 000000000000..17798ecc59ab
--- /dev/null
+++ b/packages/website/docs/_samples/main/DynamicDateRange/CustomOption/CustomOption.md
@@ -0,0 +1,4 @@
+import html from '!!raw-loader!./sample.html';
+import js from '!!raw-loader!./main.js';
+
+
diff --git a/packages/website/docs/_samples/main/DynamicDateRange/CustomOption/TodayFromTo.ts b/packages/website/docs/_samples/main/DynamicDateRange/CustomOption/TodayFromTo.ts
new file mode 100644
index 000000000000..669244a75363
--- /dev/null
+++ b/packages/website/docs/_samples/main/DynamicDateRange/CustomOption/TodayFromTo.ts
@@ -0,0 +1,96 @@
+import DateFormat from "@ui5/webcomponents-localization/dist/DateFormat.js";
+import UI5Date from "@ui5/webcomponents-localization/dist/dates/UI5Date.js";
+import type { DynamicDateRangeValue, IDynamicDateRangeOption } from "@ui5/webcomponents/dist/DynamicDateRange.js";
+import DynamicDateRange from "@ui5/webcomponents/dist/DynamicDateRange.js";
+import TodayFromToTemplate from "./TodayFromToTemplate.js";
+import type { JsxTemplate } from "@ui5/webcomponents-base/dist/index.js";
+
+/**
+ * @class
+ * @constructor
+ * @public
+ */
+class TodayFromToDays implements IDynamicDateRangeOption {
+ template: JsxTemplate;
+
+ constructor() {
+ this.template = TodayFromToTemplate;
+ }
+
+ parse(value: string): DynamicDateRangeValue {
+ const match = value.match(/Today -(\d+)\/\+(\d+) days/);
+
+ if (match) {
+ const x = parseInt(match[1]);
+ const y = parseInt(match[2]);
+ return { operator: this.operator, values: [x, y] };
+ }
+
+ return { operator: this.operator, values: [0, 0] };
+ }
+
+ format(value: DynamicDateRangeValue) {
+ if (!value.values || value.values.length !== 2) {
+ value.values = [0, 0];
+ }
+
+ // Format values in a date range
+ if (value.values[0] instanceof Date) {
+ const dateValues = value.values as Array;
+ return this.getFormat().format(dateValues);
+ }
+
+ // Format values in the pattern "Today -X/+Y days"
+ const x = value.values[0];
+ const y = value.values[1] as number;
+
+ return `Today -${x}/+${y} days`;
+ }
+
+ toDates(value: DynamicDateRangeValue): Array {
+ if (!value.values || value.values.length !== 2) {
+ return [];
+ }
+ const x = value.values[0] as number;
+ const y = value.values[1] as number;
+ const today = UI5Date.getInstance();
+
+ const startDate = x ? UI5Date.getInstance(today.getFullYear(), today.getMonth(), today.getDate() - x) : UI5Date.getInstance();
+ const endDate = y ? UI5Date.getInstance(today.getFullYear(), today.getMonth(), today.getDate() + y) : UI5Date.getInstance();
+
+ startDate?.setHours(0, 0, 0, 0);
+ endDate?.setHours(23, 59, 59, 999);
+
+ return [startDate, endDate];
+ }
+
+ isValidString(value: string): boolean {
+ const pattern = this.text.replace(/[.*+?^${}()|[\]\\/-]/g, "\\$&").replace("X", "\\d+").replace("Y", "\\d+");
+ const regex = new RegExp(`^${pattern}$`, "i");
+ return regex.test(value);
+ }
+
+ get text() {
+ return "Today -X/+Y days";
+ }
+
+ get operator() {
+ return "TODAYFROMTO";
+ }
+
+ get icon() {
+ return "check-availability";
+ }
+
+ getFormat(): DateFormat {
+ return DateFormat.getDateInstance({
+ strictParsing: true,
+ interval: true,
+ intervalDelimiter: " - ",
+ });
+ }
+}
+
+DynamicDateRange.register("TODAYFROMTO", TodayFromToDays);
+
+export default TodayFromToDays;
diff --git a/packages/website/docs/_samples/main/DynamicDateRange/CustomOption/TodayFromToTemplate.tsx b/packages/website/docs/_samples/main/DynamicDateRange/CustomOption/TodayFromToTemplate.tsx
new file mode 100644
index 000000000000..914a2e0d5956
--- /dev/null
+++ b/packages/website/docs/_samples/main/DynamicDateRange/CustomOption/TodayFromToTemplate.tsx
@@ -0,0 +1,55 @@
+import type DynamicDateRange from "@ui5/webcomponents/dist/DynamicDateRange.js";
+import Label from "@ui5/webcomponents/dist/Label.js";
+import StepInput from "@ui5/webcomponents/dist/StepInput.js";
+
+export default function TodayFromToTemplate(this: DynamicDateRange) {
+ const currentValues = this.currentValue?.values;
+
+ const xValue = currentValues ? currentValues[0] as number : 0;
+ const yValue = currentValues ? currentValues[1] as number : 0;
+
+ const handleNumberChange = (e: CustomEvent) => {
+ const target = e.target as StepInput;
+ const input = target.id;
+ const newValue = Number(target.value);
+
+ // Get current values, defaulting to existing values or 0
+ let newXValue = xValue;
+ let newYValue = yValue;
+
+ // Update the appropriate value based on which input changed
+ if (input === "x-input") {
+ newXValue = newValue;
+ } else if (input === "y-input") {
+ newYValue = newValue;
+ }
+
+ // Update currentValue with both values
+ this.currentValue = {
+ operator: "TODAYFROMTO",
+ values: [newXValue, newYValue],
+ };
+ };
+ return (
+
+
+
+
+
+
+
+
+ );
+}
diff --git a/packages/website/docs/_samples/main/DynamicDateRange/CustomOption/main.js b/packages/website/docs/_samples/main/DynamicDateRange/CustomOption/main.js
new file mode 100644
index 000000000000..a1cd6e0f45d5
--- /dev/null
+++ b/packages/website/docs/_samples/main/DynamicDateRange/CustomOption/main.js
@@ -0,0 +1,6 @@
+import "@ui5/webcomponents/dist/DynamicDateRange.js";
+import "@ui5/webcomponents/dist/dynamic-date-range-options/Today.js";
+import "@ui5/webcomponents/dist/dynamic-date-range-options/SingleDate.js";
+import "@ui5/webcomponents/dist/dynamic-date-range-options/DateRange.js";
+import "./TodayFromTo.js";
+import "./TodayFromToTemplate.tsx";
\ No newline at end of file
diff --git a/packages/website/docs/_samples/main/DynamicDateRange/CustomOption/sample.html b/packages/website/docs/_samples/main/DynamicDateRange/CustomOption/sample.html
new file mode 100644
index 000000000000..e0597d307c86
--- /dev/null
+++ b/packages/website/docs/_samples/main/DynamicDateRange/CustomOption/sample.html
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+
+ Dynamic Date Range Sample
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
From 30bbbd25a15e6124e9f55d2f62889667e68fd186 Mon Sep 17 00:00:00 2001
From: Diana Petcheva
Date: Tue, 2 Sep 2025 17:15:45 +0300
Subject: [PATCH 2/2] docs: correct option name
---
.../website/docs/_components_pages/main/DynamicDateRange.mdx | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/packages/website/docs/_components_pages/main/DynamicDateRange.mdx b/packages/website/docs/_components_pages/main/DynamicDateRange.mdx
index 3a22f3619edc..99e14bdff5a1 100644
--- a/packages/website/docs/_components_pages/main/DynamicDateRange.mdx
+++ b/packages/website/docs/_components_pages/main/DynamicDateRange.mdx
@@ -3,7 +3,7 @@ sidebar_class_name: newComponentBadge
---
import Basic from "../../_samples/main/DynamicDateRange/Basic/Basic.md";
-import DynamicDateRangeCustomSample from "../../_samples/main/DynamicDateRange/CustomOption/CustomOption.md";
+import CustomOption from "../../_samples/main/DynamicDateRange/CustomOption/CustomOption.md";
import DynamicDateRangeValueSample from "../../_samples/main/DynamicDateRange/DynamicDateRangeValueSample/DynamicDateRangeValueSample.md";
<%COMPONENT_OVERVIEW%>