@cwellt_software/cwellt-reactjs-lib 1.4.12 → 1.4.14

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.
Files changed (167) hide show
  1. package/dist/index.cjs.js +370 -16
  2. package/dist/index.css +1 -1
  3. package/dist/index.d.ts +110 -63
  4. package/dist/index.es.js +370 -17
  5. package/dist/src/components/control/action/button/CwButton.d.ts +1 -1
  6. package/dist/src/components/control/action/button/CwButton.d.ts.map +1 -1
  7. package/dist/src/components/control/action/buttons/CwButtons.d.ts +5 -5
  8. package/dist/src/components/control/action/buttons/CwButtons.d.ts.map +1 -1
  9. package/dist/src/components/control/action/search/CwSearch.d.ts +1 -1
  10. package/dist/src/components/control/action/search/CwSearch.d.ts.map +1 -1
  11. package/dist/src/components/control/choice/checkbox/CwCheck.d.ts +1 -1
  12. package/dist/src/components/control/choice/checkbox/CwCheck.d.ts.map +1 -1
  13. package/dist/src/components/control/choice/checkbox/CwCheckbox.d.ts +1 -1
  14. package/dist/src/components/control/choice/checkbox/CwCheckbox.d.ts.map +1 -1
  15. package/dist/src/components/control/choice/checkbox/CwCheckboxGroup.d.ts +1 -1
  16. package/dist/src/components/control/choice/checkbox/CwCheckboxGroup.d.ts.map +1 -1
  17. package/dist/src/components/control/choice/dropdown/CwDropdownFilter.d.ts +1 -1
  18. package/dist/src/components/control/choice/dropdown/CwDropdownFilter.d.ts.map +1 -1
  19. package/dist/src/components/control/choice/dropdown/CwPopoverButton.d.ts +1 -1
  20. package/dist/src/components/control/choice/dropdown/CwPopoverButton.d.ts.map +1 -1
  21. package/dist/src/components/control/choice/option/CwOption.d.ts +1 -1
  22. package/dist/src/components/control/choice/option/CwOption.d.ts.map +1 -1
  23. package/dist/src/components/control/choice/select/CwDropdown.d.ts +1 -1
  24. package/dist/src/components/control/choice/select/CwDropdown.d.ts.map +1 -1
  25. package/dist/src/components/control/choice/select/CwSelect.d.ts +1 -1
  26. package/dist/src/components/control/choice/select/CwSelect.d.ts.map +1 -1
  27. package/dist/src/components/control/choice/tag-selector/CwTagSelector.d.ts +1 -1
  28. package/dist/src/components/control/choice/tag-selector/CwTagSelector.d.ts.map +1 -1
  29. package/dist/src/components/control/choice/toggle/CwToggle.d.ts +1 -1
  30. package/dist/src/components/control/choice/toggle/CwToggle.d.ts.map +1 -1
  31. package/dist/src/components/control/choice/tree-view/CwTreeView.d.ts +1 -1
  32. package/dist/src/components/control/choice/tree-view/CwTreeView.d.ts.map +1 -1
  33. package/dist/src/components/control/input/any/CwInput.d.ts +1 -1
  34. package/dist/src/components/control/input/any/CwInput.d.ts.map +1 -1
  35. package/dist/src/components/control/input/date-text/CwInputDateText.d.ts +1 -1
  36. package/dist/src/components/control/input/date-text/CwInputDateText.d.ts.map +1 -1
  37. package/dist/src/components/control/input/datetime/CwInputDatetime.d.ts +1 -1
  38. package/dist/src/components/control/input/datetime/CwInputDatetime.d.ts.map +1 -1
  39. package/dist/src/components/control/input/digit/CwDigit.d.ts +1 -1
  40. package/dist/src/components/control/input/digit/CwDigit.d.ts.map +1 -1
  41. package/dist/src/components/control/input/file/CwFileUpload.d.ts +1 -1
  42. package/dist/src/components/control/input/file/CwFileUpload.d.ts.map +1 -1
  43. package/dist/src/components/control/input/file/CwFileUploadMultiple.d.ts +1 -1
  44. package/dist/src/components/control/input/file/CwFileUploadMultiple.d.ts.map +1 -1
  45. package/dist/src/components/control/input/image/CwInputImage.d.ts +1 -1
  46. package/dist/src/components/control/input/image/CwInputImage.d.ts.map +1 -1
  47. package/dist/src/components/control/input/new-dates/CwDatePicker.d.ts +2 -1
  48. package/dist/src/components/control/input/new-dates/CwDatePicker.d.ts.map +1 -1
  49. package/dist/src/components/control/input/new-dates/CwDatePickerTemporal.d.ts +2 -1
  50. package/dist/src/components/control/input/new-dates/CwDatePickerTemporal.d.ts.map +1 -1
  51. package/dist/src/components/control/input/new-dates/CwDateRangePicker.d.ts +1 -1
  52. package/dist/src/components/control/input/new-dates/CwDateRangePicker.d.ts.map +1 -1
  53. package/dist/src/components/control/input/new-dates/CwDateRangePickerTemporal.d.ts +2 -1
  54. package/dist/src/components/control/input/new-dates/CwDateRangePickerTemporal.d.ts.map +1 -1
  55. package/dist/src/components/control/input/new-dates/CwDateTimePicker.d.ts +1 -1
  56. package/dist/src/components/control/input/new-dates/CwDateTimePicker.d.ts.map +1 -1
  57. package/dist/src/components/control/input/new-dates/CwDateTimePickerCompact.d.ts +2 -1
  58. package/dist/src/components/control/input/new-dates/CwDateTimePickerCompact.d.ts.map +1 -1
  59. package/dist/src/components/control/input/new-dates/CwDateTimePickerTemporal.d.ts +52 -0
  60. package/dist/src/components/control/input/new-dates/CwDateTimePickerTemporal.d.ts.map +1 -0
  61. package/dist/src/components/control/input/new-dates/CwTimePicker.d.ts +4 -3
  62. package/dist/src/components/control/input/new-dates/CwTimePicker.d.ts.map +1 -1
  63. package/dist/src/components/control/input/new-dates/domain/DateTimePickerState.d.ts +78 -0
  64. package/dist/src/components/control/input/new-dates/domain/DateTimePickerState.d.ts.map +1 -0
  65. package/dist/src/components/control/input/new-dates/useCwDateTimePickerTemporal.d.ts +29 -0
  66. package/dist/src/components/control/input/new-dates/useCwDateTimePickerTemporal.d.ts.map +1 -0
  67. package/dist/src/components/control/input/number/CwInputNumber.d.ts +1 -1
  68. package/dist/src/components/control/input/number/CwInputNumber.d.ts.map +1 -1
  69. package/dist/src/components/control/input/phone/CwInputPhone.d.ts +1 -1
  70. package/dist/src/components/control/input/phone/CwInputPhone.d.ts.map +1 -1
  71. package/dist/src/components/control/input/text/CwInputText.d.ts +1 -1
  72. package/dist/src/components/control/input/text/CwInputText.d.ts.map +1 -1
  73. package/dist/src/components/control/input/text-area/CwTextArea.d.ts +1 -1
  74. package/dist/src/components/control/input/text-area/CwTextArea.d.ts.map +1 -1
  75. package/dist/src/components/control/input/time/CwTime.d.ts +1 -1
  76. package/dist/src/components/control/input/time/CwTime.d.ts.map +1 -1
  77. package/dist/src/components/custom/scheduler/CwSchedulerComp.d.ts +1 -1
  78. package/dist/src/components/custom/scheduler/CwSuperSchedulerComp.d.ts +1 -1
  79. package/dist/src/components/custom/scheduler/components/day_headers/DayHeader.d.ts +1 -1
  80. package/dist/src/components/custom/scheduler/components/day_headers/DayHeader.d.ts.map +1 -1
  81. package/dist/src/components/custom/scheduler/components/day_headers/MonthHeader.d.ts +1 -1
  82. package/dist/src/components/custom/scheduler/components/day_headers/MonthHeader.d.ts.map +1 -1
  83. package/dist/src/components/custom/scheduler/components/day_headers/WeekHeader.d.ts +1 -1
  84. package/dist/src/components/custom/scheduler/components/day_headers/WeekHeader.d.ts.map +1 -1
  85. package/dist/src/components/custom/scheduler/components/scheduler_timeline/SchedulerTimeLine.d.ts +1 -1
  86. package/dist/src/components/custom/scheduler/components/scheduler_timeline/SchedulerTimeLine.d.ts.map +1 -1
  87. package/dist/src/components/custom/scheduler/components/time_headers/TimeHeader.d.ts +1 -1
  88. package/dist/src/components/custom/scheduler/components/time_headers/TimeHeader.d.ts.map +1 -1
  89. package/dist/src/components/custom/scheduler-new/presentation/NewScheduler.d.ts +1 -1
  90. package/dist/src/components/custom/scheduler-new/presentation/NewScheduler.d.ts.map +1 -1
  91. package/dist/src/components/custom/scheduler-new/presentation/components/header/HeaderDivision.d.ts +1 -1
  92. package/dist/src/components/custom/scheduler-new/presentation/components/header/HeaderDivision.d.ts.map +1 -1
  93. package/dist/src/components/custom/scheduler-new/presentation/components/header/HeaderTitle.d.ts +1 -1
  94. package/dist/src/components/custom/scheduler-new/presentation/components/header/HeaderTitle.d.ts.map +1 -1
  95. package/dist/src/components/custom/scheduler-new/presentation/components/row/BackgroundEvent.d.ts +1 -1
  96. package/dist/src/components/custom/scheduler-new/presentation/components/row/BackgroundEvent.d.ts.map +1 -1
  97. package/dist/src/components/custom/scheduler-new/presentation/components/row/Event.d.ts +1 -1
  98. package/dist/src/components/custom/scheduler-new/presentation/components/row/Event.d.ts.map +1 -1
  99. package/dist/src/components/custom/scheduler-new/presentation/components/row/SchedulerRow.d.ts +1 -1
  100. package/dist/src/components/custom/scheduler-new/presentation/components/row/SchedulerRow.d.ts.map +1 -1
  101. package/dist/src/components/custom/scheduler-new/presentation/components/timeline/DivisionLine.d.ts +1 -1
  102. package/dist/src/components/custom/scheduler-new/presentation/components/timeline/DivisionLine.d.ts.map +1 -1
  103. package/dist/src/components/custom/scheduler-new/presentation/components/timeline/TimeLine.d.ts +1 -1
  104. package/dist/src/components/custom/scheduler-new/presentation/components/timeline/TimeLine.d.ts.map +1 -1
  105. package/dist/src/components/custom/scheduler-new/presentation/components/timeline/WeekEndLine.d.ts +1 -1
  106. package/dist/src/components/custom/scheduler-new/presentation/components/timeline/WeekEndLine.d.ts.map +1 -1
  107. package/dist/src/components/custom/super-scheduler/PinRowHeader.d.ts +1 -1
  108. package/dist/src/components/custom/super-scheduler/PinRowHeader.d.ts.map +1 -1
  109. package/dist/src/components/custom/super-scheduler/SuperScheduler.d.ts +2 -2
  110. package/dist/src/components/custom/super-scheduler/SuperScheduler.d.ts.map +1 -1
  111. package/dist/src/components/display/data/accordion/CwAccordionContainer.d.ts +1 -1
  112. package/dist/src/components/display/data/accordion/CwAccordionContainer.d.ts.map +1 -1
  113. package/dist/src/components/display/data/generic_tooltip/CwGenericTooltip.d.ts +2 -2
  114. package/dist/src/components/display/data/generic_tooltip/CwGenericTooltip.d.ts.map +1 -1
  115. package/dist/src/components/display/data/table/CwTable.d.ts +1 -1
  116. package/dist/src/components/display/data/table/CwTable.d.ts.map +1 -1
  117. package/dist/src/components/display/data/table-serverside/CwTableServerSide.d.ts +1 -1
  118. package/dist/src/components/display/data/table-serverside/CwTableServerSide.d.ts.map +1 -1
  119. package/dist/src/components/display/data/table_sortable/CwSortableTable.d.ts +1 -1
  120. package/dist/src/components/display/data/table_sortable/CwSortableTable.d.ts.map +1 -1
  121. package/dist/src/components/display/data/tooltip_manager/CwTooltipManager.d.ts.map +1 -1
  122. package/dist/src/components/display/graphics/icon/CwIcon.d.ts +2 -2
  123. package/dist/src/components/display/graphics/icon/CwIcon.d.ts.map +1 -1
  124. package/dist/src/components/display/graphics/icon/svg-icons.d.ts +2 -2
  125. package/dist/src/components/display/graphics/image-gallery/CwImageGallery.d.ts +1 -1
  126. package/dist/src/components/display/graphics/image-gallery/CwImageGallery.d.ts.map +1 -1
  127. package/dist/src/components/display/graphics/image-zoom/CwImageZoom.d.ts +1 -1
  128. package/dist/src/components/display/graphics/image-zoom/CwImageZoom.d.ts.map +1 -1
  129. package/dist/src/components/display/graphics/loading/CwLoading.d.ts +1 -1
  130. package/dist/src/components/display/graphics/loading/CwLoading.d.ts.map +1 -1
  131. package/dist/src/components/display/graphics/loading-small/CwLoadingSmall.d.ts +1 -1
  132. package/dist/src/components/display/graphics/loading-small/CwLoadingSmall.d.ts.map +1 -1
  133. package/dist/src/components/display/text/heading/CwHeadingMain.d.ts +1 -1
  134. package/dist/src/components/display/text/heading/CwHeadingMain.d.ts.map +1 -1
  135. package/dist/src/components/display/text/heading/CwHeadingSecond.d.ts +1 -1
  136. package/dist/src/components/display/text/heading/CwHeadingSecond.d.ts.map +1 -1
  137. package/dist/src/components/display/text/label/CwLabel.d.ts +1 -1
  138. package/dist/src/components/display/text/label/CwLabel.d.ts.map +1 -1
  139. package/dist/src/components/display/text/message/CwMessage.d.ts +1 -1
  140. package/dist/src/components/layout/align/CwAlign.d.ts +1 -1
  141. package/dist/src/components/layout/align/CwAlign.d.ts.map +1 -1
  142. package/dist/src/components/layout/card/CwCardList.d.ts +1 -1
  143. package/dist/src/components/layout/card/CwCardList.d.ts.map +1 -1
  144. package/dist/src/components/layout/confirmation-popup/CwConfirmationPopup.d.ts +2 -2
  145. package/dist/src/components/layout/confirmation-popup/CwConfirmationPopup.d.ts.map +1 -1
  146. package/dist/src/components/layout/list/sortable/CwSortableList.d.ts +2 -2
  147. package/dist/src/components/layout/list/sortable/CwSortableList.d.ts.map +1 -1
  148. package/dist/src/components/layout/modal/legacy/cw_modal.d.ts +1 -1
  149. package/dist/src/components/layout/modal/legacy/cw_modal.d.ts.map +1 -1
  150. package/dist/src/components/layout/modal/legacy/cw_modal_report.d.ts +1 -1
  151. package/dist/src/components/layout/tabs/CwTabs.d.ts +1 -1
  152. package/dist/src/components/layout/tabs/CwTabs.d.ts.map +1 -1
  153. package/dist/src/dev/index.d.ts +1 -1
  154. package/dist/src/dev/index.d.ts.map +1 -1
  155. package/dist/src/dev/palette.d.ts +2 -2
  156. package/dist/src/dev/palette.d.ts.map +1 -1
  157. package/dist/src/dev/previews.d.ts +2 -1
  158. package/dist/src/dev/previews.d.ts.map +1 -1
  159. package/dist/src/index.d.ts +1 -0
  160. package/dist/src/index.d.ts.map +1 -1
  161. package/dist/src/playground/PlaygroundApp.d.ts.map +1 -1
  162. package/dist/src/playground/pages/DatePickerTemporalPage.d.ts.map +1 -1
  163. package/dist/src/playground/pages/TooltipCrashPage.d.ts +3 -0
  164. package/dist/src/playground/pages/TooltipCrashPage.d.ts.map +1 -0
  165. package/dist/test/components/control/input/new-dates/DateTimePickerState.test.d.ts +2 -0
  166. package/dist/test/components/control/input/new-dates/DateTimePickerState.test.d.ts.map +1 -0
  167. package/package.json +1 -1
