From 2491b4a6db5cc2aac36012b55d6b7527d60d325c Mon Sep 17 00:00:00 2001 From: Gramli Date: Fri, 12 Dec 2025 22:22:25 +0100 Subject: [PATCH 1/3] -add two new localizations -fix memory leaks -new styles for example app --- example/app/app.component.css | 169 +++++-- example/app/app.component.html | 68 +-- example/app/app.component.ts | 6 + .../date-picker-div-host-element.css | 54 ++- .../date-picker-inline/date-picker-inline.css | 36 +- .../date-picker-ngmodel.css | 164 ++++++- .../date-picker-ngmodel.html | 454 +++++++++++++----- .../date-picker-ngmodel.ts | 5 +- .../date-picker-reactive-forms.css | 93 +++- .../src/lib/angular-mydatepicker.input.ts | 53 +- .../angular-mydatepicker.locale.service.ts | 22 +- 11 files changed, 885 insertions(+), 239 deletions(-) diff --git a/example/app/app.component.css b/example/app/app.component.css index dabd423..3b5f8c1 100644 --- a/example/app/app.component.css +++ b/example/app/app.component.css @@ -1,25 +1,89 @@ -.pagecontent { - margin: 20px 200px; +:root { + --primary-color: #3b82f6; + --primary-dark: #2563eb; + --primary-light: #60a5fa; + --background: #f8fafc; + --surface: #ffffff; + --text-primary: #1e293b; + --text-secondary: #64748b; + --shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, 0.05); + --shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06); + --shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05); + --radius-sm: 6px; + --radius-md: 8px; + --radius-lg: 12px; + --spacing-xs: 8px; + --spacing-sm: 16px; + --spacing-md: 24px; + --spacing-lg: 32px; + --spacing-xl: 48px; + --transition: all 0.2s ease; +} + +* { + box-sizing: border-box; } -.maintitle { - background-color: #EEE; - height: 180px; - border-bottom: 1px solid #CCC; - background: linear-gradient(to right, #2c539e 0%,rgba(44,83,158,1) 100%); - text-align: center; +body { + margin: 0; + padding: 0; } -.maintitle div { - display: inline-block; - color: #FFF; - font-size: 46px; - font-weight: bold; - line-height: 180px; +.navbar { + background: #2b82b1; + padding: 0 var(--spacing-lg); + height: 60px; + display: flex; + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3); + position: sticky; + top: 0; + z-index: 1000; + justify-content: left +} + +.navbar-brand { + color: #ffffff; + font-size: 20px; + font-weight: 700; + letter-spacing: -0.5px; + padding-left: 1rem; +} + +.nav-btn { + background: transparent; + color: #ffffff; + border: 1px solid rgba(255, 255, 255, 0.2); + padding: 8px 20px; + border-radius: 0.15rem; + font-size: 14px; + font-weight: 500; + cursor: pointer; + transition: var(--transition); +} + +.nav-btn:hover { + background: #6d8f72; + border-color: rgba(255, 255, 255, 0.4); +} + +.nav-btn.active { + background: #ffffff; + color: #000000; + border-color: transparent; +} + +.pagecontent { + max-width: 1400px; + margin: 0 auto; + padding: var(--spacing-lg) var(--spacing-md); + margin-top: 2rem; } .maintext { - margin-bottom: 20px; + margin-bottom: var(--spacing-md); + color: var(--text-secondary); + line-height: 1.6; + font-size: 16px; } .normalmode { @@ -27,30 +91,73 @@ } .inlinemode { - margin-bottom: 20px; + margin-bottom: var(--spacing-md); } -.flexcontainer { - display: flex; +.content-container { + margin-bottom: var(--spacing-xl); + max-width: 1200px; + margin-left: auto; + margin-right: auto; } -.flexitem { - width: 400px; +.content-panel { + background: var(--surface); + border-radius: var(--radius-lg); + padding: var(--spacing-xl); + box-shadow: var(--shadow-md); + border: 2px solid var(--border-color); } -@media screen and (max-width: 1200px) { - .pagecontent { - margin: 20px 10px; - } +.panel-title { + font-size: clamp(20px, 2.5vw, 26px); + font-weight: 700; + color: var(--text-primary); + margin: 0 0 var(--spacing-xs) 0; + letter-spacing: -0.02em; + padding-bottom: 1rem; } -@media screen and (max-width: 1000px) { - .flexcontainer { - display: block; - } +.panel-subtitle { + font-size: 14px; + color: var(--text-secondary); + margin: 0 0 var(--spacing-lg) 0; + line-height: 1.5; +} - .flexitem { - width: 50%; - margin: 0 auto; +@media screen and (max-width: 768px) { + .navbar { + padding: 0 var(--spacing-sm); + height: auto; + flex-direction: column; + gap: var(--spacing-sm); + padding-top: var(--spacing-sm); + padding-bottom: var(--spacing-sm); } + + .navbar-buttons { + width: 100%; + flex-wrap: wrap; + justify-content: center; + } + + .nav-btn { + flex: 1; + min-width: 100px; + } +} + +.panel-title { + font-size: clamp(20px, 2.5vw, 26px); + font-weight: 700; + color: var(--text-primary); + margin: 0 0 var(--spacing-xs) 0; + letter-spacing: -0.02em; +} + +.panel-subtitle { + font-size: 14px; + color: var(--text-secondary); + margin: 0; + line-height: 1.5; } \ No newline at end of file diff --git a/example/app/app.component.html b/example/app/app.component.html index fade1e1..0770bf8 100644 --- a/example/app/app.component.html +++ b/example/app/app.component.html @@ -1,35 +1,43 @@ -
-
angular-mydatepicker
-
-
-
-

ngModel example

-
- loading... -
+ +
+
+ @if (activeTab === 'ngmodel') { +
+

ngModel Two-Way Binding

+

Complete feature showcase with extensive configuration options

+ loading... +
+ } + @if (activeTab === 'reactive') { +
+

Reactive Forms Integration

+

FormControl and FormGroup validation with reactive forms

+ loading... +
+ } + @if (activeTab === 'divhost') { +
+

Div Host Element

+

Custom host element instead of standard input field

+ loading... +
+ } + @if (activeTab === 'inline') { +
+

Inline Calendar

+

Always-visible calendar without input field

+ loading... +
+ }
diff --git a/example/app/app.component.ts b/example/app/app.component.ts index ef791a7..c3af79d 100644 --- a/example/app/app.component.ts +++ b/example/app/app.component.ts @@ -7,7 +7,13 @@ import { Component } from '@angular/core'; standalone: false }) export class AppComponent { + activeTab: string = 'ngmodel'; + constructor() { console.log('constructor: AppComponent()'); } + + setActiveTab(tab: string): void { + this.activeTab = tab; + } } diff --git a/example/app/date-picker-div-host-element/date-picker-div-host-element.css b/example/app/date-picker-div-host-element/date-picker-div-host-element.css index cf4fdb5..485b4c2 100644 --- a/example/app/date-picker-div-host-element/date-picker-div-host-element.css +++ b/example/app/date-picker-div-host-element/date-picker-div-host-element.css @@ -1,31 +1,65 @@ .datepickercontainer { position: relative; display: flex; + align-items: center; + gap: 8px; } .datepickerelement { - border: 1px solid #ced4da; - border-radius: 4px; - padding: 6px 8px; - width: 260px; - font-size: 16px; - color: #495057; + border: 2px solid var(--border-color, #e2e8f0); + border-radius: var(--radius-md, 8px); + padding: 12px 16px; + width: 280px; + font-size: 15px; + color: var(--text-primary, #1e293b); cursor: pointer; + background-color: var(--surface, #ffffff); + transition: var(--transition, all 0.2s ease); + box-shadow: var(--shadow-sm, 0 1px 2px 0 rgba(0, 0, 0, 0.05)); + outline: none; +} + +.datepickerelement:hover { + border-color: var(--primary-light, #60a5fa); + box-shadow: var(--shadow-md, 0 4px 6px -1px rgba(0, 0, 0, 0.1)); +} + +.datepickerelement:focus { + border-color: var(--primary-color, #3b82f6); + box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1); } .placeholdercolor { - color: #bbb; + color: var(--text-secondary, #94a3b8); + font-style: italic; } .closeIconContainer { - margin: auto 0 auto -26px; + display: flex; + align-items: center; + justify-content: center; + width: 24px; + height: 24px; + margin-left: -32px; cursor: pointer; + color: var(--text-secondary, #64748b); + transition: var(--transition, all 0.2s ease); + border-radius: 50%; } .closeIconContainer:hover { - color: #bbb; + color: var(--text-primary, #1e293b); + background-color: var(--background, #f1f5f9); + transform: scale(1.1); +} + +.closeIconContainer:active { + transform: scale(0.95); } .buttons { - margin-top: 20px; + margin-top: var(--spacing-md, 24px); + display: flex; + gap: 12px; + flex-wrap: wrap; } \ No newline at end of file diff --git a/example/app/date-picker-inline/date-picker-inline.css b/example/app/date-picker-inline/date-picker-inline.css index 3556c56..46e7f85 100644 --- a/example/app/date-picker-inline/date-picker-inline.css +++ b/example/app/date-picker-inline/date-picker-inline.css @@ -1,9 +1,41 @@ .datePicker { - margin-top: 20px + margin-top: var(--spacing-md, 24px); + background: var(--surface, #ffffff); + border-radius: var(--radius-lg, 12px); + padding: var(--spacing-sm, 16px); + box-shadow: var(--shadow-md, 0 4px 6px -1px rgba(0, 0, 0, 0.1)); } .submitButton, .headerActionButton { - margin-top: 20px; + margin-top: var(--spacing-md, 24px); + padding: 10px 20px; + border: none; + border-radius: var(--radius-md, 8px); + font-size: 14px; + font-weight: 500; cursor: pointer; + transition: var(--transition, all 0.2s ease); + background: var(--primary-color, #49a6d8); + color: #ffffff; + box-shadow: var(--shadow-sm, 0 1px 2px 0 rgba(0, 0, 0, 0.05)); +} + +.submitButton:hover, +.headerActionButton:hover { + background: var(--primary-dark, #87c38f); + box-shadow: var(--shadow-md, 0 4px 6px -1px rgba(0, 0, 0, 0.1)); + transform: translateY(-1px); +} + +.submitButton:active, +.headerActionButton:active { + transform: translateY(0); + box-shadow: var(--shadow-sm, 0 1px 2px 0 rgba(0, 0, 0, 0.05)); +} + +.submitButton:focus, +.headerActionButton:focus { + outline: none; + box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.2); } diff --git a/example/app/date-picker-ngmodel/date-picker-ngmodel.css b/example/app/date-picker-ngmodel/date-picker-ngmodel.css index 72661c4..2da3862 100644 --- a/example/app/date-picker-ngmodel/date-picker-ngmodel.css +++ b/example/app/date-picker-ngmodel/date-picker-ngmodel.css @@ -1,50 +1,180 @@ -.settingstable, +.settingstable { + width: 100%; + border: none; + border-collapse: separate; + border-spacing: 0; +} + .pickertable { width: 100%; + max-width: 900px; + margin: var(--spacing-lg, 32px) auto; border: none; + border-collapse: separate; + border-spacing: 0; + display: flex; + justify-content: center; } .settingstable tr td { - width: 50%; + width: 33.33%; border: none; + padding: var(--spacing-xs, 8px); + vertical-align: middle; +} + +.settingstable input[type="checkbox"] { + width: 18px; + height: 18px; + cursor: pointer; + margin-left: 8px; } .pickertable tr td { vertical-align: top; + padding: var(--spacing-sm, 16px); } .pickertable tr td:first-child { - width: 290px; + width: 320px; } .pickertable tr td:last-child { - width: calc(100% - 260px); - padding-left: 20px; + width: calc(100% - 320px); + padding-left: var(--spacing-lg, 32px); } .border { - padding: 4px; - border-radius: 4px; - float: right; + padding: 12px 16px; + border-radius: var(--radius-md, 8px); width: 100%; + font-size: 14px; + font-weight: 500; + display: flex; + align-items: center; + gap: 8px; + transition: var(--transition, all 0.2s ease); + box-shadow: var(--shadow-sm, 0 1px 2px 0 rgba(0, 0, 0, 0.05)); +} + +.btnGroup { + display: flex; + justify-content: center; + align-items: center; + gap: var(--spacing-sm, 2px); + flex-wrap: wrap; + margin: var(--spacing-lg, 32px) auto; + max-width: 900px; } -.buttondiv { - margin: 15px 0; +.button { + padding: 10px 20px; + border: none; + border-radius: var(--radius-md, 8px); + font-size: 14px; + font-weight: 500; + cursor: pointer; + transition: var(--transition, all 0.2s ease); + background: var(--primary-color, #49a6d8); + color: #ffffff; + box-shadow: var(--shadow-sm, 0 1px 2px 0 rgba(0, 0, 0, 0.05)); +} + +.button:hover { + background: var(--primary-dark, #72ac7a); + box-shadow: var(--shadow-md, 0 4px 6px -1px rgba(0, 0, 0, 0.1)); + transform: translateY(-1px); +} + +.button:active { + transform: translateY(0); +} + +.button:focus { + outline: none; + box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.2); } .okDate { - color: #3c764d; - background-color: #dff0d6; - border: 1px solid #d6e9c2; + color: #166534; + background-color: #dcfce7; + border: 2px solid #86efac; + animation: slideIn 0.3s ease; +} + +.okDate::before { + content: '✓'; + display: inline-flex; + align-items: center; + justify-content: center; + width: 20px; + height: 20px; + background: #22c55e; + color: white; + border-radius: 50%; + font-size: 12px; + font-weight: bold; } .invalidDate { - color: #a94444; - background-color: #f1dede; - border: 1px solid #ebccd2; + color: #991b1b; + background-color: #fee2e2; + border: 2px solid #fca5a5; + animation: shake 0.3s ease; +} + +.invalidDate::before { + content: '✕'; + display: inline-flex; + align-items: center; + justify-content: center; + width: 20px; + height: 20px; + background: #ef4444; + color: white; + border-radius: 50%; + font-size: 12px; + font-weight: bold; } .inputGroup { - width: 266px; + width: 100%; + max-width: 320px; +} + +@keyframes slideIn { + from { + opacity: 0; + transform: translateY(-4px); + } + + to { + opacity: 1; + transform: translateY(0); + } +} + +@keyframes shake { + + 0%, + 100% { + transform: translateX(0); + } + + 25% { + transform: translateX(-4px); + } + + 75% { + transform: translateX(4px); + } +} + +@media screen and (max-width: 768px) { + + .pickertable tr td:first-child, + .pickertable tr td:last-child { + width: 100%; + padding-left: var(--spacing-sm, 16px); + } } \ No newline at end of file diff --git a/example/app/date-picker-ngmodel/date-picker-ngmodel.html b/example/app/date-picker-ngmodel/date-picker-ngmodel.html index a15e3d5..2b80de2 100644 --- a/example/app/date-picker-ngmodel/date-picker-ngmodel.html +++ b/example/app/date-picker-ngmodel/date-picker-ngmodel.html @@ -1,48 +1,158 @@
+
+ + + + + + +
+ + + + + + +
+
+
+ +
+ +
+
+ +
+
+
+
+ @if (inputText !== '' && selectedTextNormal.length > 0) { +
+ @if (validDate) { + {{selectedTextNormal}} + } @if (!validDate) { + Invalid date + } +
+ } +
+ - - + + - - @@ -50,183 +160,298 @@ - - + + - - - - + + - - - - + + - - - - - - + + - - - - - - - + +
Locale: - @for (l of locales; track l) { - + }
-
+
- - -
- - - - - - -
- - - - - - -
-
-
- -
- -
-
- -
-
-
-
- @if (inputText !== '') { -
- @if (validDate) { - {{selectedTextNormal}} - } - @if (!validDate) { - Invalid date - } -
- } -
- -
- +
diff --git a/example/app/date-picker-ngmodel/date-picker-ngmodel.ts b/example/app/date-picker-ngmodel/date-picker-ngmodel.ts index 28ebc15..d11eb27 100644 --- a/example/app/date-picker-ngmodel/date-picker-ngmodel.ts +++ b/example/app/date-picker-ngmodel/date-picker-ngmodel.ts @@ -97,7 +97,9 @@ export class DatePickerNgmodel implements OnInit { 'it | Italian', 'it-ch | Italian - Switzerland', 'pl | Polish', + 'pt | Portuguese', 'my | Burmese', + 'ms | Malay', 'sk | Slovak', 'sl | Slovenian', 'zh-cn | Chinese - China', @@ -1019,9 +1021,7 @@ export class DatePickerNgmodel implements OnInit { console.log('onInit(): SampleDatePickerNgModel'); } - // callbacks onDateChanged(event: IMyDateModel): void { - console.log('onDateChanged(): ', event); if (!event.isRange) { let { date, jsDate, formatted, epoc } = event.singleDate; @@ -1036,6 +1036,7 @@ export class DatePickerNgmodel implements OnInit { } else { let { formatted } = event.dateRange; + console.log('onDateChanged(): formatted: ', formatted); if (formatted !== '') { this.selectedTextNormal = 'Formatted: ' + formatted; this.validDate = true; diff --git a/example/app/date-picker-reactive-forms/date-picker-reactive-forms.css b/example/app/date-picker-reactive-forms/date-picker-reactive-forms.css index 22c1a9b..cbd4a3e 100644 --- a/example/app/date-picker-reactive-forms/date-picker-reactive-forms.css +++ b/example/app/date-picker-reactive-forms/date-picker-reactive-forms.css @@ -1,35 +1,108 @@ .table { width: 100%; + border-spacing: 0; } .table .td { width: 50%; vertical-align: top; border: none; + padding: var(--spacing-sm, 16px); } .title { - margin-bottom: 10px; + margin-bottom: var(--spacing-sm, 16px); + font-size: 18px; + font-weight: 600; + color: var(--text-primary, #1e293b); + letter-spacing: -0.01em; } .button { + padding: 10px 20px; + border: none; + border-radius: var(--radius-md, 8px); + font-size: 14px; + font-weight: 500; cursor: pointer; + transition: var(--transition, all 0.2s ease); + background: var(--primary-color, #49a6d8); + color: #ffffff; + box-shadow: var(--shadow-sm, 0 1px 2px 0 rgba(0, 0, 0, 0.05)); +} + +.button:hover { + background: var(--primary-dark, #87c38f); + box-shadow: var(--shadow-md, 0 4px 6px -1px rgba(0, 0, 0, 0.1)); + transform: translateY(-1px); +} + +.button:active { + transform: translateY(0); +} + +.button:focus { + outline: none; + box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.2); } .error { - width: 202px; - padding: 4px; - border: 1px solid #ebccd2; - color: #a94444; - background-color: #f2dede; - border-radius: 2px; - margin-top: 10px; + width: 100%; + max-width: 320px; + padding: 12px 16px; + border: 2px solid #fca5a5; + color: #991b1b; + background-color: #fee2e2; + border-radius: var(--radius-md, 8px); + margin-top: var(--spacing-sm, 16px); + font-size: 14px; + display: flex; + align-items: center; + gap: 8px; + animation: slideIn 0.3s ease; + box-shadow: var(--shadow-sm, 0 1px 2px 0 rgba(0, 0, 0, 0.05)); +} + +.error::before { + content: '⚠'; + font-size: 16px; + flex-shrink: 0; } .btnGroup { - margin-top: 10px; + margin-top: var(--spacing-md, 24px); + display: flex; + gap: 12px; + flex-wrap: wrap; } .form { - width: 260px; + width: 100%; + max-width: 320px; + padding: var(--spacing-md, 24px); + background: var(--surface, #ffffff); + border-radius: var(--radius-lg, 12px); + box-shadow: var(--shadow-md, 0 4px 6px -1px rgba(0, 0, 0, 0.1)); +} + +@keyframes slideIn { + from { + opacity: 0; + transform: translateY(-4px); + } + to { + opacity: 1; + transform: translateY(0); + } +} + +@media screen and (max-width: 768px) { + .table .td { + width: 100%; + display: block; + } + + .form { + max-width: 100%; + } } diff --git a/projects/angular-mydatepicker/src/lib/angular-mydatepicker.input.ts b/projects/angular-mydatepicker/src/lib/angular-mydatepicker.input.ts index 70695e5..618628d 100644 --- a/projects/angular-mydatepicker/src/lib/angular-mydatepicker.input.ts +++ b/projects/angular-mydatepicker/src/lib/angular-mydatepicker.input.ts @@ -62,6 +62,11 @@ export class AngularMyDatePickerDirective implements OnChanges, OnDestroy, Contr private opts: IMyOptions; + // Cleanup tracking + private preventCloseTimeout: any = null; + private focusTimeout: any = null; + private animationTimeout: any = null; + onChangeCb: (_: any) => void = () => { }; onTouchedCb: () => void = () => { }; @@ -208,6 +213,27 @@ export class AngularMyDatePickerDirective implements OnChanges, OnDestroy, Contr public ngOnDestroy(): void { this.closeCalendar(); + this.clearAllTimeouts(); + this.removeDocumentClickListener(); + } + + private clearAllTimeouts(): void { + if (this.preventCloseTimeout) { + clearTimeout(this.preventCloseTimeout); + this.preventCloseTimeout = null; + } + if (this.focusTimeout) { + clearTimeout(this.focusTimeout); + this.focusTimeout = null; + } + if (this.animationTimeout) { + clearTimeout(this.animationTimeout); + this.animationTimeout = null; + } + } + + private removeDocumentClickListener(): void { + document.removeEventListener(CLICK, this.onClickWrapper); } public setLocaleOptions(): void { @@ -392,8 +418,12 @@ export class AngularMyDatePickerDirective implements OnChanges, OnDestroy, Contr document.addEventListener(CLICK, this.onClickWrapper); } } - setTimeout(() => { + if (this.preventCloseTimeout) { + clearTimeout(this.preventCloseTimeout); + } + this.preventCloseTimeout = setTimeout(() => { this.preventClose = false; + this.preventCloseTimeout = null; }, PREVENT_CLOSE_TIMEOUT); } @@ -508,6 +538,10 @@ export class AngularMyDatePickerDirective implements OnChanges, OnDestroy, Contr private animationEnd(reason: number): void { if (this.cRef) { this.cRef.instance.selectorEl.nativeElement.removeEventListener(ANIMATION_END, this.onAnimateWrapper); + if (this.animationTimeout) { + clearTimeout(this.animationTimeout); + this.animationTimeout = null; + } this.removeComponent(); this.emitCalendarToggle(reason); } @@ -523,14 +557,17 @@ export class AngularMyDatePickerDirective implements OnChanges, OnDestroy, Contr instance.setCalendarAnimation(calendarAnimation, false); // In case the animationend event is not fired - setTimeout(this.onAnimateWrapper.bind(this, reason), ANIMATION_TIMEOUT); + if (this.animationTimeout) { + clearTimeout(this.animationTimeout); + } + this.animationTimeout = setTimeout(this.onAnimateWrapper.bind(this, reason), ANIMATION_TIMEOUT); } else { this.removeComponent(); this.emitCalendarToggle(reason); } - document.removeEventListener(CLICK, this.onClickWrapper); + this.removeDocumentClickListener(); } } @@ -555,8 +592,14 @@ export class AngularMyDatePickerDirective implements OnChanges, OnDestroy, Contr private focusToInput(): void { const {focusInputOnDateSelect, divHostElement} = this.opts; if (focusInputOnDateSelect && !divHostElement.enabled) { - setTimeout(() => { - this.elem.nativeElement.focus(); + if (this.focusTimeout) { + clearTimeout(this.focusTimeout); + } + this.focusTimeout = setTimeout(() => { + if (this.elem && this.elem.nativeElement) { + this.elem.nativeElement.focus(); + } + this.focusTimeout = null; }); } } diff --git a/projects/angular-mydatepicker/src/lib/services/angular-mydatepicker.locale.service.ts b/projects/angular-mydatepicker/src/lib/services/angular-mydatepicker.locale.service.ts index b67f4e7..1d9b0e3 100644 --- a/projects/angular-mydatepicker/src/lib/services/angular-mydatepicker.locale.service.ts +++ b/projects/angular-mydatepicker/src/lib/services/angular-mydatepicker.locale.service.ts @@ -134,6 +134,14 @@ export class LocaleService { sunHighlight: false, todayTxt: "Bugün" }, + "pt": { + dayLabels: {su: "Dom", mo: "Seg", tu: "Ter", we: "Qua", th: "Qui", fr: "Sex", sa: "Sáb"}, + monthLabels: { 1: "Jan", 2: "Fev", 3: "Mar", 4: "Abr", 5: "Mai", 6: "Jun", 7: "Jul", 8: "Ago", 9: "Set", 10: "Out", 11: "Nov", 12: "Dez" }, + dateFormat: "dd-mm-yyyy", + firstDayOfWeek: "mo", + sunHighlight: false, + todayTxt: "Hoje" + }, "pt-br": { dayLabels: {su: "Dom", mo: "Seg", tu: "Ter", we: "Qua", th: "Qui", fr: "Sex", sa: "Sab"}, monthLabels: { 1: "Jan", 2: "Fev", 3: "Mar", 4: "Abr", 5: "Mai", 6: "Jun", 7: "Jul", 8: "Ago", 9: "Set", 10: "Out", 11: "Nov", 12: "Dez" }, @@ -190,6 +198,14 @@ export class LocaleService { sunHighlight: true, todayTxt: "ယနေ့" }, + "ms": { + dayLabels: {su: "Ahd", mo: "Isn", tu: "Sel", we: "Rab", th: "Kha", fr: "Jum", sa: "Sab"}, + monthLabels: {1: "Jan", 2: "Feb", 3: "Mac", 4: "Apr", 5: "Mei", 6: "Jun", 7: "Jul", 8: "Ogo", 9: "Sep", 10: "Okt", 11: "Nov", 12: "Dis"}, + dateFormat: "dd-mm-yyyy", + firstDayOfWeek: "su", + sunHighlight: true, + todayTxt: "Hari ini" + }, "sk": { dayLabels: { su: "Ne", mo: "Po", tu: "Ut", we: "St", th: "Št", fr: "Pi", sa: "So" }, monthLabels: { 1: "Jan", 2: "Feb", 3: "Mar", 4: "Apr", 5: "Máj", 6: "Jún", 7: "Júl", 8: "Aug", 9: "Sep", 10: "Okt", 11: "Nov", 12: "Dec" }, @@ -392,10 +408,8 @@ export class LocaleService { } }; - getLocaleOptions(locale = DEFAULT_LOCALE): IMyOptions { - // Convert locale to lowercase - i.e. support passing uppercase region subtags + getLocaleOptions(locale: string = DEFAULT_LOCALE): IMyOptions { const lowerCaseLocale = locale.toLowerCase() - // If locale exists, return it, else return default locale (en) - return this.locales.hasOwnProperty(lowerCaseLocale) ? this.locales[lowerCaseLocale] : this.locales[DEFAULT_LOCALE]; + return this.locales[lowerCaseLocale] || this.locales[DEFAULT_LOCALE]; } } From 5f274c26cc58e874c4b213a5244d7efcadda7b9a Mon Sep 17 00:00:00 2001 From: Gramli Date: Sat, 13 Dec 2025 13:08:31 +0100 Subject: [PATCH 2/3] add links to npm and github to example app, fix package.json --- README.md | 2 +- example/app/app.component.css | 41 +++++++++++++++++++++- example/app/app.component.html | 12 +++++++ projects/angular-mydatepicker/README.md | 15 -------- projects/angular-mydatepicker/package.json | 2 +- 5 files changed, 54 insertions(+), 18 deletions(-) delete mode 100644 projects/angular-mydatepicker/README.md diff --git a/README.md b/README.md index 579df68..5ff2017 100644 --- a/README.md +++ b/README.md @@ -231,7 +231,7 @@ The datepicker supports 40+ locales out of the box. Set the `locale` attribute t #### Supported Locales -`en`, `fr`, `fr-ch`, `ja`, `fi`, `es`, `hu`, `sv`, `nl`, `ru`, `uk`, `uz`, `no`, `tr`, `pt-br`, `de`, `de-ch`, `it`, `it-ch`, `pl`, `my`, `sk`, `sl`, `zh-cn`, `he`, `ro`, `ca`, `id`, `en-au`, `en-gb`, `am-et`, `cs`, `el`, `kk`, `th`, `ko-kr`, `da`, `lt`, `vi`, `bn`, `bg`, `hr`, `ar`, `is`, `tw`, `lv`, `et` +`en`, `fr`, `fr-ch`, `ja`, `fi`, `es`, `hu`, `sv`, `nl`, `ru`, `uk`, `uz`, `no`, `tr`, `pt-br`, `pt`, `de`, `de-ch`, `it`, `it-ch`, `pl`, `my`, `ms`, `sk`, `sl`, `zh-cn`, `he`, `ro`, `ca`, `id`, `en-au`, `en-gb`, `am-et`, `cs`, `el`, `kk`, `th`, `ko-kr`, `da`, `lt`, `vi`, `bn`, `bg`, `hr`, `ar`, `is`, `tw`, `lv`, `et` > [!TIP] > To add a new locale, submit a PR updating the [locale service](https://github.com/gramli/angular-mydatepicker/blob/master/projects/angular-mydatepicker/src/lib/services/angular-mydatepicker.locale.service.ts). diff --git a/example/app/app.component.css b/example/app/app.component.css index 3b5f8c1..f632b69 100644 --- a/example/app/app.component.css +++ b/example/app/app.component.css @@ -38,7 +38,8 @@ body { position: sticky; top: 0; z-index: 1000; - justify-content: left + justify-content: space-between; + align-items: center; } .navbar-brand { @@ -49,6 +50,40 @@ body { padding-left: 1rem; } +.navbar-buttons { + display: flex; + gap: 12px; + align-items: left; +} + +.navbar-icons { + display: flex; + gap: 16px; + align-items: center; + padding-right: 1rem; +} + +.icon-link { + color: #ffffff; + display: flex; + align-items: center; + justify-content: center; + padding: 8px; + border-radius: var(--radius-sm); + transition: var(--transition); + text-decoration: none; +} + +.icon-link:hover { + background: rgba(255, 255, 255, 0.15); + transform: translateY(-2px); +} + +.icon-link svg { + width: 24px; + height: 24px; +} + .nav-btn { background: transparent; color: #ffffff; @@ -145,6 +180,10 @@ body { flex: 1; min-width: 100px; } + + .navbar-icons { + order: -1; + } } .panel-title { diff --git a/example/app/app.component.html b/example/app/app.component.html index 0770bf8..514fc7b 100644 --- a/example/app/app.component.html +++ b/example/app/app.component.html @@ -6,6 +6,18 @@
+
diff --git a/projects/angular-mydatepicker/README.md b/projects/angular-mydatepicker/README.md deleted file mode 100644 index 1e42bb4..0000000 --- a/projects/angular-mydatepicker/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# angular-mydatepicker - -This library was generated with [Angular CLI](https://github.com/angular/angular-cli) version 7.2.0. - -## Build - -Run `npm run build-lib` to build the datepicker library. The build artifacts will be stored in the `dist/` directory. - -## Create local npm package - -After building your library with `npm run build-lib`, go to the dist folder `cd dist/angular-mydatepicker` and run `npm pack`. The npm package is created to the `dist/angular-mydatepicker` folder. - -## Publishing - -After building your library with `npm run build-lib`, go to the dist folder `cd dist/angular-mydatepicker` and run `npm publish`. diff --git a/projects/angular-mydatepicker/package.json b/projects/angular-mydatepicker/package.json index 6faa0f8..0cc4433 100644 --- a/projects/angular-mydatepicker/package.json +++ b/projects/angular-mydatepicker/package.json @@ -1,6 +1,6 @@ { "name": "gramli-angular-mydatepicker", - "version": "21.0.0", + "version": "21.0.1", "description": "A highly configurable Angular datepicker and date range picker with no external dependencies. Lightweight, flexible, and feature-rich.", "keywords": [ "angular", From 0be39d83d375c4df8d154c1481f7756642b8fb71 Mon Sep 17 00:00:00 2001 From: Gramli Date: Sat, 13 Dec 2025 14:04:11 +0100 Subject: [PATCH 3/3] - fix typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 5ff2017..834b4f8 100644 --- a/README.md +++ b/README.md @@ -422,4 +422,4 @@ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file ## Credits -Originally created by [kekeh](https://github.com/kekeh) and [nodro7](https://github.com/nodro7) and. Currently maintained by [Gramli](https://github.com/Gramli). +Originally created by [kekeh](https://github.com/kekeh) and [nodro7](https://github.com/nodro7). Currently maintained by [Gramli](https://github.com/Gramli).