@capillarytech/blaze-ui 5.2.2 → 5.2.4

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 (47) hide show
  1. package/.npmrc +2 -0
  2. package/CapCollapsibleNavbar/index.js +55 -3
  3. package/CapCollapsibleNavbar/index.js.map +1 -1
  4. package/CapCondition/index.js +55 -3
  5. package/CapCondition/index.js.map +1 -1
  6. package/CapDatePicker/index.js +55 -3
  7. package/CapDatePicker/index.js.map +1 -1
  8. package/CapDateTimePicker/README.md +136 -0
  9. package/CapDateTimePicker/index.d.ts +13 -0
  10. package/CapDateTimePicker/index.d.ts.map +1 -0
  11. package/CapDateTimePicker/index.js +166 -106
  12. package/CapDateTimePicker/index.js.map +1 -1
  13. package/CapDateTimePicker/messages.d.ts +17 -0
  14. package/CapDateTimePicker/messages.d.ts.map +1 -0
  15. package/CapDateTimePicker/types.d.ts +93 -0
  16. package/CapDateTimePicker/types.d.ts.map +1 -0
  17. package/CapDateTimeRangePicker/index.js +55 -3
  18. package/CapDateTimeRangePicker/index.js.map +1 -1
  19. package/CapEventCalendar/index.js +55 -3
  20. package/CapEventCalendar/index.js.map +1 -1
  21. package/CapLanguageProvider/index.js +55 -3
  22. package/CapLanguageProvider/index.js.map +1 -1
  23. package/CapLevelGraphRenderer/CapLevelGraphRenderer-test-cases.md +50 -0
  24. package/CapLevelGraphRenderer/MIGRATION_ANALYSIS.md +138 -0
  25. package/CapLevelGraphRenderer/README.md +123 -0
  26. package/CapLevelGraphRenderer/STORYBOOK_ANALYSIS.md +96 -0
  27. package/CapLevelGraphRenderer/Tooltip.d.ts +31 -0
  28. package/CapLevelGraphRenderer/Tooltip.d.ts.map +1 -0
  29. package/CapLevelGraphRenderer/Tooltip_MIGRATION_ANALYSIS.md +120 -0
  30. package/CapLevelGraphRenderer/index.d.ts +16 -0
  31. package/CapLevelGraphRenderer/index.d.ts.map +1 -0
  32. package/CapLevelGraphRenderer/index.js +159 -135
  33. package/CapLevelGraphRenderer/index.js.map +1 -1
  34. package/CapLevelGraphRenderer/tests/TEST_COVERAGE.md +119 -0
  35. package/CapLevelGraphRenderer/types.d.ts +139 -0
  36. package/CapLevelGraphRenderer/types.d.ts.map +1 -0
  37. package/CapNotificationDropdown/index.js +55 -3
  38. package/CapNotificationDropdown/index.js.map +1 -1
  39. package/CapTimePicker/index.js +55 -3
  40. package/CapTimePicker/index.js.map +1 -1
  41. package/index.d.ts +4 -0
  42. package/index.d.ts.map +1 -1
  43. package/index.js +1053 -4
  44. package/index.js.map +1 -1
  45. package/package.json +4 -2
  46. package/utils/dayjs.d.ts +21 -0
  47. package/utils/dayjs.d.ts.map +1 -1
