From 4d3a3b30614e92fa29ccfb487433028df8dbb5e1 Mon Sep 17 00:00:00 2001 From: Samuel Reichert Date: Fri, 20 Feb 2026 09:10:27 +0100 Subject: [PATCH 1/5] fix(calendar-web): update startDateAttribute to use EditableValue and handle null cases --- packages/pluggableWidgets/calendar-web/src/Calendar.tsx | 7 ++++++- packages/pluggableWidgets/calendar-web/src/Calendar.xml | 4 ++-- .../calendar-web/src/helpers/CalendarPropsBuilder.ts | 6 +++++- .../calendar-web/typings/CalendarProps.d.ts | 4 ++-- 4 files changed, 15 insertions(+), 6 deletions(-) diff --git a/packages/pluggableWidgets/calendar-web/src/Calendar.tsx b/packages/pluggableWidgets/calendar-web/src/Calendar.tsx index a7d8d31d52..e245ee7b34 100644 --- a/packages/pluggableWidgets/calendar-web/src/Calendar.tsx +++ b/packages/pluggableWidgets/calendar-web/src/Calendar.tsx @@ -8,7 +8,7 @@ import "./ui/Calendar.scss"; import { useCalendarEvents } from "./helpers/useCalendarEvents"; import { useLocalizer } from "./helpers/useLocalizer"; -export default function MxCalendar(props: CalendarContainerProps): ReactElement { +export default function MxCalendar(props: CalendarContainerProps): ReactElement | null { // useMemo with empty dependency array is used // because style and calendar controller needs to be created only once // and not on every re-render @@ -26,6 +26,11 @@ export default function MxCalendar(props: CalendarContainerProps): ReactElement }, [props, calendarController, localizer, culture]); const calendarEvents = useCalendarEvents(props); + + if (props.startDateAttribute && props.startDateAttribute.status !== "available") { + return null; + } + return (
diff --git a/packages/pluggableWidgets/calendar-web/src/Calendar.xml b/packages/pluggableWidgets/calendar-web/src/Calendar.xml index 0af2436b56..24df8a40ed 100644 --- a/packages/pluggableWidgets/calendar-web/src/Calendar.xml +++ b/packages/pluggableWidgets/calendar-web/src/Calendar.xml @@ -62,9 +62,9 @@ - + Start date attribute - The start date that should be shown in the view + The DateTime attribute used on initial load diff --git a/packages/pluggableWidgets/calendar-web/src/helpers/CalendarPropsBuilder.ts b/packages/pluggableWidgets/calendar-web/src/helpers/CalendarPropsBuilder.ts index 6d3c119b8e..d6176e11a6 100644 --- a/packages/pluggableWidgets/calendar-web/src/helpers/CalendarPropsBuilder.ts +++ b/packages/pluggableWidgets/calendar-web/src/helpers/CalendarPropsBuilder.ts @@ -16,6 +16,7 @@ export class CalendarPropsBuilder { private toolbarItems?: ResolvedToolbarItem[]; private step: number; private timeSlots: number; + private defaultDate?: Date; constructor(private props: CalendarContainerProps) { this.isCustomView = props.view === "custom"; @@ -36,6 +37,7 @@ export class CalendarPropsBuilder { `[Calendar] timeslots value ${props.timeslots} was clamped to ${this.timeSlots}. Must be between 1 and 4.` ); } + this.defaultDate = props.startDateAttribute?.value; } updateProps(props: CalendarContainerProps): void { @@ -43,6 +45,7 @@ export class CalendarPropsBuilder { this.props = props; this.events = this.buildEvents(props.databaseDataSource?.items ?? []); this.toolbarItems = this.buildToolbarItems(); + this.defaultDate = props.startDateAttribute?.value; } build(localizer: DateLocalizer, culture: string): DragAndDropCalendarProps { @@ -86,7 +89,8 @@ export class CalendarPropsBuilder { min: this.minTime, max: this.maxTime, step: this.step, - timeslots: this.timeSlots + timeslots: this.timeSlots, + ...(this.defaultDate ? { defaultDate: this.defaultDate } : {}) }; } diff --git a/packages/pluggableWidgets/calendar-web/typings/CalendarProps.d.ts b/packages/pluggableWidgets/calendar-web/typings/CalendarProps.d.ts index b0a1628d5e..644e2f5a08 100644 --- a/packages/pluggableWidgets/calendar-web/typings/CalendarProps.d.ts +++ b/packages/pluggableWidgets/calendar-web/typings/CalendarProps.d.ts @@ -4,7 +4,7 @@ * @author Mendix Widgets Framework Team */ import { CSSProperties } from "react"; -import { ActionValue, DynamicValue, ListValue, Option, ListActionValue, ListAttributeValue, ListExpressionValue } from "mendix"; +import { ActionValue, DynamicValue, EditableValue, ListValue, Option, ListActionValue, ListAttributeValue, ListExpressionValue } from "mendix"; export type TitleTypeEnum = "attribute" | "expression"; @@ -79,7 +79,7 @@ export interface CalendarContainerProps { startAttribute?: ListAttributeValue; endAttribute?: ListAttributeValue; eventColor?: ListAttributeValue; - startDateAttribute?: ListAttributeValue; + startDateAttribute?: EditableValue; editable: DynamicValue; view: ViewEnum; defaultViewStandard: DefaultViewStandardEnum; From a5bd8ce1fd9310e6a57166f0e953cf054b4bb701 Mon Sep 17 00:00:00 2001 From: Samuel Reichert Date: Fri, 20 Feb 2026 14:33:53 +0100 Subject: [PATCH 2/5] chore(calendar-web): update changelog --- packages/pluggableWidgets/calendar-web/CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/pluggableWidgets/calendar-web/CHANGELOG.md b/packages/pluggableWidgets/calendar-web/CHANGELOG.md index 4bd6ccc4ac..a2538870ad 100644 --- a/packages/pluggableWidgets/calendar-web/CHANGELOG.md +++ b/packages/pluggableWidgets/calendar-web/CHANGELOG.md @@ -6,6 +6,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), ## [Unreleased] +### Fixed + +- Improved handling of the start date attribute to ensure correct calendar initialization. + ## [2.3.0] - 2026-02-17 ### Added From 551530f9fa0cbfd494d00e996b8a5b5d4696b6c9 Mon Sep 17 00:00:00 2001 From: Samuel Reichert Date: Tue, 24 Feb 2026 11:32:28 +0100 Subject: [PATCH 3/5] fix(calendar-web): move startDateAttribute property to the View tab --- .../pluggableWidgets/calendar-web/src/Calendar.xml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/pluggableWidgets/calendar-web/src/Calendar.xml b/packages/pluggableWidgets/calendar-web/src/Calendar.xml index 24df8a40ed..25e9204adf 100644 --- a/packages/pluggableWidgets/calendar-web/src/Calendar.xml +++ b/packages/pluggableWidgets/calendar-web/src/Calendar.xml @@ -62,13 +62,6 @@ - - Start date attribute - The DateTime attribute used on initial load - - - - @@ -139,6 +132,13 @@ Time slots The number of slots per "section" in the time grid views. Adjust with step to change the default of 1 hour long groups, with 30 minute slots + + Start date attribute + The DateTime attribute used on initial load + + + + From 06e241714237580d156ca417028fe1aa528c0033 Mon Sep 17 00:00:00 2001 From: Samuel Reichert Date: Thu, 26 Feb 2026 10:19:37 +0100 Subject: [PATCH 4/5] fix(calendar-web): improve rendering logic with a loading component --- .../calendar-web/src/Calendar.tsx | 20 ++++++++++--------- .../calendar-web/typings/CalendarProps.d.ts | 4 ++-- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/packages/pluggableWidgets/calendar-web/src/Calendar.tsx b/packages/pluggableWidgets/calendar-web/src/Calendar.tsx index e245ee7b34..108905a995 100644 --- a/packages/pluggableWidgets/calendar-web/src/Calendar.tsx +++ b/packages/pluggableWidgets/calendar-web/src/Calendar.tsx @@ -1,4 +1,4 @@ -import { ReactElement, useMemo } from "react"; +import { Fragment, ReactElement, useMemo } from "react"; import classNames from "classnames"; import { CalendarContainerProps } from "../typings/CalendarProps"; import { CalendarPropsBuilder } from "./helpers/CalendarPropsBuilder"; @@ -8,7 +8,7 @@ import "./ui/Calendar.scss"; import { useCalendarEvents } from "./helpers/useCalendarEvents"; import { useLocalizer } from "./helpers/useLocalizer"; -export default function MxCalendar(props: CalendarContainerProps): ReactElement | null { +export default function MxCalendar(props: CalendarContainerProps): ReactElement { // useMemo with empty dependency array is used // because style and calendar controller needs to be created only once // and not on every re-render @@ -27,13 +27,15 @@ export default function MxCalendar(props: CalendarContainerProps): ReactElement const calendarEvents = useCalendarEvents(props); - if (props.startDateAttribute && props.startDateAttribute.status !== "available") { - return null; - } - return ( -
- -
+ + {props.startDateAttribute && props.startDateAttribute.status !== "available" ? ( +
+ ) : ( +
+ +
+ )} +
); } diff --git a/packages/pluggableWidgets/calendar-web/typings/CalendarProps.d.ts b/packages/pluggableWidgets/calendar-web/typings/CalendarProps.d.ts index 644e2f5a08..323b344cff 100644 --- a/packages/pluggableWidgets/calendar-web/typings/CalendarProps.d.ts +++ b/packages/pluggableWidgets/calendar-web/typings/CalendarProps.d.ts @@ -79,7 +79,6 @@ export interface CalendarContainerProps { startAttribute?: ListAttributeValue; endAttribute?: ListAttributeValue; eventColor?: ListAttributeValue; - startDateAttribute?: EditableValue; editable: DynamicValue; view: ViewEnum; defaultViewStandard: DefaultViewStandardEnum; @@ -92,6 +91,7 @@ export interface CalendarContainerProps { showAllEvents: boolean; step: number; timeslots: number; + startDateAttribute?: EditableValue; toolbarItems: ToolbarItemsType[]; customViewShowMonday: boolean; customViewShowTuesday: boolean; @@ -134,7 +134,6 @@ export interface CalendarPreviewProps { startAttribute: string; endAttribute: string; eventColor: string; - startDateAttribute: string; editable: string; view: ViewEnum; defaultViewStandard: DefaultViewStandardEnum; @@ -147,6 +146,7 @@ export interface CalendarPreviewProps { showAllEvents: boolean; step: number | null; timeslots: number | null; + startDateAttribute: string; toolbarItems: ToolbarItemsPreviewType[]; customViewShowMonday: boolean; customViewShowTuesday: boolean; From 792a907e7cdf4202d5f7538af04ce12a724c7d2c Mon Sep 17 00:00:00 2001 From: Samuel Reichert Date: Thu, 26 Feb 2026 16:51:44 +0100 Subject: [PATCH 5/5] fix(calendar-web): update loading indicator style and add loading bar component --- .../calendar-web/src/Calendar.tsx | 2 +- .../calendar-web/src/ui/Calendar.scss | 72 +++++++++++++++++++ 2 files changed, 73 insertions(+), 1 deletion(-) diff --git a/packages/pluggableWidgets/calendar-web/src/Calendar.tsx b/packages/pluggableWidgets/calendar-web/src/Calendar.tsx index 108905a995..1795c2ee41 100644 --- a/packages/pluggableWidgets/calendar-web/src/Calendar.tsx +++ b/packages/pluggableWidgets/calendar-web/src/Calendar.tsx @@ -30,7 +30,7 @@ export default function MxCalendar(props: CalendarContainerProps): ReactElement return ( {props.startDateAttribute && props.startDateAttribute.status !== "available" ? ( -
+
) : (
diff --git a/packages/pluggableWidgets/calendar-web/src/ui/Calendar.scss b/packages/pluggableWidgets/calendar-web/src/ui/Calendar.scss index d324b682cd..72181b73be 100644 --- a/packages/pluggableWidgets/calendar-web/src/ui/Calendar.scss +++ b/packages/pluggableWidgets/calendar-web/src/ui/Calendar.scss @@ -1,4 +1,5 @@ @use "sass:color"; +$brand-primary: #264ae5 !default; .widget-calendar { $cal-form-group-margin-bottom: 15px !default; @@ -79,4 +80,75 @@ .rbc-event { background-color: var(--brand-primary, $cal-brand-primary); } + + &-loading-bar { + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; + background-color: var(--border-color-default, #ced0d3); + border: none; + border-radius: 2px; + color: var(--brand-primary, $brand-primary); + height: 4px; + width: 100%; + + &::-webkit-progress-bar { + background-color: transparent; + } + + &::-webkit-progress-value { + background-color: currentColor; + transition: all 0.2s; + } + + &::-moz-progress-bar { + background-color: currentColor; + transition: all 0.2s; + } + + &::-ms-fill { + border: none; + background-color: currentColor; + transition: all 0.2s; + } + + &:indeterminate { + background-size: 200% 100%; + background-image: linear-gradient( + to right, + transparent 50%, + currentColor 50%, + currentColor 60%, + transparent 60%, + transparent 71.5%, + currentColor 71.5%, + currentColor 84%, + transparent 84% + ); + animation: progress-linear 3s infinite linear; + } + + &:indeterminate::-moz-progress-bar { + background-color: transparent; + } + + &:indeterminate::-ms-fill { + animation-name: none; + } + + @keyframes progress-linear { + 0% { + background-size: 200% 100%; + background-position: left -31.25% top 0%; + } + 50% { + background-size: 800% 100%; + background-position: left -49% top 0%; + } + 100% { + background-size: 400% 100%; + background-position: left -102% top 0%; + } + } + } }