ng-month-year-picker 1.0.0
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/README.md
ADDED
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
# ng-month-year-picker
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/ng-month-year-picker)
|
|
4
|
+
[](https://opensource.org/licenses/MIT)
|
|
5
|
+
|
|
6
|
+
Month/year picker dropdown component for Angular. Self-contained — no Bootstrap or icon font required.
|
|
7
|
+
|
|
8
|
+
## ✨ Features
|
|
9
|
+
|
|
10
|
+
- 🎯 **Simple API** - Two-way bindable `value` in `YYYY-MM` format
|
|
11
|
+
- 📅 **Year navigation** - Browse years without changing the selected value
|
|
12
|
+
- 🌍 **Customizable month names** - Defaults to PT-BR, pass your own locale
|
|
13
|
+
- 🖱️ **Click-outside to close** - No extra wiring needed
|
|
14
|
+
- 🎨 **Themeable** - colors/spacing via `--ng-month-year-picker-*` CSS custom properties
|
|
15
|
+
- ⚡ **Standalone component support** (Angular 14+)
|
|
16
|
+
- 🔧 **NgModule compatible** (backward compatible)
|
|
17
|
+
|
|
18
|
+
## 🔧 Compatibility
|
|
19
|
+
|
|
20
|
+
| ng-month-year-picker | Angular | Standalone |
|
|
21
|
+
|------------------|---------------|-----------|
|
|
22
|
+
| 1.0.x | 14.x - 21.x | ✅ Yes |
|
|
23
|
+
|
|
24
|
+
## 📦 Installation
|
|
25
|
+
|
|
26
|
+
### NPM
|
|
27
|
+
```bash
|
|
28
|
+
npm install --save ng-month-year-picker
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
### YARN
|
|
32
|
+
```bash
|
|
33
|
+
yarn add ng-month-year-picker
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
No additional CSS or peer dependencies are required — just Angular.
|
|
37
|
+
|
|
38
|
+
## 🚀 Usage
|
|
39
|
+
|
|
40
|
+
### Method 1: Standalone Component (Angular 14+) ⚡ Recommended
|
|
41
|
+
|
|
42
|
+
**app.component.ts:**
|
|
43
|
+
```typescript
|
|
44
|
+
import { Component, signal } from '@angular/core';
|
|
45
|
+
import { NgMonthYearPickerComponent } from 'ng-month-year-picker';
|
|
46
|
+
|
|
47
|
+
@Component({
|
|
48
|
+
selector: 'app-root',
|
|
49
|
+
standalone: true,
|
|
50
|
+
imports: [NgMonthYearPickerComponent],
|
|
51
|
+
template: `
|
|
52
|
+
<ng-month-year-picker [value]="month()" (valueChange)="month.set($event)"></ng-month-year-picker>
|
|
53
|
+
`
|
|
54
|
+
})
|
|
55
|
+
export class AppComponent {
|
|
56
|
+
month = signal(new Date().toISOString().slice(0, 7));
|
|
57
|
+
}
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
---
|
|
61
|
+
|
|
62
|
+
### Method 2: NgModule (Traditional) 🔧
|
|
63
|
+
|
|
64
|
+
**Step 1: Import the module**
|
|
65
|
+
|
|
66
|
+
```typescript
|
|
67
|
+
import { NgModule } from '@angular/core';
|
|
68
|
+
import { BrowserModule } from '@angular/platform-browser';
|
|
69
|
+
import { NgMonthYearPickerModule } from 'ng-month-year-picker';
|
|
70
|
+
import { AppComponent } from './app.component';
|
|
71
|
+
|
|
72
|
+
@NgModule({
|
|
73
|
+
declarations: [AppComponent],
|
|
74
|
+
imports: [
|
|
75
|
+
BrowserModule,
|
|
76
|
+
NgMonthYearPickerModule
|
|
77
|
+
],
|
|
78
|
+
bootstrap: [AppComponent]
|
|
79
|
+
})
|
|
80
|
+
export class AppModule { }
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
**Step 2: Use in your component**
|
|
84
|
+
|
|
85
|
+
**app.component.html:**
|
|
86
|
+
```html
|
|
87
|
+
<ng-month-year-picker [value]="month" (valueChange)="month = $event"></ng-month-year-picker>
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
**app.component.ts:**
|
|
91
|
+
```typescript
|
|
92
|
+
import { Component } from '@angular/core';
|
|
93
|
+
|
|
94
|
+
@Component({
|
|
95
|
+
selector: 'app-root',
|
|
96
|
+
templateUrl: './app.component.html'
|
|
97
|
+
})
|
|
98
|
+
export class AppComponent {
|
|
99
|
+
month = new Date().toISOString().slice(0, 7);
|
|
100
|
+
}
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
---
|
|
104
|
+
|
|
105
|
+
## 📖 API Reference
|
|
106
|
+
|
|
107
|
+
### Inputs
|
|
108
|
+
|
|
109
|
+
| Input | Type | Default | Description |
|
|
110
|
+
|--------------|------------|-------------------------------------------------------|---------------------------------------------------------------|
|
|
111
|
+
| `value` | `string` | `''` | Selected month in `YYYY-MM` format |
|
|
112
|
+
| `label` | `string` | derived from `value` + `monthNames` | Overrides the text shown on the trigger button |
|
|
113
|
+
| `monthNames` | `string[]` | `['Jan','Fev','Mar','Abr','Mai','Jun','Jul','Ago','Set','Out','Nov','Dez']` | Month names used in the grid and derived label |
|
|
114
|
+
|
|
115
|
+
### Outputs
|
|
116
|
+
|
|
117
|
+
| Output | Type | Description |
|
|
118
|
+
|--------------|------------------------|-----------------------------------------------|
|
|
119
|
+
| `valueChange`| `EventEmitter<string>`| Emitted with `YYYY-MM` when a month is picked |
|
|
120
|
+
|
|
121
|
+
---
|
|
122
|
+
|
|
123
|
+
## 💡 Examples
|
|
124
|
+
|
|
125
|
+
### Basic Usage
|
|
126
|
+
|
|
127
|
+
```typescript
|
|
128
|
+
import { Component, signal } from '@angular/core';
|
|
129
|
+
import { NgMonthYearPickerComponent } from 'ng-month-year-picker';
|
|
130
|
+
|
|
131
|
+
@Component({
|
|
132
|
+
selector: 'app-example',
|
|
133
|
+
standalone: true,
|
|
134
|
+
imports: [NgMonthYearPickerComponent],
|
|
135
|
+
template: `
|
|
136
|
+
<div style="max-width: 200px">
|
|
137
|
+
<ng-month-year-picker [value]="month()" (valueChange)="month.set($event)"></ng-month-year-picker>
|
|
138
|
+
</div>
|
|
139
|
+
|
|
140
|
+
<p>Selected value: <strong>{{ month() }}</strong></p>
|
|
141
|
+
`
|
|
142
|
+
})
|
|
143
|
+
export class ExampleComponent {
|
|
144
|
+
month = signal(new Date().toISOString().slice(0, 7));
|
|
145
|
+
}
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
### Custom Month Names (English)
|
|
149
|
+
|
|
150
|
+
```typescript
|
|
151
|
+
import { Component, signal } from '@angular/core';
|
|
152
|
+
import { NgMonthYearPickerComponent } from 'ng-month-year-picker';
|
|
153
|
+
|
|
154
|
+
@Component({
|
|
155
|
+
selector: 'app-example-en',
|
|
156
|
+
standalone: true,
|
|
157
|
+
imports: [NgMonthYearPickerComponent],
|
|
158
|
+
template: `
|
|
159
|
+
<ng-month-year-picker
|
|
160
|
+
[value]="month()"
|
|
161
|
+
[monthNames]="['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec']"
|
|
162
|
+
(valueChange)="month.set($event)">
|
|
163
|
+
</ng-month-year-picker>
|
|
164
|
+
`
|
|
165
|
+
})
|
|
166
|
+
export class ExampleEnComponent {
|
|
167
|
+
month = signal(new Date().toISOString().slice(0, 7));
|
|
168
|
+
}
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
### Custom Label
|
|
172
|
+
|
|
173
|
+
```html
|
|
174
|
+
<ng-month-year-picker [value]="month()" label="Select a month" (valueChange)="month.set($event)"></ng-month-year-picker>
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
### Theming
|
|
178
|
+
|
|
179
|
+
Override the CSS custom properties on the host element to match your design system:
|
|
180
|
+
|
|
181
|
+
```css
|
|
182
|
+
ng-month-year-picker {
|
|
183
|
+
--ng-month-year-picker-primary: #198754;
|
|
184
|
+
--ng-month-year-picker-primary-color: #fff;
|
|
185
|
+
--ng-month-year-picker-border-color: #ced4da;
|
|
186
|
+
--ng-month-year-picker-bg: #f8f9fa;
|
|
187
|
+
--ng-month-year-picker-hover-bg: #e9ecef;
|
|
188
|
+
--ng-month-year-picker-color: #212529;
|
|
189
|
+
--ng-month-year-picker-radius: 0.375rem;
|
|
190
|
+
}
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
---
|
|
194
|
+
|
|
195
|
+
## ⚠️ Important Notes
|
|
196
|
+
|
|
197
|
+
1. **`value` is one-way**: the component never mutates it. Update it yourself from `valueChange`.
|
|
198
|
+
|
|
199
|
+
2. **Year navigation is independent**: browsing years with the chevrons only changes the dropdown's displayed year (`pickerYear`) — it doesn't affect `value` until a month is actually picked.
|
|
200
|
+
|
|
201
|
+
---
|
|
202
|
+
|
|
203
|
+
## 📄 License
|
|
204
|
+
|
|
205
|
+
MIT © Alvaro Marinho
|
|
206
|
+
|
|
207
|
+
## 🐛 Issues
|
|
208
|
+
|
|
209
|
+
Report issues at: https://github.com/alvaromarinho/libs/issues
|
|
210
|
+
|
|
211
|
+
## 🤝 Contributing
|
|
212
|
+
|
|
213
|
+
Contributions are welcome! Please feel free to submit a Pull Request.
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import * as i0 from '@angular/core';
|
|
2
|
+
import { EventEmitter, HostListener, Output, Input, Component, NgModule } from '@angular/core';
|
|
3
|
+
|
|
4
|
+
class NgMonthYearPickerComponent {
|
|
5
|
+
constructor() {
|
|
6
|
+
/** Nomes dos meses exibidos no grid (padrão: PT-BR). */
|
|
7
|
+
this.monthNames = ['Jan', 'Fev', 'Mar', 'Abr', 'Mai', 'Jun', 'Jul', 'Ago', 'Set', 'Out', 'Nov', 'Dez'];
|
|
8
|
+
/** Valor no formato `YYYY-MM`. */
|
|
9
|
+
this.value = '';
|
|
10
|
+
this.valueChange = new EventEmitter();
|
|
11
|
+
this.showPicker = false;
|
|
12
|
+
this.pickerYear = new Date().getFullYear();
|
|
13
|
+
}
|
|
14
|
+
get displayLabel() {
|
|
15
|
+
if (this.label)
|
|
16
|
+
return this.label;
|
|
17
|
+
const [y, m] = this.value.split('-').map(Number);
|
|
18
|
+
if (!y || !m)
|
|
19
|
+
return '';
|
|
20
|
+
return `${this.monthNames[m - 1]} ${y}`;
|
|
21
|
+
}
|
|
22
|
+
get selectedYear() { return parseInt(this.value?.split('-')[0]) || 0; }
|
|
23
|
+
get selectedMonth() { return parseInt(this.value?.split('-')[1]) || 0; }
|
|
24
|
+
ngOnChanges() {
|
|
25
|
+
if (!this.showPicker)
|
|
26
|
+
this.pickerYear = this.selectedYear || new Date().getFullYear();
|
|
27
|
+
}
|
|
28
|
+
onDocumentClick() {
|
|
29
|
+
this.showPicker = false;
|
|
30
|
+
}
|
|
31
|
+
toggle(event) {
|
|
32
|
+
event.stopPropagation();
|
|
33
|
+
if (!this.showPicker)
|
|
34
|
+
this.pickerYear = this.selectedYear || new Date().getFullYear();
|
|
35
|
+
this.showPicker = !this.showPicker;
|
|
36
|
+
}
|
|
37
|
+
select(monthIndex) {
|
|
38
|
+
const value = `${this.pickerYear}-${String(monthIndex + 1).padStart(2, '0')}`;
|
|
39
|
+
this.valueChange.emit(value);
|
|
40
|
+
this.showPicker = false;
|
|
41
|
+
}
|
|
42
|
+
isSelected(monthIndex) {
|
|
43
|
+
return this.selectedYear === this.pickerYear && this.selectedMonth === monthIndex + 1;
|
|
44
|
+
}
|
|
45
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.6", ngImport: i0, type: NgMonthYearPickerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
46
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.6", type: NgMonthYearPickerComponent, isStandalone: true, selector: "ng-month-year-picker", inputs: { label: "label", monthNames: "monthNames", value: "value" }, outputs: { valueChange: "valueChange" }, host: { listeners: { "document:click": "onDocumentClick()" } }, usesOnChanges: true, ngImport: i0, template: "<button type=\"button\" class=\"trigger\" (click)=\"toggle($event)\">\n {{ displayLabel }}\n</button>\n\n@if (showPicker) {\n <div class=\"dropdown\" (click)=\"$event.stopPropagation()\">\n <div class=\"nav\">\n <button type=\"button\" class=\"nav-btn\" (click)=\"pickerYear = pickerYear - 1\" aria-label=\"Ano anterior\">\n <svg viewBox=\"0 0 12 12\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"8 2 4 6 8 10\"></polyline></svg>\n </button>\n <span class=\"year\">{{ pickerYear }}</span>\n <button type=\"button\" class=\"nav-btn\" (click)=\"pickerYear = pickerYear + 1\" aria-label=\"Pr\u00F3ximo ano\">\n <svg viewBox=\"0 0 12 12\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"4 2 8 6 4 10\"></polyline></svg>\n </button>\n </div>\n <div class=\"grid\">\n @for (m of monthNames; track m; let i = $index) {\n <button type=\"button\" class=\"month-btn\" [class.selected]=\"isSelected(i)\" (click)=\"select(i)\">\n {{ m }}\n </button>\n }\n </div>\n </div>\n}\n", styles: [":host{position:relative;display:inline-flex;width:100%;font-size:.875rem;--ng-month-year-picker-primary: #0d6efd;--ng-month-year-picker-primary-color: #fff;--ng-month-year-picker-border-color: #ced4da;--ng-month-year-picker-bg: #f8f9fa;--ng-month-year-picker-hover-bg: #e9ecef;--ng-month-year-picker-color: #212529;--ng-month-year-picker-radius: .375rem}.trigger{width:100%;padding:.25rem .5rem;font:inherit;white-space:nowrap;color:var(--ng-month-year-picker-color);background-color:var(--ng-month-year-picker-bg);border:1px solid var(--ng-month-year-picker-border-color);border-radius:var(--ng-month-year-picker-radius);cursor:pointer}.trigger:hover{background-color:var(--ng-month-year-picker-hover-bg)}.dropdown{position:absolute;top:calc(100% + 4px);left:50%;transform:translate(-50%);z-index:1050;min-width:220px;padding:.75rem;background:#fff;border:1px solid rgba(0,0,0,.1);border-radius:var(--ng-month-year-picker-radius);box-shadow:0 4px 12px #0000001a}.nav{display:flex;align-items:center;justify-content:space-between;margin-bottom:.5rem}.nav-btn{display:inline-flex;align-items:center;justify-content:center;width:1.75rem;height:1.75rem;padding:0;color:#6c757d;background:transparent;border:none;border-radius:var(--ng-month-year-picker-radius);cursor:pointer}.nav-btn:hover{color:var(--ng-month-year-picker-color);background-color:var(--ng-month-year-picker-hover-bg)}.nav-btn svg{width:.85rem;height:.85rem}.year{font-weight:600}.grid{display:grid;grid-template-columns:repeat(4,1fr);gap:4px}.month-btn{padding:.3rem .25rem;font:inherit;font-size:.78rem;color:var(--ng-month-year-picker-color);background-color:var(--ng-month-year-picker-bg);border:1px solid transparent;border-radius:var(--ng-month-year-picker-radius);cursor:pointer}.month-btn:hover{background-color:var(--ng-month-year-picker-hover-bg)}.month-btn.selected{color:var(--ng-month-year-picker-primary-color);background-color:var(--ng-month-year-picker-primary)}\n"] }); }
|
|
47
|
+
}
|
|
48
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.6", ngImport: i0, type: NgMonthYearPickerComponent, decorators: [{
|
|
49
|
+
type: Component,
|
|
50
|
+
args: [{ selector: 'ng-month-year-picker', standalone: true, template: "<button type=\"button\" class=\"trigger\" (click)=\"toggle($event)\">\n {{ displayLabel }}\n</button>\n\n@if (showPicker) {\n <div class=\"dropdown\" (click)=\"$event.stopPropagation()\">\n <div class=\"nav\">\n <button type=\"button\" class=\"nav-btn\" (click)=\"pickerYear = pickerYear - 1\" aria-label=\"Ano anterior\">\n <svg viewBox=\"0 0 12 12\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"8 2 4 6 8 10\"></polyline></svg>\n </button>\n <span class=\"year\">{{ pickerYear }}</span>\n <button type=\"button\" class=\"nav-btn\" (click)=\"pickerYear = pickerYear + 1\" aria-label=\"Pr\u00F3ximo ano\">\n <svg viewBox=\"0 0 12 12\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"4 2 8 6 4 10\"></polyline></svg>\n </button>\n </div>\n <div class=\"grid\">\n @for (m of monthNames; track m; let i = $index) {\n <button type=\"button\" class=\"month-btn\" [class.selected]=\"isSelected(i)\" (click)=\"select(i)\">\n {{ m }}\n </button>\n }\n </div>\n </div>\n}\n", styles: [":host{position:relative;display:inline-flex;width:100%;font-size:.875rem;--ng-month-year-picker-primary: #0d6efd;--ng-month-year-picker-primary-color: #fff;--ng-month-year-picker-border-color: #ced4da;--ng-month-year-picker-bg: #f8f9fa;--ng-month-year-picker-hover-bg: #e9ecef;--ng-month-year-picker-color: #212529;--ng-month-year-picker-radius: .375rem}.trigger{width:100%;padding:.25rem .5rem;font:inherit;white-space:nowrap;color:var(--ng-month-year-picker-color);background-color:var(--ng-month-year-picker-bg);border:1px solid var(--ng-month-year-picker-border-color);border-radius:var(--ng-month-year-picker-radius);cursor:pointer}.trigger:hover{background-color:var(--ng-month-year-picker-hover-bg)}.dropdown{position:absolute;top:calc(100% + 4px);left:50%;transform:translate(-50%);z-index:1050;min-width:220px;padding:.75rem;background:#fff;border:1px solid rgba(0,0,0,.1);border-radius:var(--ng-month-year-picker-radius);box-shadow:0 4px 12px #0000001a}.nav{display:flex;align-items:center;justify-content:space-between;margin-bottom:.5rem}.nav-btn{display:inline-flex;align-items:center;justify-content:center;width:1.75rem;height:1.75rem;padding:0;color:#6c757d;background:transparent;border:none;border-radius:var(--ng-month-year-picker-radius);cursor:pointer}.nav-btn:hover{color:var(--ng-month-year-picker-color);background-color:var(--ng-month-year-picker-hover-bg)}.nav-btn svg{width:.85rem;height:.85rem}.year{font-weight:600}.grid{display:grid;grid-template-columns:repeat(4,1fr);gap:4px}.month-btn{padding:.3rem .25rem;font:inherit;font-size:.78rem;color:var(--ng-month-year-picker-color);background-color:var(--ng-month-year-picker-bg);border:1px solid transparent;border-radius:var(--ng-month-year-picker-radius);cursor:pointer}.month-btn:hover{background-color:var(--ng-month-year-picker-hover-bg)}.month-btn.selected{color:var(--ng-month-year-picker-primary-color);background-color:var(--ng-month-year-picker-primary)}\n"] }]
|
|
51
|
+
}], propDecorators: { label: [{
|
|
52
|
+
type: Input
|
|
53
|
+
}], monthNames: [{
|
|
54
|
+
type: Input
|
|
55
|
+
}], value: [{
|
|
56
|
+
type: Input
|
|
57
|
+
}], valueChange: [{
|
|
58
|
+
type: Output
|
|
59
|
+
}], onDocumentClick: [{
|
|
60
|
+
type: HostListener,
|
|
61
|
+
args: ['document:click']
|
|
62
|
+
}] } });
|
|
63
|
+
|
|
64
|
+
class NgMonthYearPickerModule {
|
|
65
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.6", ngImport: i0, type: NgMonthYearPickerModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
|
|
66
|
+
static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "21.2.6", ngImport: i0, type: NgMonthYearPickerModule, imports: [NgMonthYearPickerComponent], exports: [NgMonthYearPickerComponent] }); }
|
|
67
|
+
static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "21.2.6", ngImport: i0, type: NgMonthYearPickerModule }); }
|
|
68
|
+
}
|
|
69
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.6", ngImport: i0, type: NgMonthYearPickerModule, decorators: [{
|
|
70
|
+
type: NgModule,
|
|
71
|
+
args: [{
|
|
72
|
+
imports: [NgMonthYearPickerComponent],
|
|
73
|
+
exports: [NgMonthYearPickerComponent]
|
|
74
|
+
}]
|
|
75
|
+
}] });
|
|
76
|
+
|
|
77
|
+
/*
|
|
78
|
+
* Public API Surface of ng-month-year-picker
|
|
79
|
+
*/
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Generated bundle index. Do not edit.
|
|
83
|
+
*/
|
|
84
|
+
|
|
85
|
+
export { NgMonthYearPickerComponent, NgMonthYearPickerModule };
|
|
86
|
+
//# sourceMappingURL=ng-month-year-picker.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ng-month-year-picker.mjs","sources":["../../../projects/ng-month-year-picker/src/lib/ng-month-year-picker.component.ts","../../../projects/ng-month-year-picker/src/lib/ng-month-year-picker.component.html","../../../projects/ng-month-year-picker/src/lib/ng-month-year-picker.module.ts","../../../projects/ng-month-year-picker/src/public-api.ts","../../../projects/ng-month-year-picker/src/ng-month-year-picker.ts"],"sourcesContent":["import { Component, EventEmitter, HostListener, Input, OnChanges, Output } from '@angular/core';\n\n@Component({\n selector: 'ng-month-year-picker',\n standalone: true,\n templateUrl: './ng-month-year-picker.component.html',\n styleUrl: './ng-month-year-picker.component.css',\n})\nexport class NgMonthYearPickerComponent implements OnChanges {\n\n /** Texto exibido no botão. Se vazio, é derivado de `value` + `monthNames`. */\n @Input() label?: string;\n /** Nomes dos meses exibidos no grid (padrão: PT-BR). */\n @Input() monthNames: string[] = ['Jan', 'Fev', 'Mar', 'Abr', 'Mai', 'Jun', 'Jul', 'Ago', 'Set', 'Out', 'Nov', 'Dez'];\n \n /** Valor no formato `YYYY-MM`. */\n @Input() value = '';\n @Output() valueChange = new EventEmitter<string>();\n\n showPicker = false;\n pickerYear = new Date().getFullYear();\n\n get displayLabel(): string {\n if (this.label) return this.label;\n const [y, m] = this.value.split('-').map(Number);\n if (!y || !m) return '';\n return `${this.monthNames[m - 1]} ${y}`;\n }\n\n private get selectedYear(): number { return parseInt(this.value?.split('-')[0]) || 0; }\n private get selectedMonth(): number { return parseInt(this.value?.split('-')[1]) || 0; }\n\n ngOnChanges() {\n if (!this.showPicker) this.pickerYear = this.selectedYear || new Date().getFullYear();\n }\n\n @HostListener('document:click')\n onDocumentClick() {\n this.showPicker = false;\n }\n\n toggle(event: Event) {\n event.stopPropagation();\n if (!this.showPicker) this.pickerYear = this.selectedYear || new Date().getFullYear();\n this.showPicker = !this.showPicker;\n }\n\n select(monthIndex: number) {\n const value = `${this.pickerYear}-${String(monthIndex + 1).padStart(2, '0')}`;\n this.valueChange.emit(value);\n this.showPicker = false;\n }\n\n isSelected(monthIndex: number): boolean {\n return this.selectedYear === this.pickerYear && this.selectedMonth === monthIndex + 1;\n }\n}\n","<button type=\"button\" class=\"trigger\" (click)=\"toggle($event)\">\n {{ displayLabel }}\n</button>\n\n@if (showPicker) {\n <div class=\"dropdown\" (click)=\"$event.stopPropagation()\">\n <div class=\"nav\">\n <button type=\"button\" class=\"nav-btn\" (click)=\"pickerYear = pickerYear - 1\" aria-label=\"Ano anterior\">\n <svg viewBox=\"0 0 12 12\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"8 2 4 6 8 10\"></polyline></svg>\n </button>\n <span class=\"year\">{{ pickerYear }}</span>\n <button type=\"button\" class=\"nav-btn\" (click)=\"pickerYear = pickerYear + 1\" aria-label=\"Próximo ano\">\n <svg viewBox=\"0 0 12 12\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"4 2 8 6 4 10\"></polyline></svg>\n </button>\n </div>\n <div class=\"grid\">\n @for (m of monthNames; track m; let i = $index) {\n <button type=\"button\" class=\"month-btn\" [class.selected]=\"isSelected(i)\" (click)=\"select(i)\">\n {{ m }}\n </button>\n }\n </div>\n </div>\n}\n","import { NgModule } from '@angular/core';\nimport { NgMonthYearPickerComponent } from './ng-month-year-picker.component';\n\n@NgModule({\n imports: [NgMonthYearPickerComponent],\n exports: [NgMonthYearPickerComponent]\n})\nexport class NgMonthYearPickerModule { }\n","/*\n * Public API Surface of ng-month-year-picker\n */\n\nexport * from './lib/ng-month-year-picker.component';\nexport * from './lib/ng-month-year-picker.module';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "ng-month-year-picker",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Month/year picker dropdown component for Angular",
|
|
5
|
+
"author": "Alvaro Marinho",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"keywords": [
|
|
8
|
+
"angular",
|
|
9
|
+
"month",
|
|
10
|
+
"year",
|
|
11
|
+
"picker",
|
|
12
|
+
"date",
|
|
13
|
+
"ng",
|
|
14
|
+
"component"
|
|
15
|
+
],
|
|
16
|
+
"homepage": "https://github.com/alvaromarinho/libs/tree/master/projects/ng-month-year-picker#readme",
|
|
17
|
+
"bugs": {
|
|
18
|
+
"url": "https://github.com/alvaromarinho/libs/issues"
|
|
19
|
+
},
|
|
20
|
+
"repository": {
|
|
21
|
+
"type": "git",
|
|
22
|
+
"url": "https://github.com/alvaromarinho/libs/tree/master/projects/ng-month-year-picker"
|
|
23
|
+
},
|
|
24
|
+
"peerDependencies": {
|
|
25
|
+
"@angular/common": ">=14.0.0 <22.0.0",
|
|
26
|
+
"@angular/core": ">=14.0.0 <22.0.0"
|
|
27
|
+
},
|
|
28
|
+
"dependencies": {
|
|
29
|
+
"tslib": "^2.3.0"
|
|
30
|
+
},
|
|
31
|
+
"sideEffects": false,
|
|
32
|
+
"module": "fesm2022/ng-month-year-picker.mjs",
|
|
33
|
+
"typings": "types/ng-month-year-picker.d.ts",
|
|
34
|
+
"exports": {
|
|
35
|
+
"./package.json": {
|
|
36
|
+
"default": "./package.json"
|
|
37
|
+
},
|
|
38
|
+
".": {
|
|
39
|
+
"types": "./types/ng-month-year-picker.d.ts",
|
|
40
|
+
"default": "./fesm2022/ng-month-year-picker.mjs"
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import * as i0 from '@angular/core';
|
|
2
|
+
import { OnChanges, EventEmitter } from '@angular/core';
|
|
3
|
+
|
|
4
|
+
declare class NgMonthYearPickerComponent implements OnChanges {
|
|
5
|
+
/** Texto exibido no botão. Se vazio, é derivado de `value` + `monthNames`. */
|
|
6
|
+
label?: string;
|
|
7
|
+
/** Nomes dos meses exibidos no grid (padrão: PT-BR). */
|
|
8
|
+
monthNames: string[];
|
|
9
|
+
/** Valor no formato `YYYY-MM`. */
|
|
10
|
+
value: string;
|
|
11
|
+
valueChange: EventEmitter<string>;
|
|
12
|
+
showPicker: boolean;
|
|
13
|
+
pickerYear: number;
|
|
14
|
+
get displayLabel(): string;
|
|
15
|
+
private get selectedYear();
|
|
16
|
+
private get selectedMonth();
|
|
17
|
+
ngOnChanges(): void;
|
|
18
|
+
onDocumentClick(): void;
|
|
19
|
+
toggle(event: Event): void;
|
|
20
|
+
select(monthIndex: number): void;
|
|
21
|
+
isSelected(monthIndex: number): boolean;
|
|
22
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<NgMonthYearPickerComponent, never>;
|
|
23
|
+
static ɵcmp: i0.ɵɵComponentDeclaration<NgMonthYearPickerComponent, "ng-month-year-picker", never, { "label": { "alias": "label"; "required": false; }; "monthNames": { "alias": "monthNames"; "required": false; }; "value": { "alias": "value"; "required": false; }; }, { "valueChange": "valueChange"; }, never, never, true, never>;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
declare class NgMonthYearPickerModule {
|
|
27
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<NgMonthYearPickerModule, never>;
|
|
28
|
+
static ɵmod: i0.ɵɵNgModuleDeclaration<NgMonthYearPickerModule, never, [typeof NgMonthYearPickerComponent], [typeof NgMonthYearPickerComponent]>;
|
|
29
|
+
static ɵinj: i0.ɵɵInjectorDeclaration<NgMonthYearPickerModule>;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export { NgMonthYearPickerComponent, NgMonthYearPickerModule };
|