@@ -0,0 +1,119 @@
1
+ # Test Coverage: CapLevelGraphRenderer
2
+
3
+ ## Test Files Created
4
+
5
+ 1. **CapLevelGraphRenderer.test.tsx** - Main test file with comprehensive coverage
6
+ 2. **CapLevelGraphRenderer.mockData.ts** - Mock data and test fixtures
7
+
8
+ ## Test Coverage Summary
9
+
10
+ ### ✅ Default Rendering (4 tests)
11
+ - Renders graph container and pagination controls
12
+ - Renders with nodes and connections
13
+ - Renders empty state without errors
14
+ - Renders single node without connections
15
+
16
+ ### ✅ Graph Initialization (4 tests)
17
+ - Initializes graph with correct container
18
+ - Registers tooltip tool when showToolTip is true
19
+ - Does not register tooltip tool when showToolTip is false
20
+ - Handles missing container gracefully
21
+
22
+ ### ✅ Node Rendering (3 tests)
23
+ - Renders multiple nodes
24
+ - Renders nodes with custom components and props
25
+ - Handles nodes with toolTip property
26
+
27
+ ### ✅ Connections (4 tests)
28
+ - Renders forward connections between adjacent nodes
29
+ - Renders reverse connections
30
+ - Handles complex connection scenarios
31
+ - Handles invalid connections gracefully
32
+
33
+ ### ✅ Pagination (5 tests)
34
+ - Disables previous button at start position
35
+ - Enables next button when content exceeds viewport
36
+ - Disables both buttons when all content fits
37
+ - Scrolls left when previous button is clicked
38
+ - Scrolls right when next button is clicked
39
+
40
+ ### ✅ Props Variations (9 tests)
41
+ - Applies className and scrollClassName props
42
+ - Applies graphStyles prop
43
+ - Applies containerStyles prop
44
+ - Applies graphWidth and graphHeight props
45
+ - Applies layout props (offsetHeight, defaultStartX, defaultStartY, etc.)
46
+ - Applies lineStrokeColor prop
47
+ - Applies forwardConnProps
48
+ - Applies reverseConnProps
49
+
50
+ ### ✅ Tooltip Functionality (3 tests)
51
+ - Registers edge events when showToolTip is true
52
+ - Does not register edge events when showToolTip is false
53
+ - Registers node events for input focus
54
+
55
+ ### ✅ Scroller Props (1 test)
56
+ - Applies scrollerProps to graph
57
+
58
+ ### ✅ Edge Cases (3 tests)
59
+ - Handles empty nodes array
60
+ - Handles empty connections array
61
+ - Updates scroll position when nodes change
62
+
63
+ ## Total Test Count
64
+
65
+ **36 test cases** covering all major functionality areas.
66
+
67
+ ## Test Patterns Used
68
+
69
+ - ✅ `it.each` for repetitive prop variations
70
+ - ✅ Reusable helper functions (`renderWithProps`)
71
+ - ✅ Mock data in separate file (`CapLevelGraphRenderer.mockData.ts`)
72
+ - ✅ Focus on functional behavior (not styling)
73
+ - ✅ User interaction testing with `@testing-library/user-event`
74
+ - ✅ Edge case coverage
75
+ - ✅ Proper mocking of @antv/x6 Graph library
76
+
77
+ ## Mocking Strategy
78
+
79
+ - **@antv/x6 Graph**: Mocked constructor and instance methods (addNode, addEdge, on, setScrollbarPosition)
80
+ - **Graph.registerEdgeTool**: Mocked static method
81
+ - **TooltipTool**: Mocked module
82
+ - **DOM Containers**: Created and cleaned up in beforeEach/afterEach
83
+
84
+ ## Notes
85
+
86
+ - Tests focus on functional behavior and user interactions
87
+ - No Cap UI components are mocked (CapButton, CapIcon render normally)
88
+ - Tests verify graph initialization, node rendering, connection drawing, and pagination
89
+ - Edge cases like empty states and invalid data are covered
90
+ - Tooltip functionality is tested through event registration verification
91
+
92
+ ## Use Cases Coverage
93
+
94
+ Based on `CapLevelGraphRenderer-test-cases.md`:
95
+
96
+ | Use Case ID | Status | Test Coverage |
97
+ |-------------|--------|---------------|
98
+ | UC-001 | ✅ | Basic rendering test |
99
+ | UC-002 | ✅ | Empty state test |
100
+ | UC-003 | ✅ | Single node test |
101
+ | UC-004 | ✅ | Forward connections test |
102
+ | UC-005 | ✅ | Reverse connections test |
103
+ | UC-006 | ✅ | Styling props test |
104
+ | UC-007 | ✅ | Layout props test |
105
+ | UC-008 | ✅ | Connection styling test |
106
+ | UC-009 | ✅ | Tooltip registration test |
107
+ | UC-010 | ✅ | Tooltip registration test |
108
+ | UC-011 | ✅ | Tooltip disabled test |
109
+ | UC-012 | ✅ | Pagination previous test |
110
+ | UC-013 | ✅ | Pagination next test |
111
+ | UC-014 | ✅ | Pagination states test |
112
+ | UC-015 | ✅ | Scroller props test |
113
+ | UC-016 | ✅ | Node component rendering test |
114
+ | UC-017 | ✅ | Complex connections test |
115
+ | UC-018 | ✅ | Missing container test |
116
+ | UC-019 | ✅ | Invalid connections test |
117
+ | UC-020 | ✅ | Graph API integration test |
118
+
119
+ **Coverage**: 20/20 use cases covered ✅
@@ -0,0 +1,139 @@
1
+ import { Graph } from '@antv/x6';
2
+ import React from 'react';
3
+ /**
4
+ * Node data structure for graph rendering
5
+ */
6
+ export interface GraphNode {
7
+ /** Unique identifier for the node */
8
+ id: string;
9
+ /** React component to render inside the node */
10
+ component: React.ComponentType<Record<string, unknown>>;
11
+ /** Height of the node in pixels */
12
+ height: number;
13
+ /** Props to pass to the component */
14
+ props?: Record<string, unknown>;
15
+ /** Tooltip text for the node */
16
+ toolTip?: string;
17
+ }
18
+ /**
19
+ * Connection data structure for graph edges
20
+ */
21
+ export interface GraphConnection {
22
+ /** Source node ID */
23
+ sourceId: string;
24
+ /** Target node ID */
25
+ targetId: string;
26
+ }
27
+ /**
28
+ * Node position tracking object
29
+ */
30
+ export interface NodePosition {
31
+ /** X coordinate */
32
+ x: number;
33
+ /** Y coordinate */
34
+ y: number;
35
+ /** End X coordinate */
36
+ x1: number;
37
+ /** End Y coordinate */
38
+ y1: number;
39
+ /** Node height */
40
+ height: number;
41
+ /** Node width */
42
+ width: number;
43
+ /** Tooltip text */
44
+ toolTip: string;
45
+ }
46
+ /**
47
+ * Edge tracking object
48
+ */
49
+ export interface EdgeObj {
50
+ forward?: boolean;
51
+ reverse?: boolean;
52
+ }
53
+ /**
54
+ * Connection object for internal tracking
55
+ */
56
+ export interface ConnectionObj {
57
+ in: string[];
58
+ out: string[];
59
+ }
60
+ /**
61
+ * Props for CapLevelGraphRenderer component
62
+ */
63
+ export interface CapLevelGraphRendererProps {
64
+ /** Array of nodes to render in the graph */
65
+ nodes?: GraphNode[];
66
+ /** Unique identifier for the graph container DOM element (required) */
67
+ graphId: string;
68
+ /** Additional CSS class name */
69
+ className?: string;
70
+ /** Width of the graph container (number in pixels or string like '500px') */
71
+ graphWidth?: number | string;
72
+ /** Height of the graph container (number in pixels or string like '500px') */
73
+ graphHeight?: number | string;
74
+ /** Whether to show tooltips on edges */
75
+ showToolTip?: boolean;
76
+ /** Array of connections between nodes */
77
+ connections?: GraphConnection[];
78
+ /** Inline styles for the graph container */
79
+ graphStyles?: React.CSSProperties;
80
+ /** Offset height for connection lines from node top */
81
+ offsetHeight?: number;
82
+ /** Default starting X coordinate */
83
+ defaultStartX?: number;
84
+ /** Default starting Y coordinate */
85
+ defaultStartY?: number;
86
+ /** Props to pass to the x6 scroller */
87
+ scrollerProps?: Record<string, unknown>;
88
+ /** CSS class name for the scroller */
89
+ scrollClassName?: string;
90
+ /** Inline styles for the container wrapper */
91
+ containerStyles?: React.CSSProperties;
92
+ /** Color for connection lines */
93
+ lineStrokeColor?: string;
94
+ /** Default width for each node element */
95
+ defaultEleWidth?: number;
96
+ /** Default distance between node elements */
97
+ defaultEleDistance?: number;
98
+ /** Offset distance for reverse connection lines */
99
+ offsetLineDistance?: number;
100
+ /** Props to apply to forward connections */
101
+ forwardConnProps?: Record<string, unknown>;
102
+ /** Props to apply to reverse connections */
103
+ reverseConnProps?: Record<string, unknown>;
104
+ /** Whether to allow tooltips on forward arrows */
105
+ allowForwardArrowTooltip?: boolean;
106
+ /** Whether to allow tooltips on reverse arrows */
107
+ allowReverseArrowTooltip?: boolean;
108
+ }
109
+ /**
110
+ * Reference type for the graph instance
111
+ */
112
+ export type GraphRef = React.MutableRefObject<Graph | null>;
113
+ /**
114
+ * Options for TooltipTool
115
+ */
116
+ export interface TooltipToolOptions {
117
+ /** Tooltip text content */
118
+ tooltip?: string;
119
+ }
120
+ /**
121
+ * Type for x6 Graph instance methods used by TooltipTool
122
+ */
123
+ export interface GraphInstance {
124
+ /** Convert client coordinates to graph coordinates */
125
+ clientToGraph: (x: number, y: number) => {
126
+ x: number;
127
+ y: number;
128
+ };
129
+ }
130
+ /**
131
+ * Type for x6 CellView instance methods used by TooltipTool
132
+ */
133
+ export interface CellViewInstance {
134
+ /** Register event handler */
135
+ on: (event: string, handler: () => void, context: unknown) => void;
136
+ /** Unregister event handler */
137
+ off: (event: string, handler: () => void) => void;
138
+ }
139
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../components/CapLevelGraphRenderer/types.ts"],"names":[],"mappings":"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"}
@@ -4226,7 +4226,7 @@ var _default = exports["default"] = SvgFile;
4226
4226
 
