@festo-ui/angular 10.0.1-dev.852 → 10.1.0-dev.856

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.
@@ -4440,6 +4440,11 @@ class FngFlatpickrComponent {
4440
4440
  this.dateChange.emit(dateOption[0]);
4441
4441
  }
4442
4442
  }
4443
+ setDate(date, triggerChange = true, dateFormat) {
4444
+ if (this.datePicker) {
4445
+ this.datePicker.setDate(date, triggerChange, dateFormat);
4446
+ }
4447
+ }
4443
4448
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: FngFlatpickrComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
4444
4449
  static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.15", type: FngFlatpickrComponent, isStandalone: true, selector: "fng-flatpickr", inputs: { date: "date", options: "options" }, outputs: { dateChange: "dateChange" }, viewQueries: [{ propertyName: "datePickerRef", first: true, predicate: ["datePicker"], descendants: true, static: true }], ngImport: i0, template: "<div class=\"fng-flatpickr\">\r\n <div #datePicker></div>\r\n</div>\r\n", encapsulation: i0.ViewEncapsulation.None }); }
4445
4450
  }
@@ -4478,6 +4483,42 @@ class FngDatePickerComponent {
4478
4483
  set disabled(value) {
4479
4484
  this.innerDisabled = coerceBooleanProperty(value);
4480
4485
  }
4486
+ /**
4487
+ * @deprecated Use the `formatDate` input instead.
4488
+ * This property is kept for backward compatibility and will be removed in version 11.0.0.
4489
+ * Migration: Replace `format` with a custom `formatDate` function.
4490
+ */
4491
+ set format(value) {
4492
+ this._deprecatedFormat = value;
4493
+ if (value) {
4494
+ console.warn('FngDatePickerComponent: The "format" input is deprecated and will be removed in version 11.0.0. ' +
4495
+ 'Use the "formatDate" input instead to provide a custom formatting function.');
4496
+ }
4497
+ }
4498
+ /**
4499
+ * @deprecated Use Angular's built-in locale support with injection tokens instead.
4500
+ * This property is kept for backward compatibility and will be removed in version 11.0.0.
4501
+ * Migration: Use LOCALE_ID injection token or pass locale via the `formatDate` function.
4502
+ */
4503
+ set locale(value) {
4504
+ this._deprecatedLocale = value;
4505
+ if (value) {
4506
+ console.warn('FngDatePickerComponent: The "locale" input is deprecated and will be removed in version 11.0.0. ' +
4507
+ 'Use Angular\'s LOCALE_ID injection token or configure locale in your formatDate function instead.');
4508
+ }
4509
+ }
4510
+ /**
4511
+ * @deprecated Timezone handling is now delegated to the JavaScript Date object and platform implementation.
4512
+ * This property is kept for backward compatibility and will be removed in version 11.0.0.
4513
+ * Migration: Timezone conversion should be handled in your application layer or via the `formatDate` function.
4514
+ */
4515
+ set timezone(value) {
4516
+ this._deprecatedTimezone = value;
4517
+ if (value) {
4518
+ console.warn('FngDatePickerComponent: The "timezone" input is deprecated and will be removed in version 11.0.0. ' +
4519
+ 'Timezone handling should be managed at the application layer using libraries like date-fns or day.js.');
4520
+ }
4521
+ }
4481
4522
  get required() {
4482
4523
  return this.innerRequired;
4483
4524
  }
@@ -4488,10 +4529,12 @@ class FngDatePickerComponent {
4488
4529
  if (!this.value) {
4489
4530
  return '';
4490
4531
  }
4491
- const format = this.format || 'mediumDate';
4492
- const locale = this.locale || this.localeDefault;
4493
- const timezone = this.timezone;
4494
- return formatDate(this.value, format, locale, timezone);
4532
+ return this.formatDate(this.value);
4533
+ }
4534
+ static { this.DATE_PATTERN = /^(\d{1,4})[/\-.\s](\d{1,2})[/\-.\s](\d{1,4})$/; }
4535
+ /** Expand 2-digit years: 0–99 → 2000–2099 */
4536
+ static expandYear(y) {
4537
+ return y >= 0 && y < 100 ? y + 2000 : y;
4495
4538
  }
4496
4539
  constructor(overlay, localeDefault, cd) {
4497
4540
  this.overlay = overlay;
@@ -4499,7 +4542,51 @@ class FngDatePickerComponent {
4499
4542
  this.cd = cd;
4500
4543
  this.innerDisabled = false;
4501
4544
  this.options = {};
4545
+ /**
4546
+ * Function to format the date for display in the input field.
4547
+ * Defaults to using the application's configured locale (via LOCALE_ID) for consistent, predictable formatting.
4548
+ *
4549
+ * @default Uses `Intl.DateTimeFormat(localeId)` where localeId is the injected LOCALE_ID token.
4550
+ * This ensures consistent rendering across all users and browser/OS locales.
4551
+ *
4552
+ * @example
4553
+ * // Custom format with specific options (e.g., short date format)
4554
+ * formatDate = (date: Date) => {
4555
+ * return new Intl.DateTimeFormat('en-US', {
4556
+ * year: 'numeric',
4557
+ * month: '2-digit',
4558
+ * day: '2-digit'
4559
+ * }).format(date);
4560
+ * }
4561
+ *
4562
+ * @example
4563
+ * // Custom format using date-fns
4564
+ * formatDate = (date: Date) => {
4565
+ * return format(date, 'dd/MM/yyyy', { locale: enUS });
4566
+ * }
4567
+ *
4568
+ * @example
4569
+ * // Custom format using day.js
4570
+ * formatDate = (date: Date) => {
4571
+ * return dayjs(date).locale('en-US').format('DD/MM/YYYY');
4572
+ * }
4573
+ */
4574
+ this.formatDate = (date) => {
4575
+ if (!date || !(date instanceof Date) || isNaN(date.getTime())) {
4576
+ return '';
4577
+ }
4578
+ const locale = this._deprecatedLocale || this.localeDefault;
4579
+ const options = {};
4580
+ if (this._deprecatedTimezone) {
4581
+ options.timeZone = this._deprecatedTimezone;
4582
+ }
4583
+ return new Intl.DateTimeFormat(locale, options).format(date);
4584
+ };
4502
4585
  this.innerRequired = false;
4586
+ /** If true, allows manual input in the date picker field */
4587
+ this.allowManualInput = false;
4588
+ /** If true, opening the calendar is triggered on input click; if false, only the calendar icon opens it */
4589
+ this.openOnInputClick = true;
4503
4590
  this.display = 'block';
4504
4591
  this.innerValue = new Date();
4505
4592
  this.complete = new Subject();
@@ -4590,19 +4677,144 @@ class FngDatePickerComponent {
4590
4677
  this.datePickerRef.dispose();
4591
4678
  this.datePickerRef = undefined;
4592
4679
  }
4680
+ if (this.datePicker != null) {
4681
+ this.datePicker = undefined;
4682
+ }
4593
4683
  if (this.complete != null) {
4594
4684
  this.complete.next(true);
4595
4685
  this.complete.complete();
4596
4686
  }
4597
4687
  }
4688
+ onDateInputBlur() {
4689
+ if (this.allowManualInput && this.dateInput?.nativeElement) {
4690
+ const raw = this.dateInput.nativeElement.value;
4691
+ if (raw) {
4692
+ // Only parse if calendar is NOT open - flatpickr handles it when open
4693
+ if (!this.datePicker) {
4694
+ const parsedDate = this.parseDate ? this.parseDate(raw) : this.defaultParseDate(raw);
4695
+ if (parsedDate && !isNaN(parsedDate.getTime())) {
4696
+ this.value = parsedDate;
4697
+ }
4698
+ else {
4699
+ // Reset input to last valid value on invalid input
4700
+ this.dateInput.nativeElement.value = this.displayValue;
4701
+ }
4702
+ }
4703
+ }
4704
+ }
4705
+ }
4706
+ /**
4707
+ * Default date parsing implementation using intelligent heuristics.
4708
+ * Tries to guess the date format by analyzing which parts could be day/month/year.
4709
+ * Accepts common separators: / - . and space
4710
+ * Defaults to dd-mm-yyyy when ambiguous.
4711
+ *
4712
+ * This is used as a fallback when no custom parseDate input is provided.
4713
+ * For locale-aware or custom format parsing, provide your own parseDate function.
4714
+ */
4715
+ defaultParseDate(dateString) {
4716
+ const trim = dateString.trim();
4717
+ const match = trim.match(FngDatePickerComponent.DATE_PATTERN);
4718
+ if (!match) {
4719
+ return null;
4720
+ }
4721
+ let part1 = parseInt(match[1], 10);
4722
+ let part2 = parseInt(match[2], 10);
4723
+ let part3 = parseInt(match[3], 10);
4724
+ // Try to determine the format intelligently
4725
+ // If any part is > 31, it's definitely the year
4726
+ let day, month, year;
4727
+ if (part1 > 31) {
4728
+ // Format: yyyy-mm-dd or yyyy-dd-mm
4729
+ year = part1;
4730
+ // Try both interpretations and pick the valid one
4731
+ const attempt1 = new Date(year, part2 - 1, part3);
4732
+ const attempt2 = new Date(year, part3 - 1, part2);
4733
+ if (!isNaN(attempt1.getTime()) && attempt1.getDate() === part3 && attempt1.getMonth() === part2 - 1) {
4734
+ return attempt1;
4735
+ }
4736
+ if (!isNaN(attempt2.getTime()) && attempt2.getDate() === part2 && attempt2.getMonth() === part3 - 1) {
4737
+ return attempt2;
4738
+ }
4739
+ return null;
4740
+ }
4741
+ else if (part3 > 31) {
4742
+ // Format: dd-mm-yyyy or mm-dd-yyyy
4743
+ year = part3;
4744
+ // Try dd-mm-yyyy first (more common internationally)
4745
+ let result = new Date(year, part2 - 1, part1);
4746
+ if (!isNaN(result.getTime()) && result.getDate() === part1 && result.getMonth() === part2 - 1) {
4747
+ return result;
4748
+ }
4749
+ // Then try mm-dd-yyyy (US format)
4750
+ result = new Date(year, part1 - 1, part2);
4751
+ if (!isNaN(result.getTime()) && result.getDate() === part2 && result.getMonth() === part1 - 1) {
4752
+ return result;
4753
+ }
4754
+ return null;
4755
+ }
4756
+ else if (part2 > 12) {
4757
+ // part2 is clearly a day (> 12), so format is part1-day-part3 or similar
4758
+ // Ambiguous between yyyy-dd-mm and mm-yyyy-dd which doesn't make sense
4759
+ // Assume mm-dd-yyyy or dd-mm-yyyy, and since part2 > 12 it's dd, so mm-dd-yyyy
4760
+ month = part1 - 1;
4761
+ day = part2;
4762
+ year = FngDatePickerComponent.expandYear(part3);
4763
+ const result = new Date(year, month, day);
4764
+ if (!isNaN(result.getTime()) && result.getDate() === day && result.getMonth() === month) {
4765
+ return result;
4766
+ }
4767
+ return null;
4768
+ }
4769
+ else if (part1 > 12) {
4770
+ // part1 is clearly a day (> 12), so format is dd-mm-yyyy
4771
+ day = part1;
4772
+ month = part2 - 1;
4773
+ year = FngDatePickerComponent.expandYear(part3);
4774
+ const result = new Date(year, month, day);
4775
+ if (!isNaN(result.getTime()) && result.getDate() === day && result.getMonth() === month) {
4776
+ return result;
4777
+ }
4778
+ return null;
4779
+ }
4780
+ else {
4781
+ // All parts <= 12, ambiguous - try dd-mm-yyyy first (more common)
4782
+ const expandedPart3 = FngDatePickerComponent.expandYear(part3);
4783
+ let result = new Date(expandedPart3, part2 - 1, part1);
4784
+ if (!isNaN(result.getTime()) && result.getDate() === part1 && result.getMonth() === part2 - 1) {
4785
+ return result;
4786
+ }
4787
+ // Then try mm-dd-yyyy
4788
+ result = new Date(expandedPart3, part1 - 1, part2);
4789
+ if (!isNaN(result.getTime()) && result.getDate() === part2 && result.getMonth() === part1 - 1) {
4790
+ return result;
4791
+ }
4792
+ return null;
4793
+ }
4794
+ }
4795
+ onDateInputClick(event) {
4796
+ if (this.allowManualInput && !this.openOnInputClick) {
4797
+ event.preventDefault();
4798
+ event.stopPropagation();
4799
+ }
4800
+ }
4801
+ onDateInputKeyDown(event) {
4802
+ if (this.allowManualInput) {
4803
+ event.stopPropagation();
4804
+ if (event.key === 'Enter') {
4805
+ event.preventDefault();
4806
+ this.onDateInputBlur();
4807
+ }
4808
+ }
4809
+ }
4598
4810
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: FngDatePickerComponent, deps: [{ token: i1$2.Overlay }, { token: LOCALE_ID }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); }
4599
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.15", type: FngDatePickerComponent, isStandalone: true, selector: "fng-date-picker", inputs: { value: "value", disabled: "disabled", hint: "hint", error: "error", options: "options", locale: "locale", format: "format", timezone: "timezone", required: "required", width: "width" }, host: { listeners: { "document:keydown": "hide($event)" }, properties: { "style.width": "this.width", "style.display": "this.display" } }, providers: [
4811
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.15", type: FngDatePickerComponent, isStandalone: true, selector: "fng-date-picker", inputs: { value: "value", disabled: "disabled", hint: "hint", error: "error", options: "options", format: "format", locale: "locale", timezone: "timezone", formatDate: "formatDate", parseDate: "parseDate", required: "required", allowManualInput: "allowManualInput", openOnInputClick: "openOnInputClick", width: "width" }, host: { listeners: { "document:keydown": "hide($event)" }, properties: { "style.width": "this.width", "style.display": "this.display" } }, providers: [
4600
4812
  {
4601
4813
  provide: NG_VALUE_ACCESSOR,
4602
4814
  useExisting: forwardRef(() => FngDatePickerComponent),
4603
4815
  multi: true
4604
4816
  }
4605
- ], viewQueries: [{ propertyName: "connector", first: true, predicate: ["connector"], descendants: true, static: true }], ngImport: i0, template: "<label #connector class=\"fng-date-picker fwe-input-text fwe-input-text-icon\" (click)=\"toggle($event)\">\n <i\n class=\"fng-icon-svg fng-icon-svg--time-calendar\"\n [class.fwe-color-hero]=\"datePickerRef != null\"\n [class.fwe-color-control-disabled]=\"disabled\"\n ></i>\n <input\n aria-label=\"picked date\"\n type=\"text\"\n readonly\n [required]=\"required === true || null\"\n [class.fwe-border-hero]=\"datePickerRef != null\"\n [value]=\"displayValue\"\n [disabled]=\"disabled\"\n />\n <span class=\"fwe-input-text-label\"><ng-content></ng-content></span>\n @if (hint) {\n <span class=\"fwe-input-text-info\">{{ hint }}</span>\n }\n @if (error) {\n <span class=\"fwe-input-text-invalid\">{{ error }}</span>\n }\n </label>\n", styles: [".fwe-border-hero{border-color:var(--fwe-hero)!important}\n"], encapsulation: i0.ViewEncapsulation.None }); }
4817
+ ], viewQueries: [{ propertyName: "connector", first: true, predicate: ["connector"], descendants: true, static: true }, { propertyName: "dateInput", first: true, predicate: ["dateInput"], descendants: true }], ngImport: i0, template: "<label\n #connector\n class=\"fng-date-picker fwe-input-text fwe-input-text-icon\"\n [class.fng-date-picker--editable]=\"allowManualInput\"\n (click)=\"openOnInputClick ? toggle($event) : null\"\n>\n <i\n class=\"fng-icon-svg fng-icon-svg--time-calendar\"\n [class.fwe-color-hero]=\"datePickerRef != null\"\n [class.fwe-color-control-disabled]=\"disabled\"\n (click)=\"$event.stopPropagation(); toggle($event)\"\n ></i>\n <input\n #dateInput\n aria-label=\"picked date\"\n type=\"text\"\n [readonly]=\"!allowManualInput\"\n [required]=\"required === true || null\"\n [class.fwe-border-hero]=\"datePickerRef != null\"\n [value]=\"displayValue\"\n [disabled]=\"disabled\"\n (click)=\"onDateInputClick($event)\"\n (keydown)=\"onDateInputKeyDown($event)\"\n (blur)=\"onDateInputBlur()\"\n />\n <span class=\"fwe-input-text-label\"><ng-content></ng-content></span>\n @if (hint) {\n <span class=\"fwe-input-text-info\">{{ hint }}</span>\n }\n @if (error) {\n <span class=\"fwe-input-text-invalid\">{{ error }}</span>\n }\n</label>\n", styles: [".fwe-border-hero{border-color:var(--fwe-hero)!important}.fng-date-picker,.fng-date-picker i,.fng-date-picker input{cursor:pointer}.fng-date-picker--editable input{cursor:text}\n"], encapsulation: i0.ViewEncapsulation.None }); }
4606
4818
  }
