ngxsmk-datepicker 2.2.13 → 2.2.15

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.
package/docs/API.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  This document describes the stable public API of ngxsmk-datepicker with comprehensive real-world examples. APIs marked as **stable** are guaranteed to remain backward-compatible within the same major version. APIs marked as **experimental** may change in future releases.
4
4
 
5
- **Version**: 2.2.13+ | **Last updated**: March 21, 2026
5
+ **Version**: 2.2.15+ | **Last updated**: March 21, 2026
6
6
 
7
7
  ## Stable vs experimental
8
8
 
@@ -1,6 +1,6 @@
1
1
  # Version Compatibility Matrix
2
2
 
3
- **Last updated:** May 6, 2026 - **Current stable:** v2.2.13
3
+ **Last updated:** May 19, 2026 - **Current stable:** v2.2.15
4
4
 
5
5
  This document provides comprehensive compatibility information for `ngxsmk-datepicker` across different Angular versions, Zone.js configurations, and SSR/CSR setups.
6
6
 
@@ -250,6 +250,18 @@ export class MyComponent {
250
250
  }
251
251
  ```
252
252
 
253
+ ## 🧩 Shadow DOM & Web Components Compatibility
254
+
255
+ `ngxsmk-datepicker` is fully compatible with **Shadow DOM encapsulation** (`ViewEncapsulation.ShadowDom`) and deployment as an **Angular Element (Custom Web Component)** inside other frameworks (React, Vue, etc.).
256
+
257
+ ### Composed Path Event Retargeting
258
+ When components are loaded inside a Shadow root, the browser retargets event targets when they bubble outside of the Shadow boundary. Standard `.contains()` checks on the host node will fail when checking external interaction listeners (e.g. document close listeners).
259
+
260
+ `ngxsmk-datepicker` natively handles this by tracking event composed paths:
261
+ * Inspects `event.composedPath()` when available to accurately check event origins inside Shadow DOM trees.
262
+ * Falls back to standard light DOM `.contains(target)` when composed paths are not supported by the environment.
263
+ * Supported across both the primary Datepicker component and Custom Select dropdown components.
264
+
253
265
  ## 🔧 Feature Compatibility Matrix
254
266
 
255
267
  ### By Angular Version
@@ -258,6 +270,7 @@ export class MyComponent {
258
270
  |---------|------------|-----------|------------|------------|-------------|
259
271
  | **Standalone Component** | ✅ | ✅ | ✅ | ✅ | ✅ |
260
272
  | **Signals** | ✅ | ✅ | ✅ | ✅ | ✅ |
273
+ | **Shadow DOM Support** | ✅ | ✅ | ✅ | ✅ | ✅ |
261
274
  | **Computed Signals** | ✅ | ✅ | ✅ | ✅ | ✅ |
262
275
  | **Effects** | ⚠️ Limited | ✅ | ✅ | ✅ | ✅ |
263
276
  | **Signal Forms** | ❌ | ❌ | ❌ | ❌ | ✅ |
@@ -1,6 +1,6 @@
1
1
  # Integration Guides
2
2
 
3
- **Last updated:** May 6, 2026 - **Current stable:** v2.2.13
3
+ **Last updated:** May 19, 2026 - **Current stable:** v2.2.15
4
4
 
5
5
  This document provides integration examples for using ngxsmk-datepicker with popular frameworks and libraries.
6
6
 
@@ -1,6 +1,6 @@
1
1
  # Ionic Framework Integration Guide
2
2
 
3
- **Last updated:** May 6, 2026 - **Current stable:** v2.2.13
3
+ **Last updated:** May 19, 2026 - **Current stable:** v2.2.15
4
4
 
5
5
  This guide provides step-by-step instructions for integrating ngxsmk-datepicker with Ionic Angular applications.
6
6
 
@@ -1,6 +1,6 @@
1
1
  # Ionic Integration Testing Guide
2
2
 
3
- **Last updated:** May 6, 2026 - **Current stable:** v2.2.13
3
+ **Last updated:** May 19, 2026 - **Current stable:** v2.2.15
4
4
 
5
5
  This document provides comprehensive testing instructions for verifying ngxsmk-datepicker compatibility with Ionic Framework.
6
6
 
@@ -1,6 +1,6 @@
1
1
  # Locale Packs & i18n Contributor Guide
2
2
 
3
- **Last updated:** May 6, 2026 - **Current stable:** v2.2.13
3
+ **Last updated:** May 19, 2026 - **Current stable:** v2.2.15
4
4
 
5
5
  Guide for adding locale support and contributing translations to ngxsmk-datepicker.
6
6
 
@@ -1,6 +1,6 @@
1
1
  # Plugin Architecture
2
2
 
3
- **Last updated:** May 6, 2026 - **Current stable:** v2.2.13
3
+ **Last updated:** May 19, 2026 - **Current stable:** v2.2.15
4
4
 
5
5
  ngxsmk-datepicker features a powerful **plugin architecture** that allows you to extend and customize the component's behavior without modifying its core code. This architecture is built on a **hook-based system** that provides extension points throughout the component's lifecycle.
6
6
 
package/docs/SEO.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # SEO Optimization Guide
2
2
 
3
- **Last updated:** May 6, 2026 - **Current stable:** v2.2.13
3
+ **Last updated:** May 19, 2026 - **Current stable:** v2.2.15
4
4
 
5
5
  This document outlines the SEO optimizations implemented for ngxsmk-datepicker to improve search engine visibility and discoverability.
6
6
 
@@ -1,6 +1,6 @@
1
1
  # Server-Side Rendering (SSR) Example
2
2
 
3
- **Last updated:** May 6, 2026 - **Current stable:** v2.2.13
3
+ **Last updated:** May 19, 2026 - **Current stable:** v2.2.15
4
4
 
5
5
  Complete example demonstrating ngxsmk-datepicker with Angular Universal (SSR).
6
6
 
@@ -1,6 +1,6 @@
1
1
  # Theme Tokens & CSS Custom Properties
2
2
 
3
- **Last updated:** May 6, 2026 - **Current stable:** v2.2.13
3
+ **Last updated:** May 19, 2026 - **Current stable:** v2.2.15
4
4
 
5
5
  Complete reference for all CSS custom properties (CSS variables) available in ngxsmk-datepicker.
6
6
 
package/docs/TIMEZONE.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Timezone Support
2
2
 
3
- **Last updated:** May 6, 2026 - **Current stable:** v2.2.13
3
+ **Last updated:** May 19, 2026 - **Current stable:** v2.2.15
4
4
 
5
5
  ## Overview
6
6
 
@@ -1,6 +1,6 @@
1
1
  # Extension Points and Hooks
2
2
 
3
- **Last updated:** May 6, 2026 - **Current stable:** v2.2.13
3
+ **Last updated:** May 19, 2026 - **Current stable:** v2.2.15
4
4
 
5
5
  ngxsmk-datepicker provides comprehensive extension points through the `hooks` input, allowing you to customize rendering, validation, keyboard shortcuts, formatting, and event handling.
6
6
 
@@ -1,6 +1,6 @@
1
1
  # Signal Forms Integration
2
2
 
3
- **Last updated:** May 6, 2026 - **Current stable:** v2.2.13
3
+ **Last updated:** May 19, 2026 - **Current stable:** v2.2.15
4
4
 
5
5
  This guide covers using ngxsmk-datepicker with Angular 21+ Signal Forms API.
6
6
 
package/docs/signals.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Signals Integration Guide
2
2
 
3
- **Last updated:** May 6, 2026 - **Current stable:** v2.2.13
3
+ **Last updated:** May 19, 2026 - **Current stable:** v2.2.15
4
4
 
5
5
  ngxsmk-datepicker is fully compatible with Angular Signals, providing seamless integration with both traditional reactive forms and modern signal-based patterns.
6
6
 
package/docs/ssr.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Server-Side Rendering (SSR) Guide
2
2
 
3
- **Last updated:** May 6, 2026 - **Current stable:** v2.2.13
3
+ **Last updated:** May 19, 2026 - **Current stable:** v2.2.15
4
4
 
5
5
  ngxsmk-datepicker is fully compatible with Angular Universal and server-side rendering. This guide covers SSR setup, best practices, and troubleshooting.
6
6
 
@@ -1012,26 +1012,41 @@ class CustomSelectComponent {
1012
1012
  }
1013
1013
  onDocumentClick(event) {
1014
1014
  if (this.isBrowser) {
1015
- const target = event.target;
1016
- if (target && !this.elementRef.nativeElement.contains(target)) {
1017
- this.isOpen = false;
1015
+ if (event.composedPath && typeof event.composedPath === 'function') {
1016
+ const path = event.composedPath();
1017
+ if (!path.includes(this.elementRef.nativeElement)) {
1018
+ this.isOpen = false;
1019
+ }
1018
1020
  }
1019
- // Logic removed: forcing closure when calendar is open prevented dropdown from opening
1020
- }
1021
- }
1022
- onDocumentTouchStart(event) {
1023
- // On mobile, close dropdown when calendar opens
1024
- if (this.isBrowser && this.isOpen) {
1025
- const calendarBackdrop = this.document.querySelector('.ngxsmk-backdrop');
1026
- if (calendarBackdrop) {
1021
+ else {
1027
1022
  const target = event.target;
1028
- // Only close if touch is outside the dropdown
1029
1023
  if (target && !this.elementRef.nativeElement.contains(target)) {
1030
1024
  this.isOpen = false;
1031
1025
  }
1032
1026
  }
1033
1027
  }
1034
1028
  }
1029
+ onDocumentTouchStart(event) {
1030
+ // On mobile, close dropdown when calendar opens
1031
+ if (!this.isBrowser || !this.isOpen)
1032
+ return;
1033
+ const calendarBackdrop = this.document.querySelector('.ngxsmk-backdrop');
1034
+ if (!calendarBackdrop)
1035
+ return;
1036
+ if (event.composedPath && typeof event.composedPath === 'function') {
1037
+ const path = event.composedPath();
1038
+ if (!path.includes(this.elementRef.nativeElement)) {
1039
+ this.isOpen = false;
1040
+ }
1041
+ }
1042
+ else {
1043
+ const target = event.target;
1044
+ // Only close if touch is outside the dropdown
1045
+ if (target && !this.elementRef.nativeElement.contains(target)) {
1046
+ this.isOpen = false;
1047
+ }
1048
+ }
1049
+ }
1035
1050
  get displayValue() {
1036
1051
  const selectedOption = this.options.find((opt) => opt.value === this.value);
1037
1052
  return selectedOption ? selectedOption.label : '';
@@ -8886,17 +8901,26 @@ class NgxsmkDatepickerComponent {
8886
8901
  * @param calendarMonth - The calendar month object
8887
8902
  * @returns Unique identifier combining year and month
8888
8903
  */
8889
- /**
8890
- * Checks if a DOM node is contained within this datepicker instance,
8891
- * including its input group and any portaled popover content.
8892
- *
8893
- * @param target - The node to check
8894
- * @returns True if the node is inside this datepicker's DOM tree
8895
- */
8896
- containsNode(target) {
8897
- if (!this.isBrowser || !target) {
8898
- return false;
8904
+ containsNodeViaComposedPath(path) {
8905
+ const nativeElement = this.elementRef?.nativeElement;
8906
+ if (nativeElement && path.includes(nativeElement)) {
8907
+ return true;
8908
+ }
8909
+ // Check portaled popover content if it exists
8910
+ if (this._shouldAppendToBody && this.portalViewRef) {
8911
+ if (this.portalViewRef.rootNodes.some((node) => path.includes(node))) {
8912
+ return true;
8913
+ }
8914
+ }
8915
+ // Check inline popover Container (secondary fallback)
8916
+ if (this.popoverContainer?.nativeElement) {
8917
+ if (path.includes(this.popoverContainer.nativeElement)) {
8918
+ return true;
8919
+ }
8899
8920
  }
8921
+ return false;
8922
+ }
8923
+ containsNodeViaDOM(target) {
8900
8924
  const nativeElement = this.elementRef?.nativeElement;
8901
8925
  if (nativeElement && (nativeElement === target || nativeElement.contains(target))) {
8902
8926
  return true;
@@ -8914,14 +8938,31 @@ class NgxsmkDatepickerComponent {
8914
8938
  }
8915
8939
  return false;
8916
8940
  }
8941
+ /**
8942
+ * Checks if a DOM node is contained within this datepicker instance,
8943
+ * including its input group and any portaled popover content.
8944
+ *
8945
+ * @param target - The node to check
8946
+ * @returns True if the node is inside this datepicker's DOM tree
8947
+ */
8948
+ containsNode(target, event) {
8949
+ if (!this.isBrowser || !target) {
8950
+ return false;
8951
+ }
8952
+ // Support shadow DOM by checking composedPath if event is provided
8953
+ if (event && typeof event.composedPath === 'function') {
8954
+ return this.containsNodeViaComposedPath(event.composedPath());
8955
+ }
8956
+ return this.containsNodeViaDOM(target);
8957
+ }
8917
8958
  /** Shared logic for closing calendar when user interacts outside (click or touch). */
8918
- tryCloseCalendarOnOutsideInteraction(target) {
8919
- if (this.containsNode(target))
8959
+ tryCloseCalendarOnOutsideInteraction(target, event) {
8960
+ if (this.containsNode(target, event))
8920
8961
  return;
8921
8962
  const isInsideOtherDatepicker = Array.from(NgxsmkDatepickerComponent._allInstances).some((instance) => {
8922
8963
  if (instance === this || instance.isInlineMode)
8923
8964
  return false;
8924
- return instance.containsNode(target);
8965
+ return instance.containsNode(target, event);
8925
8966
  });
8926
8967
  if (isInsideOtherDatepicker || !this.isCalendarOpen)
8927
8968
  return;
@@ -8945,7 +8986,7 @@ class NgxsmkDatepickerComponent {
8945
8986
  const target = event.target;
8946
8987
  if (!target)
8947
8988
  return;
8948
- this.tryCloseCalendarOnOutsideInteraction(target);
8989
+ this.tryCloseCalendarOnOutsideInteraction(target, event);
8949
8990
  }
8950
8991
  onTouchStart(event) {
8951
8992
  if (this.disabled || this.isInlineMode) {
package/package.json CHANGED
@@ -1,6 +1,7 @@
1
1
  {
2
2
  "name": "ngxsmk-datepicker",
3
- "version": "2.2.13",
3
+ "version": "2.2.15",
4
+ "description": "Lightweight, accessible date and range picker for Angular 17+. Standalone component, Signals, SSR and zoneless-ready, Luxon-based i18n and timezones.",
4
5
  "author": {
5
6
  "name": "Sachin Dilshan",
6
7
  "url": "https://www.sachindilshan.com/"
@@ -59,15 +60,24 @@
59
60
  "date-range-picker",
60
61
  "calendar",
61
62
  "standalone-component",
63
+ "reactive-forms",
64
+ "luxon",
62
65
  "angular-17",
63
66
  "angular-18",
64
67
  "angular-19",
65
68
  "angular-20",
66
69
  "angular-21",
70
+ "angular-22",
71
+ "angular-23",
67
72
  "typescript",
68
73
  "date-selection",
69
74
  "i18n",
70
- "localization"
75
+ "localization",
76
+ "ssr",
77
+ "angular-universal",
78
+ "zoneless",
79
+ "accessibility",
80
+ "a11y"
71
81
  ],
72
82
  "optimization": {
73
83
  "treeShaking": true,
@@ -1304,6 +1304,8 @@ declare class NgxsmkDatepickerComponent implements OnInit, OnChanges, OnDestroy,
1304
1304
  * @param calendarMonth - The calendar month object
1305
1305
  * @returns Unique identifier combining year and month
1306
1306
  */
1307
+ private containsNodeViaComposedPath;
1308
+ private containsNodeViaDOM;
1307
1309
  /**
1308
1310
  * Checks if a DOM node is contained within this datepicker instance,
1309
1311
  * including its input group and any portaled popover content.
@@ -1311,7 +1313,7 @@ declare class NgxsmkDatepickerComponent implements OnInit, OnChanges, OnDestroy,
1311
1313
  * @param target - The node to check
1312
1314
  * @returns True if the node is inside this datepicker's DOM tree
1313
1315
  */
1314
- containsNode(target: Node | null): boolean;
1316
+ containsNode(target: Node | null, event?: UIEvent): boolean;
1315
1317
  /** Shared logic for closing calendar when user interacts outside (click or touch). */
1316
1318
  private tryCloseCalendarOnOutsideInteraction;
1317
1319
  onDocumentClick(event: MouseEvent | TouchEvent): void;