diff --git a/packages/pluggableWidgets/date-time-picker-web/.eslintrc.js b/packages/pluggableWidgets/date-time-picker-web/.eslintrc.js
new file mode 100644
index 0000000000..a81cc74f08
--- /dev/null
+++ b/packages/pluggableWidgets/date-time-picker-web/.eslintrc.js
@@ -0,0 +1,5 @@
+const base = require("@mendix/pluggable-widgets-tools/configs/eslint.ts.base.json");
+
+module.exports = {
+ ...base
+};
diff --git a/packages/pluggableWidgets/date-time-picker-web/.gitattributes b/packages/pluggableWidgets/date-time-picker-web/.gitattributes
new file mode 100644
index 0000000000..ed8ea8651d
--- /dev/null
+++ b/packages/pluggableWidgets/date-time-picker-web/.gitattributes
@@ -0,0 +1,21 @@
+# Set the default behavior, in case people don't have core.autocrlf set.
+* text=auto
+
+# Explicitly declare text files you want to always be normalized and converted
+# to native line endings on checkout.
+*.ts text eol=lf
+*.tsx text eol=lf
+*.js text eol=lf
+*.jsx text eol=lf
+*.css text eol=lf
+*.scss text eol=lf
+*.json text eol=lf
+*.xml text eol=lf
+*.md text eol=lf
+*.gitattributes eol=lf
+*.gitignore eol=lf
+
+# Denote all files that are truly binary and should not be modified.
+*.png binary
+*.jpg binary
+*.gif binary
diff --git a/packages/pluggableWidgets/date-time-picker-web/.gitignore b/packages/pluggableWidgets/date-time-picker-web/.gitignore
new file mode 100644
index 0000000000..6721739184
--- /dev/null
+++ b/packages/pluggableWidgets/date-time-picker-web/.gitignore
@@ -0,0 +1,20 @@
+tests/testProject/
+.DS_Store
+.idea
+.vscode
+dist
+node_modules
+.env
+*.log
+*.bak
+*.launch
+mxproject
+coverage
+
+**/results
+mendixProject
+**/e2e/diffs
+**/screenshot
+**/screenshot-results
+**/tests/testProject
+**/artifacts
diff --git a/packages/pluggableWidgets/date-time-picker-web/.prettierignore b/packages/pluggableWidgets/date-time-picker-web/.prettierignore
new file mode 100644
index 0000000000..316da987ac
--- /dev/null
+++ b/packages/pluggableWidgets/date-time-picker-web/.prettierignore
@@ -0,0 +1 @@
+tests/testProject/
diff --git a/packages/pluggableWidgets/date-time-picker-web/.prettierrc.js b/packages/pluggableWidgets/date-time-picker-web/.prettierrc.js
new file mode 100644
index 0000000000..0892704ab0
--- /dev/null
+++ b/packages/pluggableWidgets/date-time-picker-web/.prettierrc.js
@@ -0,0 +1 @@
+module.exports = require("@mendix/prettier-config-web-widgets");
diff --git a/packages/pluggableWidgets/date-time-picker-web/LICENSE b/packages/pluggableWidgets/date-time-picker-web/LICENSE
new file mode 100644
index 0000000000..035fced0d9
--- /dev/null
+++ b/packages/pluggableWidgets/date-time-picker-web/LICENSE
@@ -0,0 +1,15 @@
+The Apache License v2.0
+
+Copyright © Mendix Technology BV 2022. All rights reserved.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
diff --git a/packages/pluggableWidgets/date-time-picker-web/README.md b/packages/pluggableWidgets/date-time-picker-web/README.md
new file mode 100644
index 0000000000..765710f775
--- /dev/null
+++ b/packages/pluggableWidgets/date-time-picker-web/README.md
@@ -0,0 +1,4 @@
+
+
+Please see [Date Time Picker](https://docs.mendix.com/appstore/widgets/combobox) in the Mendix documentation for
+details.
diff --git a/packages/pluggableWidgets/date-time-picker-web/package.json b/packages/pluggableWidgets/date-time-picker-web/package.json
new file mode 100644
index 0000000000..5236da9141
--- /dev/null
+++ b/packages/pluggableWidgets/date-time-picker-web/package.json
@@ -0,0 +1,60 @@
+{
+ "name": "@mendix/date-time-picker-web",
+ "widgetName": "DateTimePicker",
+ "version": "1.0.0",
+ "description": "Date, time and range picker widget",
+ "copyright": "© Mendix Technology BV 2025. All rights reserved.",
+ "license": "Apache-2.0",
+ "repository": {
+ "type": "git",
+ "url": "https://github.com/mendix/web-widgets.git"
+ },
+ "config": {
+ "developmentPort": 3000,
+ "mendixHost": "http://localhost:8080"
+ },
+ "mxpackage": {
+ "name": "DateTimePicker",
+ "type": "widget",
+ "mpkName": "com.mendix.widget.web.DateTimePicker.mpk"
+ },
+ "packagePath": "com.mendix.widget.web",
+ "marketplace": {
+ "minimumMXVersion": "10.24.0",
+ "appNumber": 999999,
+ "appName": "Date Time Picker",
+ "reactReady": true
+ },
+ "testProject": {
+ "githubUrl": "https://github.com/mendix/testProjects",
+ "branchName": "date-time-picker-web"
+ },
+ "scripts": {
+ "prebuild": "rui-create-translation",
+ "build": "pluggable-widgets-tools build:web",
+ "create-gh-release": "rui-create-gh-release",
+ "create-translation": "rui-create-translation",
+ "dev": "pluggable-widgets-tools start:web",
+ "format": "prettier --ignore-path ./node_modules/@mendix/prettier-config-web-widgets/global-prettierignore --write .",
+ "lint": "pluggable-widgets-tools lint",
+ "lint:fix": "pluggable-widgets-tools lint:fix",
+ "publish-marketplace": "rui-publish-marketplace",
+ "prerelease": "npm run lint",
+ "release": "pluggable-widgets-tools release:web",
+ "start": "pluggable-widgets-tools start:server",
+ "test": "pluggable-widgets-tools test:unit:web:enzyme-free",
+ "update-changelog": "rui-update-changelog-widget",
+ "verify": "rui-verify-package-format"
+ },
+ "dependencies": {
+ "classnames": "^2.5.1"
+ },
+ "devDependencies": {
+ "@mendix/automation-utils": "workspace:*",
+ "@mendix/eslint-config-web-widgets": "workspace:*",
+ "@mendix/pluggable-widgets-tools": "*",
+ "@mendix/prettier-config-web-widgets": "workspace:*",
+ "@mendix/rollup-web-widgets": "workspace:*",
+ "@mendix/widget-plugin-test-utils": "workspace:*"
+ }
+}
diff --git a/packages/pluggableWidgets/date-time-picker-web/rollup.config.mjs b/packages/pluggableWidgets/date-time-picker-web/rollup.config.mjs
new file mode 100644
index 0000000000..688a1a7197
--- /dev/null
+++ b/packages/pluggableWidgets/date-time-picker-web/rollup.config.mjs
@@ -0,0 +1,5 @@
+import copyFiles from "@mendix/rollup-web-widgets/copyFiles.mjs";
+
+export default args => {
+ return copyFiles(args);
+};
diff --git a/packages/pluggableWidgets/date-time-picker-web/src/DateTimePicker.dark.png b/packages/pluggableWidgets/date-time-picker-web/src/DateTimePicker.dark.png
new file mode 100644
index 0000000000..57c8008c44
Binary files /dev/null and b/packages/pluggableWidgets/date-time-picker-web/src/DateTimePicker.dark.png differ
diff --git a/packages/pluggableWidgets/date-time-picker-web/src/DateTimePicker.editorConfig.ts b/packages/pluggableWidgets/date-time-picker-web/src/DateTimePicker.editorConfig.ts
new file mode 100644
index 0000000000..2fe7a3f94e
--- /dev/null
+++ b/packages/pluggableWidgets/date-time-picker-web/src/DateTimePicker.editorConfig.ts
@@ -0,0 +1,140 @@
+import { DateTimePickerPreviewProps } from "../typings/DateTimePickerProps";
+
+export type Platform = "web" | "desktop";
+
+export type Properties = PropertyGroup[];
+
+type PropertyGroup = {
+ caption: string;
+ propertyGroups?: PropertyGroup[];
+ properties?: Property[];
+};
+
+type Property = {
+ key: string;
+ caption: string;
+ description?: string;
+ objectHeaders?: string[]; // used for customizing object grids
+ objects?: ObjectProperties[];
+ properties?: Properties[];
+};
+
+type ObjectProperties = {
+ properties: PropertyGroup[];
+ captions?: string[]; // used for customizing object grids
+};
+
+export type Problem = {
+ property?: string; // key of the property, at which the problem exists
+ severity?: "error" | "warning" | "deprecation"; // default = "error"
+ message: string; // description of the problem
+ studioMessage?: string; // studio-specific message, defaults to message
+ url?: string; // link with more information about the problem
+ studioUrl?: string; // studio-specific link
+};
+
+type BaseProps = {
+ type: "Image" | "Container" | "RowLayout" | "Text" | "DropZone" | "Selectable" | "Datasource";
+ grow?: number; // optionally sets a growth factor if used in a layout (default = 1)
+};
+
+type ImageProps = BaseProps & {
+ type: "Image";
+ document?: string; // svg image
+ data?: string; // base64 image
+ property?: object; // widget image property object from Values API
+ width?: number; // sets a fixed maximum width
+ height?: number; // sets a fixed maximum height
+};
+
+type ContainerProps = BaseProps & {
+ type: "Container" | "RowLayout";
+ children: PreviewProps[]; // any other preview element
+ borders?: boolean; // sets borders around the layout to visually group its children
+ borderRadius?: number; // integer. Can be used to create rounded borders
+ backgroundColor?: string; // HTML color, formatted #RRGGBB
+ borderWidth?: number; // sets the border width
+ padding?: number; // integer. adds padding around the container
+};
+
+type RowLayoutProps = ContainerProps & {
+ type: "RowLayout";
+ columnSize?: "fixed" | "grow"; // default is fixed
+};
+
+type TextProps = BaseProps & {
+ type: "Text";
+ content: string; // text that should be shown
+ fontSize?: number; // sets the font size
+ fontColor?: string; // HTML color, formatted #RRGGBB
+ bold?: boolean;
+ italic?: boolean;
+};
+
+type DropZoneProps = BaseProps & {
+ type: "DropZone";
+ property: object; // widgets property object from Values API
+ placeholder: string; // text to be shown inside the dropzone when empty
+ showDataSourceHeader?: boolean; // true by default. Toggles whether to show a header containing information about the datasource
+};
+
+type SelectableProps = BaseProps & {
+ type: "Selectable";
+ object: object; // object property instance from the Value API
+ child: PreviewProps; // any type of preview property to visualize the object instance
+};
+
+type DatasourceProps = BaseProps & {
+ type: "Datasource";
+ property: object | null; // datasource property object from Values API
+ child?: PreviewProps; // any type of preview property component (optional)
+};
+
+export type PreviewProps =
+ | ImageProps
+ | ContainerProps
+ | RowLayoutProps
+ | TextProps
+ | DropZoneProps
+ | SelectableProps
+ | DatasourceProps;
+
+export function getProperties(
+ _values: DateTimePickerPreviewProps,
+ defaultProperties: Properties /*, target: Platform*/
+): Properties {
+ // Do the values manipulation here to control the visibility of properties in Studio and Studio Pro conditionally.
+ /* Example
+ if (values.myProperty === "custom") {
+ delete defaultProperties.properties.myOtherProperty;
+ }
+ */
+ return defaultProperties;
+}
+
+// export function check(_values: DateTimePickerPreviewProps): Problem[] {
+// const errors: Problem[] = [];
+// // Add errors to the above array to throw errors in Studio and Studio Pro.
+// /* Example
+// if (values.myProperty !== "custom") {
+// errors.push({
+// property: `myProperty`,
+// message: `The value of 'myProperty' is different of 'custom'.`,
+// url: "https://github.com/myrepo/mywidget"
+// });
+// }
+// */
+// return errors;
+// }
+
+// export function getPreview(values: DateTimePickerPreviewProps, isDarkMode: boolean, version: number[]): PreviewProps {
+// // Customize your pluggable widget appearance for Studio Pro.
+// return {
+// type: "Container",
+// children: []
+// }
+// }
+
+// export function getCustomCaption(values: DateTimePickerPreviewProps, platform: Platform): string {
+// return "DateTimePicker";
+// }
diff --git a/packages/pluggableWidgets/date-time-picker-web/src/DateTimePicker.editorPreview.tsx b/packages/pluggableWidgets/date-time-picker-web/src/DateTimePicker.editorPreview.tsx
new file mode 100644
index 0000000000..c338cc236e
--- /dev/null
+++ b/packages/pluggableWidgets/date-time-picker-web/src/DateTimePicker.editorPreview.tsx
@@ -0,0 +1,37 @@
+import { ReactElement, createElement } from "react";
+
+import { parseInlineStyle } from "@mendix/pluggable-widgets-tools";
+
+import { BadgeSample, BadgeSampleProps } from "./components/BadgeSample";
+import { DateTimePickerPreviewProps } from "../typings/DateTimePickerProps";
+
+function parentInline(node?: HTMLElement | null): void {
+ // Temporary fix, the web modeler add a containing div, to render inline we need to change it.
+ if (node && node.parentElement && node.parentElement.parentElement) {
+ node.parentElement.parentElement.style.display = "inline-block";
+ }
+}
+
+function transformProps(props: DateTimePickerPreviewProps): BadgeSampleProps {
+ return {
+ type: props.datetimepickerType,
+ bootstrapStyle: props.bootstrapStyle,
+ className: props.className,
+ clickable: false,
+ style: parseInlineStyle(props.style),
+ defaultValue: props.datetimepickerValue ? props.datetimepickerValue : "",
+ value: props.valueAttribute
+ };
+}
+
+export function preview(props: DateTimePickerPreviewProps): ReactElement {
+ return (
+
+
+
+ );
+}
+
+export function getPreviewCss(): string {
+ return require("./ui/DateTimePicker.css");
+}
diff --git a/packages/pluggableWidgets/date-time-picker-web/src/DateTimePicker.icon.dark.png b/packages/pluggableWidgets/date-time-picker-web/src/DateTimePicker.icon.dark.png
new file mode 100644
index 0000000000..57c8008c44
Binary files /dev/null and b/packages/pluggableWidgets/date-time-picker-web/src/DateTimePicker.icon.dark.png differ
diff --git a/packages/pluggableWidgets/date-time-picker-web/src/DateTimePicker.icon.png b/packages/pluggableWidgets/date-time-picker-web/src/DateTimePicker.icon.png
new file mode 100644
index 0000000000..3e0905098f
Binary files /dev/null and b/packages/pluggableWidgets/date-time-picker-web/src/DateTimePicker.icon.png differ
diff --git a/packages/pluggableWidgets/date-time-picker-web/src/DateTimePicker.png b/packages/pluggableWidgets/date-time-picker-web/src/DateTimePicker.png
new file mode 100644
index 0000000000..bf2e00774c
Binary files /dev/null and b/packages/pluggableWidgets/date-time-picker-web/src/DateTimePicker.png differ
diff --git a/packages/pluggableWidgets/date-time-picker-web/src/DateTimePicker.tile.dark.png b/packages/pluggableWidgets/date-time-picker-web/src/DateTimePicker.tile.dark.png
new file mode 100644
index 0000000000..a609dfde9a
Binary files /dev/null and b/packages/pluggableWidgets/date-time-picker-web/src/DateTimePicker.tile.dark.png differ
diff --git a/packages/pluggableWidgets/date-time-picker-web/src/DateTimePicker.tile.png b/packages/pluggableWidgets/date-time-picker-web/src/DateTimePicker.tile.png
new file mode 100644
index 0000000000..e758564f7c
Binary files /dev/null and b/packages/pluggableWidgets/date-time-picker-web/src/DateTimePicker.tile.png differ
diff --git a/packages/pluggableWidgets/date-time-picker-web/src/DateTimePicker.tsx b/packages/pluggableWidgets/date-time-picker-web/src/DateTimePicker.tsx
new file mode 100644
index 0000000000..fccbfc7b3f
--- /dev/null
+++ b/packages/pluggableWidgets/date-time-picker-web/src/DateTimePicker.tsx
@@ -0,0 +1,27 @@
+import { ReactElement, createElement, useCallback } from "react";
+
+import { DateTimePickerContainerProps } from "../typings/DateTimePickerProps";
+import { BadgeSample } from "./components/BadgeSample";
+import "./ui/DateTimePicker.css";
+
+export function DateTimePicker(props: DateTimePickerContainerProps): ReactElement {
+ const { datetimepickerType, datetimepickerValue, valueAttribute, onClickAction, style, bootstrapStyle } = props;
+ const onClickHandler = useCallback(() => {
+ if (onClickAction && onClickAction.canExecute) {
+ onClickAction.execute();
+ }
+ }, [onClickAction]);
+
+ return (
+
+ );
+}
diff --git a/packages/pluggableWidgets/date-time-picker-web/src/DateTimePicker.xml b/packages/pluggableWidgets/date-time-picker-web/src/DateTimePicker.xml
new file mode 100644
index 0000000000..585c1bde14
--- /dev/null
+++ b/packages/pluggableWidgets/date-time-picker-web/src/DateTimePicker.xml
@@ -0,0 +1,123 @@
+
+
+ Date Time Picker
+
+ Input elements
+ Display
+ https://docs.mendix.com/appstore/widgets/datetimepicker
+
+
+
+
+ Picker type
+
+
+ Date
+ Time
+ Range
+
+
+
+ Placeholder
+
+
+
+
+
+
+ Value
+
+
+
+
+
+
+
+
+ Show label
+
+
+
+ Label caption
+
+
+
+
+
+
+ Editable
+
+
+ Default
+ Never
+ Conditionally
+
+
+
+ Condition
+
+
+
+
+ Read-only style
+
+
+ Based on data view (Control)
+ Control
+ Text
+
+
+
+
+
+ Visible
+
+
+
+
+
+
+ Validation
+
+
+ None
+ Required
+ Date in the future
+ Date in the past
+ Custom
+
+
+
+ Custom condition
+
+
+
+
+ Message
+
+
+
+
+
+
+ Aria required
+ Used by assistive technologies to indicate that a field is required.
+
+
+
+
+
+ On change
+
+
+
+ On enter
+
+
+
+ On leave
+
+
+
+
+
diff --git a/packages/pluggableWidgets/date-time-picker-web/src/components/Alert.tsx b/packages/pluggableWidgets/date-time-picker-web/src/components/Alert.tsx
new file mode 100644
index 0000000000..b3d283091d
--- /dev/null
+++ b/packages/pluggableWidgets/date-time-picker-web/src/components/Alert.tsx
@@ -0,0 +1,12 @@
+import { ReactElement, createElement } from "react";
+import classNames from "classnames";
+
+export interface AlertProps {
+ message?: string;
+ className?: string;
+ bootstrapStyle: "default" | "primary" | "success" | "info" | "inverse" | "warning" | "danger";
+}
+
+export function Alert({ message, className, bootstrapStyle }: AlertProps): ReactElement | null {
+ return message ? {message}
: null;
+}
diff --git a/packages/pluggableWidgets/date-time-picker-web/src/components/BadgeSample.tsx b/packages/pluggableWidgets/date-time-picker-web/src/components/BadgeSample.tsx
new file mode 100644
index 0000000000..9c3d762bd3
--- /dev/null
+++ b/packages/pluggableWidgets/date-time-picker-web/src/components/BadgeSample.tsx
@@ -0,0 +1,33 @@
+import { ReactElement, CSSProperties, createElement } from "react";
+import classNames from "classnames";
+
+export interface BadgeSampleProps {
+ type: "badge" | "label";
+ defaultValue?: string;
+ className?: string;
+ style?: CSSProperties;
+ value?: string;
+ bootstrapStyle?: BootstrapStyle;
+ clickable?: boolean;
+ onClickAction?: () => void;
+ getRef?: (node: HTMLElement) => void;
+}
+
+export type BootstrapStyle = "default" | "info" | "inverse" | "primary" | "danger" | "success" | "warning";
+
+export function BadgeSample(props: BadgeSampleProps): ReactElement {
+ const { type, defaultValue, className, style, value, bootstrapStyle, clickable, onClickAction, getRef } = props;
+ return (
+
+ {value || defaultValue}
+
+ );
+}
diff --git a/packages/pluggableWidgets/date-time-picker-web/src/components/__tests__/Alert.spec.tsx b/packages/pluggableWidgets/date-time-picker-web/src/components/__tests__/Alert.spec.tsx
new file mode 100644
index 0000000000..55334ef1cf
--- /dev/null
+++ b/packages/pluggableWidgets/date-time-picker-web/src/components/__tests__/Alert.spec.tsx
@@ -0,0 +1,19 @@
+import { createElement } from "react";
+import { shallow } from "enzyme";
+
+import { Alert } from "../Alert";
+
+describe("Alert", () => {
+ it("renders the structure when an alert message is specified", () => {
+ const message = "This is an error";
+ const alert = shallow();
+
+ expect(alert.equals({message}
)).toEqual(true);
+ });
+
+ it("renders no structure when the alert message is not specified", () => {
+ const alert = shallow();
+
+ expect(alert.isEmptyRender()).toEqual(true);
+ });
+});
diff --git a/packages/pluggableWidgets/date-time-picker-web/src/components/__tests__/BadgeSample.spec.tsx b/packages/pluggableWidgets/date-time-picker-web/src/components/__tests__/BadgeSample.spec.tsx
new file mode 100644
index 0000000000..db0dcde8e9
--- /dev/null
+++ b/packages/pluggableWidgets/date-time-picker-web/src/components/__tests__/BadgeSample.spec.tsx
@@ -0,0 +1,97 @@
+import { createElement } from "react";
+import { shallow, ShallowWrapper } from "enzyme";
+
+import { BadgeSample, BadgeSampleProps } from "../BadgeSample";
+
+describe("Badge", () => {
+ const createBadge = (props: BadgeSampleProps): ShallowWrapper => shallow();
+
+ it("should render the structure", () => {
+ const badgeProps: BadgeSampleProps = {
+ type: "badge",
+ bootstrapStyle: "default",
+ value: "0"
+ };
+ const badge = createBadge(badgeProps);
+
+ expect(badge.equals(0)).toEqual(true);
+ });
+
+ it("should show value when no value or default value provided", () => {
+ const value = "value";
+ const badge = createBadge({ type: "label", value, defaultValue: "default value" });
+
+ expect(badge.text()).toBe(value);
+ });
+
+ it("should show default value when no value is provided", () => {
+ const defaultValue = "default";
+ const badge = createBadge({ type: "label", value: undefined, defaultValue });
+
+ expect(badge.text()).toBe(defaultValue);
+ });
+
+ it("should show no value when no value or default value provided", () => {
+ const badge = createBadge({ type: "label", value: undefined });
+
+ expect(badge.text()).toBe("");
+ });
+
+ it("configured as a label should have the class label", () => {
+ const badge = createBadge({ type: "label" });
+
+ expect(badge.hasClass("label")).toBe(true);
+ });
+
+ it("configured as a badge should have the class badge", () => {
+ const badge = createBadge({ type: "badge" });
+
+ expect(badge.hasClass("badge")).toBe(true);
+ });
+
+ it("with a click action should respond to click events", () => {
+ const badgeProps: BadgeSampleProps = { onClickAction: jest.fn(), type: "badge" };
+ const onClick = (badgeProps.onClickAction = jest.fn());
+ const badge = createBadge(badgeProps);
+
+ badge.simulate("click");
+
+ expect(onClick).toHaveBeenCalledTimes(1);
+ });
+
+ it("with the Bootstrap style default should have the class label-default", () => {
+ const badge = createBadge({ bootstrapStyle: "default", type: "badge" });
+
+ expect(badge.hasClass("label-default")).toBe(true);
+ });
+
+ it("with the Bootstrap style primary should have the class label-primary", () => {
+ const badge = createBadge({ bootstrapStyle: "primary", type: "badge" });
+
+ expect(badge.hasClass("label-primary")).toBe(true);
+ });
+
+ it("with the Bootstrap style success should have the class label-success", () => {
+ const badge = createBadge({ bootstrapStyle: "success", type: "badge" });
+
+ expect(badge.hasClass("label-success")).toBe(true);
+ });
+
+ it("with the Bootstrap style info should have the class label-info", () => {
+ const badge = createBadge({ bootstrapStyle: "info", type: "badge" });
+
+ expect(badge.hasClass("label-info")).toBe(true);
+ });
+
+ it("with the Bootstrap style warning should have the class label-warning", () => {
+ const badge = createBadge({ bootstrapStyle: "warning", type: "badge" });
+
+ expect(badge.hasClass("label-warning")).toBe(true);
+ });
+
+ it("with the Bootstrap style danger should have the class label-danger", () => {
+ const badge = createBadge({ bootstrapStyle: "danger", type: "badge" });
+
+ expect(badge.hasClass("label-danger")).toBe(true);
+ });
+});
diff --git a/packages/pluggableWidgets/date-time-picker-web/src/package.xml b/packages/pluggableWidgets/date-time-picker-web/src/package.xml
new file mode 100644
index 0000000000..bada44ee78
--- /dev/null
+++ b/packages/pluggableWidgets/date-time-picker-web/src/package.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/pluggableWidgets/date-time-picker-web/src/ui/DateTimePicker.css b/packages/pluggableWidgets/date-time-picker-web/src/ui/DateTimePicker.css
new file mode 100644
index 0000000000..963df20d55
--- /dev/null
+++ b/packages/pluggableWidgets/date-time-picker-web/src/ui/DateTimePicker.css
@@ -0,0 +1,24 @@
+.widget-datetimepicker-clickable {
+ cursor: pointer;
+}
+
+.widget-datetimepicker {
+ display: inline-block;
+}
+
+.widget-datetimepicker.badge:empty {
+ display: initial;
+ /* Fix padding to stay round */
+ padding: 3px 10px;
+}
+
+.widget-datetimepicker.label:empty {
+ display: initial;
+ /* Fix padding to stay square */
+ padding: .2em .8em .3em;
+}
+
+.widget-datetimepicker.badge {
+ min-width: 18px;
+ min-height: 18px;
+}
diff --git a/packages/pluggableWidgets/date-time-picker-web/tsconfig.json b/packages/pluggableWidgets/date-time-picker-web/tsconfig.json
new file mode 100644
index 0000000000..a3d2c5cce8
--- /dev/null
+++ b/packages/pluggableWidgets/date-time-picker-web/tsconfig.json
@@ -0,0 +1,32 @@
+{
+ "extends": "@mendix/pluggable-widgets-tools/configs/tsconfig.base",
+ "compilerOptions": {
+ "baseUrl": "./",
+ "noEmitOnError": true,
+ "sourceMap": true,
+ "module": "esnext",
+ "target": "es6",
+ "lib": ["esnext", "dom"],
+ "types": ["jest", "node"],
+ "moduleResolution": "node",
+ "declaration": false,
+ "noLib": false,
+ "forceConsistentCasingInFileNames": true,
+ "noFallthroughCasesInSwitch": true,
+ "strict": true,
+ "strictFunctionTypes": false,
+ "skipLibCheck": true,
+ "noUnusedLocals": true,
+ "noUnusedParameters": true,
+ "jsx": "react-jsx",
+ "jsxFactory": "",
+ "allowSyntheticDefaultImports": true,
+ "esModuleInterop": true,
+ "useUnknownInCatchVariables": false,
+ "exactOptionalPropertyTypes": false,
+ "paths": {
+ "react-hot-loader/root": ["./hot-typescript.ts"]
+ }
+ },
+ "include": ["./src", "./typings"]
+}
diff --git a/packages/pluggableWidgets/date-time-picker-web/typings/DateTimePickerProps.d.ts b/packages/pluggableWidgets/date-time-picker-web/typings/DateTimePickerProps.d.ts
new file mode 100644
index 0000000000..f3fee7d375
--- /dev/null
+++ b/packages/pluggableWidgets/date-time-picker-web/typings/DateTimePickerProps.d.ts
@@ -0,0 +1,67 @@
+/**
+ * This file was generated from DateTimePicker.xml
+ * WARNING: All changes made to this file will be overwritten
+ * @author Mendix Widgets Framework Team
+ */
+import { CSSProperties } from "react";
+import { ActionValue, DynamicValue, EditableValue } from "mendix";
+
+export type TypeEnum = "date" | "time" | "Range";
+
+export type EditableEnum = "default" | "never" | "conditionally";
+
+export type ReadOnlyStyleEnum = "default" | "control" | "text";
+
+export type ValidationTypeEnum = "none" | "required" | "future" | "past" | "custom";
+
+export interface DateTimePickerContainerProps {
+ name: string;
+ class: string;
+ style?: CSSProperties;
+ tabIndex?: number;
+ type: TypeEnum;
+ placeholder?: DynamicValue;
+ dateAttribute: EditableValue;
+ showLabel: boolean;
+ label?: DynamicValue;
+ editable: EditableEnum;
+ editabilityCondition?: DynamicValue;
+ readOnlyStyle: ReadOnlyStyleEnum;
+ visible?: DynamicValue;
+ validationType: ValidationTypeEnum;
+ customValidation?: DynamicValue;
+ validationMessage?: DynamicValue;
+ ariaRequired: boolean;
+ onChange?: ActionValue;
+ onEnter?: ActionValue;
+ onLeave?: ActionValue;
+}
+
+export interface DateTimePickerPreviewProps {
+ /**
+ * @deprecated Deprecated since version 9.18.0. Please use class property instead.
+ */
+ className: string;
+ class: string;
+ style: string;
+ styleObject?: CSSProperties;
+ readOnly: boolean;
+ renderMode: "design" | "xray" | "structure";
+ translate: (text: string) => string;
+ type: TypeEnum;
+ placeholder: string;
+ dateAttribute: string;
+ showLabel: boolean;
+ label: string;
+ editable: EditableEnum;
+ editabilityCondition: string;
+ readOnlyStyle: ReadOnlyStyleEnum;
+ visible: string;
+ validationType: ValidationTypeEnum;
+ customValidation: string;
+ validationMessage: string;
+ ariaRequired: boolean;
+ onChange: {} | null;
+ onEnter: {} | null;
+ onLeave: {} | null;
+}
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 4fb47d0630..cb641c98b2 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -1330,6 +1330,31 @@ importers:
specifier: workspace:*
version: link:../../shared/widget-plugin-test-utils
+ packages/pluggableWidgets/date-time-picker-web:
+ dependencies:
+ classnames:
+ specifier: ^2.5.1
+ version: 2.5.1
+ devDependencies:
+ '@mendix/automation-utils':
+ specifier: workspace:*
+ version: link:../../../automation/utils
+ '@mendix/eslint-config-web-widgets':
+ specifier: workspace:*
+ version: link:../../shared/eslint-config-web-widgets
+ '@mendix/pluggable-widgets-tools':
+ specifier: 10.21.2
+ version: 10.21.2(@jest/transform@29.7.0)(@jest/types@30.2.0)(@swc/core@1.13.5)(@types/babel__core@7.20.5)(@types/node@22.14.1)(jest-util@30.2.0)(picomatch@4.0.3)(react-dom@18.3.1(react@18.3.1))(react-native@0.82.0(@babel/core@7.28.4)(@types/react@19.2.2)(react@18.3.1))(react@18.3.1)(tslib@2.8.1)
+ '@mendix/prettier-config-web-widgets':
+ specifier: workspace:*
+ version: link:../../shared/prettier-config-web-widgets
+ '@mendix/rollup-web-widgets':
+ specifier: workspace:*
+ version: link:../../shared/rollup-web-widgets
+ '@mendix/widget-plugin-test-utils':
+ specifier: workspace:*
+ version: link:../../shared/widget-plugin-test-utils
+
packages/pluggableWidgets/document-viewer-web:
dependencies:
'@mendix/widget-plugin-component-kit':