4227
4227
 
4228
4228
  exports.__esModule = true;
4229
- exports.TIME_UNITS = exports.FORMAT_TOKENS = void 0;
4229
+ exports.TIME_UNITS = exports.FORMAT_TOKENS = exports.DEFAULT_TIMEZONE = void 0;
4230
4230
  exports.dayjsToMoment = dayjsToMoment;
4231
4231
  exports["default"] = void 0;
4232
4232
  exports.hasMomentTimezoneSupport = hasMomentTimezoneSupport;
@@ -4234,6 +4234,7 @@ exports.isDayjsObject = isDayjsObject;
4234
4234
  exports.isMomentObject = isMomentObject;
4235
4235
  exports.momentToDayjs = momentToDayjs;
4236
4236
  exports.normalizeDateValue = normalizeDateValue;
4237
+ exports.toDayjsInTimezone = toDayjsInTimezone;
4237
4238
  var _dayjs = _interopRequireDefault(__webpack_require__(87695));
4238
4239
  var _advancedFormat = _interopRequireDefault(__webpack_require__(96833));
4239
4240
  var _customParseFormat = _interopRequireDefault(__webpack_require__(2825));
@@ -4345,7 +4346,23 @@ if (!tzIsCallable) {
4345
4346
  if (_dayjs.default.isDayjs(date)) {
4346
4347
  return date.tz(tzName);
4347
4348
  }
4348
- return (0, _dayjs.default)(date).tz(tzName);
4349
+ // For strings/Dates: interpret the date/time values as being IN the target timezone
4350
+ // (matching moment.tz(string, tz) semantics). dayjs(date).tz(tz) is wrong because
4351
+ // dayjs(date) anchors to the system local timezone, so .tz() converts FROM local TO tz.
4352
+ // Instead: parse as UTC to get raw date/time values, compute the target timezone's offset,
4353
+ // then adjust the UTC timestamp so .tz() produces the intended local time.
4354
+ try {
4355
+ // Validate timezone is a real IANA timezone before applying the offset correction
4356
+ Intl.DateTimeFormat(undefined, {
4357
+ timeZone: tzName
4358
+ });
4359
+ } catch (_unused) {
4360
+ // Invalid timezone — fall back to local time
4361
+ return (0, _dayjs.default)(date);
4362
+ }
4363
+ const asUtc = _dayjs.default.utc(date);
4364
+ const tzOffset = asUtc.tz(tzName).utcOffset(); // target tz offset in minutes
4365
+ return _dayjs.default.utc(asUtc.valueOf() - tzOffset * 60000).tz(tzName);
4349
4366
  } catch (error) {
4350
4367
  // If timezone is invalid, log error and fall back to local time
4351
4368
  logDevError("dayjs.tz: Invalid timezone \"" + tzName + "\"", error);
@@ -4422,6 +4439,8 @@ const FORMAT_TOKENS = exports.FORMAT_TOKENS = {
4422
4439
  MONTH_FULL: 'MMMM',
4423
4440
  YEAR: 'YYYY',
4424
4441
  YEAR_SHORT: 'YY',
4442
+ // Cap UI datetime picker format (DD-MM-YYYY | HH:mm)
4443
+ DATE_TIME: 'DD-MM-YYYY | HH:mm',
4425
4444
  // Localized formats
4426
4445
  DATE_LOCALIZED_SHORT: 'l',
4427
4446
  DATETIME_LOCALIZED_SHORT: 'll',
@@ -4432,6 +4451,7 @@ const FORMAT_TOKENS = exports.FORMAT_TOKENS = {
4432
4451
  DATETIME_LOCALIZED_LONG_TIME: 'LLL',
4433
4452
  DATETIME_LOCALIZED_LONG_TIME_WEEKDAY: 'LLLL'
4434
4453
  };
4454
+ const DEFAULT_TIMEZONE = exports.DEFAULT_TIMEZONE = 'Asia/Kolkata';
4435
4455
  function logDevError(message, error) {
4436
4456
  if (false) // removed by dead control flow
4437
4457
  {}
@@ -4512,7 +4532,10 @@ function momentToDayjs(value) {
4512
4532
  const tz = value.tz();
4513
4533
  if (tz) {
4514
4534
  // Has a named timezone - preserve it
4515
- dayjsObj = (0, _dayjs.default)(date).tz(tz);
4535
+ // dayjs.utc(date) is required here: dayjs(date) anchors to the system local timezone,
4536
+ // causing .tz() to only re-label without converting hours. dayjs.utc(date) creates a
4537
+ // UTC-mode dayjs, which .tz() correctly converts to the target timezone for display.
4538
+ dayjsObj = _dayjs.default.utc(date).tz(tz);
4516
4539
 
4517
4540
  // WORKAROUND: dayjs-timezone-iana-plugin doesn't persist timezone name in standard way
4518
4541
  // Store it manually in $x for round-trip conversion fidelity
@@ -4565,6 +4588,35 @@ function momentToDayjs(value) {
4565
4588
  return null;
4566
4589
  }
4567
4590
 
4591
+ /**
4592
+ * Converts any supported date value (Moment, Day.js, string, Date) to a Day.js object
4593
+ * in the specified timezone. This is the recommended single entry point for timezone-safe
4594
+ * date conversion — it handles moment-to-dayjs conversion and timezone application in one step,
4595
+ * avoiding the double-offset bug in dayjs-timezone-iana-plugin.
4596
+ *
4597
+ * @param value - Moment, Day.js, string, Date, or null/undefined
4598
+ * @param timezone - Target IANA timezone (e.g., 'Asia/Kolkata', 'America/New_York')
4599
+ * @returns Day.js object in the target timezone, or null if invalid
4600
+ *
4601
+ * @example
4602
+ * toDayjsInTimezone(moment.tz('2025-04-21 00:00', 'Asia/Kolkata'), 'Asia/Kolkata');
4603
+ * // Returns dayjs representing 2025-04-21 00:00 IST
4604
+ *
4605
+ * @example
4606
+ * toDayjsInTimezone(moment.tz('2025-04-21 00:00', 'UTC'), 'Asia/Kolkata');
4607
+ * // Returns dayjs representing 2025-04-21 05:30 IST
4608
+ */
4609
+ function toDayjsInTimezone(value, timezone) {
4610
+ const dayjsValue = momentToDayjs(value);
4611
+ if (!dayjsValue) return null;
4612
+
4613
+ // Convert via UTC to avoid the double-offset bug in dayjs-timezone-iana-plugin:
4614
+ // calling .tz() on a dayjs that already has a non-zero utcOffset corrupts the value.
4615
+ // Going through .toDate() → dayjs.utc() gives us a clean UTC-mode dayjs that .tz()
4616
+ // correctly converts to the target timezone.
4617
+ return _dayjs.default.utc(dayjsValue.toDate()).tz(timezone);
4618
+ }
4619
+
4568
4620
  /**
4569
4621
  * Converts a Day.js object to Moment.js, preserving timezone and locale information.
4570
4622
  *