package/dist/index.cjs.js CHANGED
@@ -219,6 +219,11 @@ const showTooltip = (content, triggerElement, position = "right", dissapearsWhen
219
219
  constraintRect: constraintElement?.getBoundingClientRect()
220
220
  };
221
221
  stateUpdateCallbacks.forEach((cb) => cb());
222
+ // Self-heal: if the manager root died (e.g. a prior uncaught error), rebuild
223
+ // it now. The fresh manager initializes from the currentState set above, so
224
+ // this tooltip still shows on this hover — no page reload required. No-op
225
+ // (cheap guard return) when the manager is alive.
226
+ ensureTooltipManager();
222
227
  };
223
228
  const hideTooltip = (delay = 100) => {
224
229
  if (hideTimeout !== undefined) {
@@ -259,15 +264,59 @@ const calculatePositionForSide$1 = (position, triggerRect, tooltipRect) => {
259
264
  }
260
265
  };
261
266
  const MANAGER_CONTAINER_CLASS = "cw-tooltip-manager";
267
+ // Live reference to the manager's React root. Non-null while the manager is
268
+ // mounted (or being built), null once it unmounts — including when React tears
269
+ // the root down after an uncaught error. This is the liveness signal used to
270
+ // self-heal: a dead root leaves a stale container div in the DOM, so checking
271
+ // the div alone (as before) would never rebuild. The manager's effect nulls it
272
+ // on unmount (see CwTooltipManager).
273
+ let managerRoot = null;
262
274
  const ensureTooltipManager = () => {
263
- if (document.querySelector(`.${MANAGER_CONTAINER_CLASS}`))
275
+ // Truthy => alive or already being built this tick (guards against the many
276
+ // CwTooltipNew that mount in the same commit each spinning up their own root).
277
+ if (managerRoot)
264
278
  return;
279
+ // Remove any dead container left behind by a previous crash before rebuilding.
280
+ document.querySelectorAll(`.${MANAGER_CONTAINER_CLASS}`).forEach((el) => el.remove());
265
281
  const container = document.createElement("div");
266
282
  container.className = MANAGER_CONTAINER_CLASS;
267
283
  document.body.appendChild(container);
268
- const root = client.createRoot(container);
269
- root.render(jsxRuntime.jsx(CwTooltipManager, {}));
284
+ managerRoot = client.createRoot(container);
285
+ managerRoot.render(jsxRuntime.jsx(CwTooltipManager, {}));
270
286
  };
287
+ /**
288
+ * Isolates a crashing tooltip's content from the shared singleton root.
289
+ * Without this, an error thrown while rendering any single tooltip's content
290
+ * would unmount the whole CwTooltipManager root, killing every tooltip across
291
+ * the app until a full page reload.
292
+ *
293
+ * NOTE: React error boundaries can ONLY be implemented as class components —
294
+ * there is no hook / functional-component equivalent (see the React docs). This
295
+ * is the accepted exception to the project's functional-component convention;
296
+ * it is intentional infrastructure, not a refactor target — do not flag it.
297
+ */
298
+ class TooltipErrorBoundary extends React.Component {
299
+ state = { hasError: false };
300
+ static getDerivedStateFromError() {
301
+ return { hasError: true };
302
+ }
303
+ componentDidCatch(error) {
304
+ // Contain the crash: log it, then hide the tooltip so the manager stays
305
+ // mounted and the next hover works normally.
306
+ console.error("CwTooltip content crashed; hiding tooltip.", error);
307
+ this.props.onError();
308
+ }
309
+ componentDidUpdate(prevProps) {
310
+ // Recover for the hover-to-adjacent-element case, where content swaps
311
+ // without the boundary unmounting: clear the error so new content renders.
312
+ if (this.state.hasError && prevProps.children !== this.props.children) {
313
+ this.setState({ hasError: false });
314
+ }
315
+ }
316
+ render() {
317
+ return this.state.hasError ? null : this.props.children;
318
+ }
319
+ }
271
320
  // Main component
272
321
  /**
273
322
  * Global tooltip renderer. Manages a single portal instance in the DOM,
@@ -297,6 +346,11 @@ const CwTooltipManager = () => {
297
346
  stateUpdateCallbacks.add(update);
298
347
  return () => {
299
348
  stateUpdateCallbacks.delete(update);
349
+ // Signal that the root is gone so ensureTooltipManager rebuilds it on
350
+ // the next show — covers React tearing down the root after an uncaught
351
+ // error in the manager's own machinery (which the content boundary,
352
+ // living inside this tree, cannot catch).
353
+ managerRoot = null;
300
354
  };
301
355
  }, []);
302
356
  // Function to calculate position
@@ -426,7 +480,7 @@ const CwTooltipManager = () => {
426
480
  top: `${tooltipPosition.top}px`,
427
481
  left: `${tooltipPosition.left}px`,
428
482
  opacity: (isPositioned && !isMeasuring) ? 1 : 0,
429
- }, onMouseEnter: () => state.dissapearsWhenHover && hideTooltip(), children: state.content }), document.body);
483
+ }, onMouseEnter: () => state.dissapearsWhenHover && hideTooltip(), children: jsxRuntime.jsx(TooltipErrorBoundary, { onError: () => hideTooltip(0), children: state.content }) }), document.body);
430
484
  };
431
485
 
432
486
  /**
@@ -6512,7 +6566,10 @@ function CwTimePicker({ value, onChange, interval = 15, minTime, maxTime, labelP
6512
6566
  const handleClear = (e) => {
6513
6567
  e.stopPropagation();
6514
6568
  onChange(undefined);
6515
- setInputValue("");
6569
+ // Keep showing the current value prop: a controlled parent that accepts the
6570
+ // clear empties it via the value-sync effect, while a parent that rejects or
6571
+ // transforms the clear (e.g. resets to a default) stays visually in sync.
6572
+ setInputValue(value ?? "");
6516
6573
  };
6517
6574
  const handleInputClick = () => {
6518
6575
  if (!disabled) {
@@ -6540,15 +6597,18 @@ function CwTimePicker({ value, onChange, interval = 15, minTime, maxTime, labelP
6540
6597
  const [hours, minutes] = newValue.split(":");
6541
6598
  const h = parseInt(hours, 10);
6542
6599
  const m = parseInt(minutes, 10);
6543
- if (h >= 0 && h <= 23 && m >= 0 && m <= 59) {
6544
- const formattedTime = `${hours.padStart(2, "0")}:${minutes.padStart(2, "0")}`;
6545
- // Check min/max time restrictions
6546
- const isValid = (!minTime || formattedTime >= minTime) &&
6547
- (!maxTime || formattedTime <= maxTime);
6548
- if (isValid) {
6549
- onChange(formattedTime);
6550
- setInputValue(formattedTime);
6551
- }
6600
+ const formattedTime = `${hours.padStart(2, "0")}:${minutes.padStart(2, "0")}`;
6601
+ // Check well-formedness and min/max time restrictions
6602
+ const isValid = h >= 0 && h <= 23 && m >= 0 && m <= 59 &&
6603
+ (!minTime || formattedTime >= minTime) &&
6604
+ (!maxTime || formattedTime <= maxTime);
6605
+ if (isValid) {
6606
+ onChange(formattedTime);
6607
+ setInputValue(formattedTime);
6608
+ }
6609
+ else {
6610
+ // Completed entry is invalid/out of range: snap back to the previous value
6611
+ setInputValue(value ?? "");
6552
6612
  }
6553
6613
  }
6554
6614
  else if (newValue === "") {
@@ -7264,7 +7324,8 @@ function formatPlainDate(pd, fmt) {
7264
7324
 
7265
7325
  function CwDatePickerTemporal({ value, onChange, minDate, maxDate, disabledDates, disabledMatcher, defaultMonth, labelProps, alignProps, placeholder = "Select a date", displayFormat = "dd.MM.yyyy", disabled, required, className, showClear = true, popupPosition = "left-bottom", numberOfMonths = 1, showTodayButton = false, locale: locale$1 = locale.enGB, todayLabel = "Today", yearRangeStart, yearRangeEnd, feedback, }) {
7266
7326
  const [isOpen, setIsOpen] = React.useState(false);
7267
- const [inputValue, setInputValue] = React.useState();
7327
+ // Initialize with the formatted value so the input is controlled from the first render
7328
+ const [inputValue, setInputValue] = React.useState(() => value ? formatPlainDate(value, displayFormat) : "");
7268
7329
  const containerRef = React.useRef(null);
7269
7330
  const feedbackMessages = feedback
7270
7331
  ? Array.isArray(feedback) ? feedback : [feedback]
@@ -7382,6 +7443,298 @@ function CwDatePickerTemporal({ value, onChange, minDate, maxDate, disabledDates
7382
7443
  } }), showTodayButton && (jsxRuntime.jsx("footer", { className: "cw-flex-row cw-align-right-center", children: jsxRuntime.jsx(CwButton, { type: "button", variant: "outline", onClick: handleTodayClick, text: todayLabel }) }))] }))] })] }), feedbackMessages.map((feedbackItem, index) => (jsxRuntime.jsx("p", { className: "cw-input-info", "data-color": feedbackItem.type, children: feedbackItem.message }, index)))] }));
7383
7444
  }
7384
7445
 
7446
+ // DateTimePickerState - immutable domain model for the Temporal date-time picker.
7447
+ //
7448
+ // Invariants:
7449
+ // - `time` is NEVER null: this is a date-TIME picker, so the time always has a
7450
+ // value and defaults to 00:00. Only the date can be unselected, and without
7451
+ // a date the whole `value` is undefined.
7452
+ // - Minute precision everywhere: times AND constraints are truncated to HH:mm
7453
+ // on the way in, so emitted values always carry :00 seconds and boundary
7454
+ // checks never fail on sub-minute residue.
7455
+ // - NO reachable state holds an out-of-range selection when minDateTime /
7456
+ // maxDateTime are set. User operations that would leave the state invalid
7457
+ // return THE SAME instance (===), which the hook uses to skip the emission
7458
+ // and let the UI snap back; entry paths that cannot reject (fromValue,
7459
+ // withConstraints, withTimeCleared) clamp into the range instead.
7460
+ //
7461
+ // Because of these invariants the emission is state-scoped: after any accepted
7462
+ // operation the value to emit is simply the new state's `value`. Rejected
7463
+ // operations are detected by identity (`next === prev`).
7464
+ /** Truncate to minute precision (HH:mm) - the picker's working precision */
7465
+ function truncateToMinute(time) {
7466
+ return new Temporal.PlainTime(time.hour, time.minute);
7467
+ }
7468
+ function midnight() {
7469
+ return new Temporal.PlainTime(0, 0);
7470
+ }
7471
+ function truncateDateTimeToMinute(dateTime) {
7472
+ return dateTime
7473
+ ? dateTime.toPlainDate().toPlainDateTime(truncateToMinute(dateTime.toPlainTime()))
7474
+ : undefined;
7475
+ }
7476
+ /** Normalize constraints to the picker's minute precision */
7477
+ function normalizeConstraints(constraints) {
7478
+ return {
7479
+ minDateTime: truncateDateTimeToMinute(constraints.minDateTime),
7480
+ maxDateTime: truncateDateTimeToMinute(constraints.maxDateTime),
7481
+ minTime: constraints.minTime ? truncateToMinute(constraints.minTime) : undefined,
7482
+ maxTime: constraints.maxTime ? truncateToMinute(constraints.maxTime) : undefined,
7483
+ };
7484
+ }
7485
+ class DateTimePickerState {
7486
+ date;
7487
+ time;
7488
+ constraints;
7489
+ constructor(date, time, constraints) {
7490
+ this.date = date;
7491
+ this.time = time;
7492
+ this.constraints = normalizeConstraints(constraints);
7493
+ Object.freeze(this);
7494
+ }
7495
+ static empty(constraints = {}) {
7496
+ return new DateTimePickerState(undefined, midnight(), constraints);
7497
+ }
7498
+ /**
7499
+ * Build a state from an external value (the value-prop sync path).
7500
+ * The time is truncated to minute precision and the whole value is
7501
+ * clamped into [minDateTime, maxDateTime]: no state can ever hold an
7502
+ * out-of-range selection, regardless of where the value came from.
7503
+ */
7504
+ static fromValue(value, constraints = {}) {
7505
+ if (!value)
7506
+ return new DateTimePickerState(undefined, midnight(), constraints);
7507
+ const base = new DateTimePickerState(value.toPlainDate(), truncateToMinute(value.toPlainTime()), constraints);
7508
+ return base.clampedIntoRange();
7509
+ }
7510
+ /** Combined date+time; undefined when no date is selected. */
7511
+ get value() {
7512
+ return this.date ? this.date.toPlainDateTime(this.time) : undefined;
7513
+ }
7514
+ /**
7515
+ * Effective minimum time of day for the currently selected date:
7516
+ * when the selected date is the minDateTime boundary date, the boundary's
7517
+ * time (minute-truncated) replaces the static minTime.
7518
+ */
7519
+ get effectiveMinTime() {
7520
+ return this.effectiveMinTimeFor(this.date);
7521
+ }
7522
+ /** Effective maximum time of day for the currently selected date (see effectiveMinTime). */
7523
+ get effectiveMaxTime() {
7524
+ return this.effectiveMaxTimeFor(this.date);
7525
+ }
7526
+ /**
7527
+ * Select (or clear) the date.
7528
+ * - Clearing the date resets the whole selection (time back to 00:00).
7529
+ * - When the current time is out of range for the new date, it falls back
7530
+ * to the effective minimum time for that date (or 00:00).
7531
+ * - When even the fallback is out of range the date is rejected and the
7532
+ * same instance is returned.
7533
+ */
7534
+ withDate(date) {
7535
+ if (!date) {
7536
+ return new DateTimePickerState(undefined, midnight(), this.constraints);
7537
+ }
7538
+ if (this.isInRange(date.toPlainDateTime(this.time))) {
7539
+ return new DateTimePickerState(date, this.time, this.constraints);
7540
+ }
7541
+ const fallbackTime = this.effectiveMinTimeFor(date) ?? midnight();
7542
+ if (this.isInRange(date.toPlainDateTime(fallbackTime))) {
7543
+ return new DateTimePickerState(date, fallbackTime, this.constraints);
7544
+ }
7545
+ return this;
7546
+ }
7547
+ /**
7548
+ * Select the time (minute-truncated). An out-of-range time for the
7549
+ * selected date is rejected: the same instance is returned so the UI can
7550
+ * snap back to the previous time. Without a date any time is accepted
7551
+ * (there is no combination to validate yet).
7552
+ */
7553
+ withTime(time) {
7554
+ const truncated = truncateToMinute(time);
7555
+ if (this.date && !this.isInRange(this.date.toPlainDateTime(truncated))) {
7556
+ return this;
7557
+ }
7558
+ return new DateTimePickerState(this.date, truncated, this.constraints);
7559
+ }
7560
+ /**
7561
+ * Apply "now" (Now button), truncated to minute precision. Rejected
7562
+ * (same instance returned) when the truncated now is out of range.
7563
+ */
7564
+ withNow(now) {
7565
+ const date = now.toPlainDate();
7566
+ const time = truncateToMinute(now.toPlainTime());
7567
+ if (!this.isInRange(date.toPlainDateTime(time))) {
7568
+ return this;
7569
+ }
7570
+ return new DateTimePickerState(date, time, this.constraints);
7571
+ }
7572
+ /**
7573
+ * Reset the time to its default: the effective minimum for the current
7574
+ * date when 00:00 would be out of range (boundary dates), else 00:00.
7575
+ * The result is always in range - this is the clear-time path.
7576
+ */
7577
+ withTimeCleared() {
7578
+ if (!this.date) {
7579
+ return new DateTimePickerState(undefined, midnight(), this.constraints);
7580
+ }
7581
+ return new DateTimePickerState(this.date, midnight(), this.constraints).clampedIntoRange();
7582
+ }
7583
+ /** Reset the selection (no date, time back to 00:00), keeping the constraints. */
7584
+ clear() {
7585
+ return new DateTimePickerState(undefined, midnight(), this.constraints);
7586
+ }
7587
+ /**
7588
+ * Replace the constraints. The current selection is clamped into the new
7589
+ * [minDateTime, maxDateTime] range so it can never be left out of range.
7590
+ */
7591
+ withConstraints(constraints) {
7592
+ return new DateTimePickerState(this.date, this.time, constraints).clampedIntoRange();
7593
+ }
7594
+ /**
7595
+ * Clamp the selection into [minDateTime, maxDateTime]: a combined value
7596
+ * below the minimum becomes the minimum (date and time), one above the
7597
+ * maximum becomes the maximum. In-range states return themselves.
7598
+ */
7599
+ clampedIntoRange() {
7600
+ const combined = this.value;
7601
+ if (!combined)
7602
+ return this;
7603
+ const { minDateTime, maxDateTime } = this.constraints;
7604
+ if (minDateTime && Temporal.PlainDateTime.compare(combined, minDateTime) < 0) {
7605
+ return new DateTimePickerState(minDateTime.toPlainDate(), truncateToMinute(minDateTime.toPlainTime()), this.constraints);
7606
+ }
7607
+ if (maxDateTime && Temporal.PlainDateTime.compare(combined, maxDateTime) > 0) {
7608
+ return new DateTimePickerState(maxDateTime.toPlainDate(), truncateToMinute(maxDateTime.toPlainTime()), this.constraints);
7609
+ }
7610
+ return this;
7611
+ }
7612
+ effectiveMinTimeFor(date) {
7613
+ const { minDateTime, minTime } = this.constraints;
7614
+ if (date && minDateTime && date.equals(minDateTime.toPlainDate())) {
7615
+ return truncateToMinute(minDateTime.toPlainTime());
7616
+ }
7617
+ return minTime;
7618
+ }
7619
+ effectiveMaxTimeFor(date) {
7620
+ const { maxDateTime, maxTime } = this.constraints;
7621
+ if (date && maxDateTime && date.equals(maxDateTime.toPlainDate())) {
7622
+ return truncateToMinute(maxDateTime.toPlainTime());
7623
+ }
7624
+ return maxTime;
7625
+ }
7626
+ isInRange(combined) {
7627
+ const { minDateTime, maxDateTime } = this.constraints;
7628
+ if (minDateTime && Temporal.PlainDateTime.compare(combined, minDateTime) < 0)
7629
+ return false;
7630
+ if (maxDateTime && Temporal.PlainDateTime.compare(combined, maxDateTime) > 0)
7631
+ return false;
7632
+ return true;
7633
+ }
7634
+ }
7635
+
7636
+ // useCwDateTimePickerTemporal - thin glue between DateTimePickerState and the
7637
+ // CwDateTimePickerTemporal component. All picker logic lives in the domain
7638
+ // class; this hook only holds the instance in React state, syncs it with the
7639
+ // external value prop, and converts PlainTime <-> "HH:mm" at the CwTimePicker
7640
+ // string boundary.
7641
+ //
7642
+ // Emission model: an accepted operation returns a NEW instance and the hook
7643
+ // emits its `value`; a rejected operation returns the SAME instance and
7644
+ // nothing is emitted (CwTimePicker snaps its text back to the value prop as
7645
+ // soon as the typed entry is complete and invalid).
7646
+ //
7647
+ // The time string is empty until a date is selected (visual only): without a
7648
+ // date the whole value is undefined, so showing the default 00:00 would
7649
+ // suggest a selection that doesn't exist.
7650
+ function plainTimeToHHmm(time) {
7651
+ return `${String(time.hour).padStart(2, "0")}:${String(time.minute).padStart(2, "0")}`;
7652
+ }
7653
+ /** "HH:mm" -> PlainTime; unparseable input yields undefined (ignored by the caller) */
7654
+ function hhmmToPlainTime(time) {
7655
+ try {
7656
+ return Temporal.PlainTime.from(time);
7657
+ }
7658
+ catch {
7659
+ return undefined;
7660
+ }
7661
+ }
7662
+ function optionalTimeToHHmm(time) {
7663
+ return time ? plainTimeToHHmm(time) : undefined;
7664
+ }
7665
+ function plainDateTimesEqual(a, b) {
7666
+ if (!a || !b)
7667
+ return a === b;
7668
+ return a.equals(b);
7669
+ }
7670
+ function useCwDateTimePickerTemporal({ value, onChange, minDateTime, maxDateTime, minTime, maxTime, }) {
7671
+ const constraints = React.useMemo(() => ({
7672
+ minDateTime,
7673
+ maxDateTime,
7674
+ minTime: minTime ? hhmmToPlainTime(minTime) : undefined,
7675
+ maxTime: maxTime ? hhmmToPlainTime(maxTime) : undefined,
7676
+ // ISO-string deps keep the object stable across re-created Temporal instances
7677
+ }), [minDateTime?.toString(), maxDateTime?.toString(), minTime, maxTime]);
7678
+ const [state, setState] = React.useState(() => DateTimePickerState.fromValue(value, constraints));
7679
+ // Track the previous value prop to detect external changes.
7680
+ const prevValueRef = React.useRef(value);
7681
+ React.useEffect(() => {
7682
+ if (!plainDateTimesEqual(value, prevValueRef.current)) {
7683
+ prevValueRef.current = value;
7684
+ setState(prev => DateTimePickerState.fromValue(value, prev.constraints));
7685
+ }
7686
+ }, [value]);
7687
+ React.useEffect(() => {
7688
+ setState(prev => prev.withConstraints(constraints));
7689
+ }, [constraints]);
7690
+ const apply = React.useCallback((next) => {
7691
+ if (next === state)
7692
+ return; // operation rejected by the domain - no emission
7693
+ setState(next);
7694
+ onChange(next.value);
7695
+ }, [state, onChange]);
7696
+ const selectDate = React.useCallback((date) => {
7697
+ apply(state.withDate(date));
7698
+ }, [state, apply]);
7699
+ const selectTime = React.useCallback((time) => {
7700
+ if (!time) {
7701
+ // Cleared time input: reset to the in-range default for the current date
7702
+ apply(state.withTimeCleared());
7703
+ return;
7704
+ }
7705
+ const parsed = hhmmToPlainTime(time);
7706
+ if (parsed) {
7707
+ apply(state.withTime(parsed));
7708
+ }
7709
+ }, [state, apply]);
7710
+ const selectNow = React.useCallback(() => {
7711
+ apply(state.withNow(Temporal.Now.plainDateTimeISO()));
7712
+ }, [state, apply]);
7713
+ return {
7714
+ date: state.date,
7715
+ time: state.date ? plainTimeToHHmm(state.time) : "",
7716
+ minDate: minDateTime?.toPlainDate(),
7717
+ maxDate: maxDateTime?.toPlainDate(),
7718
+ effectiveMinTime: optionalTimeToHHmm(state.effectiveMinTime),
7719
+ effectiveMaxTime: optionalTimeToHHmm(state.effectiveMaxTime),
7720
+ selectDate,
7721
+ selectTime,
7722
+ selectNow,
7723
+ };
7724
+ }
7725
+
7726
+ function CwDateTimePickerTemporal({ value, onChange, minDateTime, maxDateTime, disabledDates, disabledMatcher, timeInterval = 15, minTime, maxTime, labelProps, alignProps, datePlaceholder = "dd.MM.yyyy", timePlaceholder = "HH:mm", disabled, required, className, showClear = true, popupPosition = "left-bottom", numberOfMonths = 1, showNowButton = false, nowLabel = "Now", locale: locale$1 = locale.enGB, }) {
7727
+ const picker = useCwDateTimePickerTemporal({
7728
+ value,
7729
+ onChange,
7730
+ minDateTime,
7731
+ maxDateTime,
7732
+ minTime,
7733
+ maxTime,
7734
+ });
7735
+ return jsxRuntime.jsx("div", { className: `cw-datetimepicker cw-datetimepicker-separate ${className || ""}`, children: jsxRuntime.jsxs(CwAlign, { ...alignProps, itemProp: required ? "required" : "", children: [labelProps && (jsxRuntime.jsx(CwLabel, { ...labelProps, children: labelProps.text })), jsxRuntime.jsxs("div", { className: "cw-flex-row cw-align-left-center cw-gap-small", children: [jsxRuntime.jsx(CwDatePickerTemporal, { value: picker.date, onChange: picker.selectDate, minDate: picker.minDate, maxDate: picker.maxDate, disabledDates: disabledDates, disabledMatcher: disabledMatcher, placeholder: datePlaceholder, disabled: disabled, required: required, showClear: showClear, numberOfMonths: numberOfMonths, popupPosition: popupPosition, locale: locale$1 }), jsxRuntime.jsx(CwTimePicker, { value: picker.time, onChange: picker.selectTime, interval: timeInterval, minTime: picker.effectiveMinTime, maxTime: picker.effectiveMaxTime, placeholder: timePlaceholder, disabled: disabled, required: required, showClear: showClear, popupPosition: popupPosition }), showNowButton && (jsxRuntime.jsx(CwButton, { type: "button", variant: "outline", onClick: picker.selectNow, disabled: disabled, text: nowLabel }))] })] }) });
7736
+ }
7737
+
7385
7738
  // dateRangePresetsTemporal.ts
7386
7739
  // Temporal-typed counterpart of dateRangePresets.ts (used by CwDateRangePickerTemporal).
7387
7740
  // Each preset is evaluated at click time; a reference date can be injected for testing.
@@ -8148,7 +8501,7 @@ crewAssignmentSchedulerContextMenu, }) => {
8148
8501
  };