4607
4819
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: FngDatePickerComponent, decorators: [{
4608
4820
  type: Component,
@@ -4612,7 +4824,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImpo
4612
4824
  useExisting: forwardRef(() => FngDatePickerComponent),
4613
4825
  multi: true
4614
4826
  }
4615
- ], encapsulation: ViewEncapsulation.None, template: "<label #connector class=\"fng-date-picker fwe-input-text fwe-input-text-icon\" (click)=\"toggle($event)\">\n <i\n class=\"fng-icon-svg fng-icon-svg--time-calendar\"\n [class.fwe-color-hero]=\"datePickerRef != null\"\n [class.fwe-color-control-disabled]=\"disabled\"\n ></i>\n <input\n aria-label=\"picked date\"\n type=\"text\"\n readonly\n [required]=\"required === true || null\"\n [class.fwe-border-hero]=\"datePickerRef != null\"\n [value]=\"displayValue\"\n [disabled]=\"disabled\"\n />\n <span class=\"fwe-input-text-label\"><ng-content></ng-content></span>\n @if (hint) {\n <span class=\"fwe-input-text-info\">{{ hint }}</span>\n }\n @if (error) {\n <span class=\"fwe-input-text-invalid\">{{ error }}</span>\n }\n </label>\n", styles: [".fwe-border-hero{border-color:var(--fwe-hero)!important}\n"] }]
4827
+ ], encapsulation: ViewEncapsulation.None, template: "<label\n #connector\n class=\"fng-date-picker fwe-input-text fwe-input-text-icon\"\n [class.fng-date-picker--editable]=\"allowManualInput\"\n (click)=\"openOnInputClick ? toggle($event) : null\"\n>\n <i\n class=\"fng-icon-svg fng-icon-svg--time-calendar\"\n [class.fwe-color-hero]=\"datePickerRef != null\"\n [class.fwe-color-control-disabled]=\"disabled\"\n (click)=\"$event.stopPropagation(); toggle($event)\"\n ></i>\n <input\n #dateInput\n aria-label=\"picked date\"\n type=\"text\"\n [readonly]=\"!allowManualInput\"\n [required]=\"required === true || null\"\n [class.fwe-border-hero]=\"datePickerRef != null\"\n [value]=\"displayValue\"\n [disabled]=\"disabled\"\n (click)=\"onDateInputClick($event)\"\n (keydown)=\"onDateInputKeyDown($event)\"\n (blur)=\"onDateInputBlur()\"\n />\n <span class=\"fwe-input-text-label\"><ng-content></ng-content></span>\n @if (hint) {\n <span class=\"fwe-input-text-info\">{{ hint }}</span>\n }\n @if (error) {\n <span class=\"fwe-input-text-invalid\">{{ error }}</span>\n }\n</label>\n", styles: [".fwe-border-hero{border-color:var(--fwe-hero)!important}.fng-date-picker,.fng-date-picker i,.fng-date-picker input{cursor:pointer}.fng-date-picker--editable input{cursor:text}\n"] }]
4616
4828
  }], ctorParameters: () => [{ type: i1$2.Overlay }, { type: undefined, decorators: [{
4617
4829
  type: Inject,
4618
4830
  args: [LOCALE_ID]
@@ -4626,17 +4838,28 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImpo
4626
4838
  type: Input
4627
4839
  }], options: [{
4628
4840
  type: Input
4629
- }], locale: [{
4630
- type: Input
4631
4841
  }], format: [{
4632
4842
  type: Input
4843
+ }], locale: [{
4844
+ type: Input
4633
4845
  }], timezone: [{
4634
4846
  type: Input
4847
+ }], formatDate: [{
4848
+ type: Input
4849
+ }], parseDate: [{
4850
+ type: Input
4635
4851
  }], required: [{
4636
4852
  type: Input
4853
+ }], allowManualInput: [{
4854
+ type: Input
4855
+ }], openOnInputClick: [{
4856
+ type: Input
4637
4857
  }], connector: [{
4638
4858
  type: ViewChild,
4639
4859
  args: ['connector', { static: true }]
4860
+ }], dateInput: [{
4861
+ type: ViewChild,
4862
+ args: ['dateInput']
4640
4863
  }], width: [{
4641
4864
  type: Input
4642
4865
  }, {