8149
8502
 
8150
8503
  const TimeLine$1 = ({ id, toolTipTitle, marginLeft, color = "rgba(255,0,0,.6)", pixels = 2, height = "100%", zIndex = 1, }) => {
8151
- return (jsxRuntime.jsx(CwGenericTooltip, { content: toolTipTitle, position: "top", children: jsxRuntime.jsx("div", { id: id, style: {
8504
+ return (jsxRuntime.jsx(CwTooltipNew, { content: toolTipTitle, position: "top", children: jsxRuntime.jsx("div", { id: id, style: {
8152
8505
  borderLeft: `${pixels}px solid ${color}`,
8153
8506
  marginLeft: marginLeft,
8154
8507
  width: "0px",
@@ -10792,6 +11145,7 @@ exports.CwDateRangePicker = CwDateRangePicker;
10792
11145
  exports.CwDateRangePickerTemporal = CwDateRangePickerTemporal;
10793
11146
  exports.CwDateTimePicker = CwDateTimePicker;
10794
11147
  exports.CwDateTimePickerCompact = CwDateTimePickerCompact;
11148
+ exports.CwDateTimePickerTemporal = CwDateTimePickerTemporal;
10795
11149
  exports.CwDialog = CwDialog;
10796
11150
  exports.CwDigit = CwDigit;
10797
11151
  exports.CwDisplayMessage = CwDisplayMessage;