@cahyo-dimas/freeday 3.9.4 → 3.11.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/CHANGELOG.md +100 -0
- package/COMPONENTS.md +47 -3
- package/README.id.md +39 -11
- package/README.md +37 -10
- package/adapters/blazor/FdyDateRange.razor +20 -2
- package/adapters/blazor/FdyDateRange.razor.cs +20 -0
- package/adapters/blazor/FdyTimepicker.razor +23 -0
- package/adapters/blazor/FdyTimepicker.razor.cs +79 -0
- package/adapters/react/components/FdyDateRange.tsx +29 -0
- package/adapters/react/components/FdyTimepicker.tsx +212 -0
- package/adapters/react/index.d.ts +1 -0
- package/adapters/react/index.js +1 -0
- package/adapters/vue/components/FdyDateRange.vue +29 -0
- package/adapters/vue/components/FdyTimepicker.vue +276 -0
- package/adapters/vue/index.d.ts +1 -0
- package/adapters/vue/index.js +1 -0
- package/dist/freeday-timepicker.js +44 -1
- package/dist/freeday.bundle.css +74 -30
- package/dist/freeday.css +74 -30
- package/dist/freeday.js +44 -1
- package/docs/agent-onboarding.md +3 -3
- package/docs/getting-started.md +12 -5
- package/docs/integrations.md +2 -2
- package/package.json +4 -2
- package/src/base.css +0 -3
- package/src/components/avatar.css +1 -1
- package/src/components/breadcrumb.css +1 -1
- package/src/components/cfl.css +72 -25
package/CHANGELOG.md
CHANGED
|
@@ -9,6 +9,106 @@ benar. Perubahan seperti itu ditulis di bawah `### Changed: BREAKING (types)`
|
|
|
9
9
|
lama → tipe baru, dan cara menyempitkannya — bukan di bawah `### Added`, betapapun aditifnya dari
|
|
10
10
|
sisi kit.
|
|
11
11
|
|
|
12
|
+
## [3.11.0] - 2026-10-26
|
|
13
|
+
|
|
14
|
+
**Audit kontrol native di seluruh layar sebuah aplikasi konsumen, bukan di satu layar yang
|
|
15
|
+
mengeluh.** Pemiliknya melaporkan tampilan HP aslinya tak cocok dengan peramban di lebar yang sama,
|
|
16
|
+
dan dugaan pertama -- termasuk dugaan saya -- adalah CSS. Pengukuran menyangkalnya: dengan
|
|
17
|
+
stylesheet aplikasi yang sebenarnya, pada 375x667, Chromium dan WebKit menata `date`, `time`,
|
|
18
|
+
`number`, `search` dan `text` **identik**, 293x44 keenamnya, selisih satu piksel pada `y` yang
|
|
19
|
+
cuma pembulatan. Jadi yang berbeda bukan tata letaknya, melainkan **widget native-nya**: `date` dan
|
|
20
|
+
`time` digambar sistem operasi, sehingga iOS memberi roda gulir, Android piringan jam dan desktop
|
|
21
|
+
sebuah stepper, masing-masing dengan lebar dan format nilainya sendiri, dan tak ada CSS yang
|
|
22
|
+
menjangkaunya. Itu sebabnya satu HP dan satu peramban di lebar yang sama bisa tidak sepakat soal
|
|
23
|
+
layar yang selebihnya sama.
|
|
24
|
+
|
|
25
|
+
Kit sudah mengatakan ini di tabelnya sendiri ("Use `.fdy-datepicker` / `.fdy-timepicker` /
|
|
26
|
+
`.fdy-datetimepicker` instead") dan sudah mengirim CSS plus enhancer-nya. Yang belum ada adalah
|
|
27
|
+
wrapper bertipe untuk timepicker, jadi aplikasi Vue/React/Blazor harus merakit sendiri
|
|
28
|
+
plumbing custom-event-nya -- dan merakit sendiri adalah yang membuat empat `<input type="time">`
|
|
29
|
+
bertahan di satu formulir shift.
|
|
30
|
+
|
|
31
|
+
Catatan kejujuran: perbedaan iOS itu **tidak** direproduksi di sini. WebKit desktop bukan Mobile
|
|
32
|
+
Safari, dan penampilan kontrol native memang bersifat platform; buktinya adalah tangkapan layar
|
|
33
|
+
perangkat nyata plus fakta terukur bahwa tata letak per lebar sudah identik. Yang dapat diuji
|
|
34
|
+
lokal, dan kini diuji, adalah perilaku penggantinya.
|
|
35
|
+
|
|
36
|
+
### Added
|
|
37
|
+
- **`FdyTimepicker`** (`#094`), wrapper bertipe di **ketiga** stack, menjadikannya tiga belas.
|
|
38
|
+
Vue dan React mengimplementasikan listbox-nya secara native sebab ia kontrol form -- alasan yang
|
|
39
|
+
sama dengan `FdyCombo`, dan alasan yang `FdyChart` nyatakan dari sisi sebaliknya: enhancer yang
|
|
40
|
+
menguasai DOM berkelahi dengan render framework dan tak menyisakan `v-model`. Blazor
|
|
41
|
+
menjembatani enhancer lewat seed, seperti `FdyDatepicker`. Sorotannya **dijepit, bukan
|
|
42
|
+
berputar**: pada daftar 48 opsi, ArrowUp di `00:00` yang melompat ke `23:30` terbaca sebagai
|
|
43
|
+
kerusakan. Sorotan juga digulirkan ke dalam pandangan, sebab panelnya `max-height:15rem` dan
|
|
44
|
+
sorotan yang tak terlihat bukan sorotan.
|
|
45
|
+
- **`data-id` dan `data-describedby` pada seed timepicker** (`#094`). Keduanya tak terbaca
|
|
46
|
+
sebelumnya, jadi host yang menampilkan teks galat tak punya cara menautkannya. Pemicunya
|
|
47
|
+
`<button>`, yang **bukan** elemen labelable, sehingga `<label for>` memang tak akan pernah
|
|
48
|
+
mengaktifkannya -- itu didokumentasikan sekarang, bukan dibiarkan jadi kejutan.
|
|
49
|
+
- **`FreedayTimepicker.setState(root, { disabled, readonly, invalid })`** (`#094`), bentuknya sama
|
|
50
|
+
dengan `FreedayDatepicker.setState`. Tanpa ini, host yang merender seed-nya sekali lalu tidak
|
|
51
|
+
pernah lagi (Blazor, `ShouldRender => false`) memiliki tiga parameter keadaan yang tak ada yang
|
|
52
|
+
membacanya setelah render pertama.
|
|
53
|
+
|
|
54
|
+
### Fixed
|
|
55
|
+
- **`FdyDateRange` membuang kedelapan prop label navigasi kalender** (`#095`), di ketiga stack.
|
|
56
|
+
`FdyDatepicker` menerimanya sejak 2.1.1; rentangnya tidak meneruskannya, sehingga rentang tanggal
|
|
57
|
+
adalah **satu-satunya** kontrol tanggal di kit yang navigasinya tak bisa dinamai dalam bahasa
|
|
58
|
+
halamannya sendiri -- aplikasi berbahasa Indonesia mendapat "Previous month" tepat di tempat yang
|
|
59
|
+
tak dapat ia jangkau. Diteruskan apa adanya ke kedua pemilih. Prop datar `xxxLabel`, bukan objek
|
|
60
|
+
`labels`, sebab bentuk itulah yang sudah dipakai setiap komponen lain di kit. Blazor menambah
|
|
61
|
+
`BackToMonthsLabel`, karena seed yang kedua pemilihnya dibangun dari situ punya tombol itu.
|
|
62
|
+
|
|
63
|
+
## [3.10.0] - 2026-10-26
|
|
64
|
+
|
|
65
|
+
**Lima rilis dalam satu hari, empat di antaranya menambal satu kelas yang sama, dan pemiliknya
|
|
66
|
+
menghentikan polanya.** Setiap cacat Safari hari ini ditemukan oleh sebuah iPhone 7 sesudah
|
|
67
|
+
terkirim, satu per satu, karena suite kit berjalan di Chrome saja: `browser/harness.mjs` berbicara
|
|
68
|
+
CDP ke `chrome-headless-shell` dan tak ada WebKit di ujung kabel itu. Lantai dukungan di README
|
|
69
|
+
adalah prosa yang tak ada yang membacanya. Rilis ini memperbaiki keduanya.
|
|
70
|
+
|
|
71
|
+
### Added
|
|
72
|
+
- **Gerbang lantai fitur** (`#091`), `test/baseline.test.mjs`. Ia **membaca ketiga angka lantai
|
|
73
|
+
dari README** alih-alih mengetiknya ulang, mengenumerasi 41 fitur CSS di kedua stylesheet yang
|
|
74
|
+
dikirim, dan gagal ketika satu di antaranya menuntut rilis yang lantainya tak capai. Pengecualian
|
|
75
|
+
boleh ada tetapi wajib membawa alasan tertulis minimal 160 karakter, DAN fiturnya harus benar-benar
|
|
76
|
+
masih melampaui lantai; kalau tidak gerbangnya menyuruh menghapus entrinya. Daftar pemaafan yang
|
|
77
|
+
tumbuh tanpa alasan adalah penjaga yang berhenti menjaga, dan itu persis kegagalan yang sudah
|
|
78
|
+
terjadi dua kali di hari yang sama.
|
|
79
|
+
- **Suite WebKit di gerbang** (`#092`), job CI tersendiri dengan Playwright, terpisah penuh dari
|
|
80
|
+
harness CDP yang menjalankan 206 uji dan tidak menyentuhnya. Sebelas uji menutup apa yang hanya
|
|
81
|
+
WebKit dapat perlihatkan: backdrop dan centang checkbox dan thumb switch harus MENCAPAI keadaan
|
|
82
|
+
akhirnya di bawah Reduce Motion, tap pada backdrop menutup drawer (sintesis klik `#057`), dan
|
|
83
|
+
asap tata letak telepon. Ia menolak lulus diam-diam lewat lima jalur yang semuanya diuji terhadap
|
|
84
|
+
laporan JSON nyata: laporan hilang, nol uji, ada yang dilewati, ada yang goyah, atau uji identitas
|
|
85
|
+
mesin hilang.
|
|
86
|
+
|
|
87
|
+
### Fixed
|
|
88
|
+
- **Tiga fitur melampaui lantai yang kit nyatakan sendiri** (`#091`). `@container` di CFL dipagari
|
|
89
|
+
`@supports` dengan cadangan `@media (max-width:32rem)`, dan angka itu diturunkan dari lebar
|
|
90
|
+
dialognya sendiri bukan dipilih; absennya bukan kosmetik, sebab di Safari 15.4 sampai 15.8 seluruh
|
|
91
|
+
bloknya dibuang dan dialog 372px memakai tabel tiga kolom yang digulir dua arah.
|
|
92
|
+
`overscroll-behavior` dan `text-wrap:balance` jadi pengecualian beralasan. **Lantainya tidak
|
|
93
|
+
dinaikkan:** iPhone 7 yang menemukan empat cacat hari ini berhenti di iOS 15.
|
|
94
|
+
- **`user-select` dikirim tanpa pasangan `-webkit-`** di `.fdy-avatar` dan `.fdy-breadcrumb__sep`
|
|
95
|
+
(`#091`). WebKit menuntut prefiks itu sampai Safari 17.
|
|
96
|
+
- **Blok durasi-mungil lama di `src/base.css` mengalahkan perlakuan reduced-motion kit sendiri**
|
|
97
|
+
(`#093`). `*,*::before,*::after{animation-duration:.001ms !important}` sebagai `!important` pada
|
|
98
|
+
`*` menang atas `.fdy-spinner{animation-duration:2s}`, `.fdy-skeleton{animation:none}` dan
|
|
99
|
+
`.fdy-progress{animation:none}`, jadi ketiga perlakuan yang ditulis khusus untuk setelan itu tidak
|
|
100
|
+
pernah bekerja. Ketiganya satu-satunya animasi di luar pagar `no-preference`, jadi membuang blok
|
|
101
|
+
lama memulihkan semuanya tanpa membuka apa pun. Penjaga 3.9.4 melewatkannya karena regexnya
|
|
102
|
+
menuntut `0.001ms` berawalan nol sementara berkasnya menulis `.001ms`; sekarang ia menerima
|
|
103
|
+
keduanya dan ikut memeriksa `animation-duration`.
|
|
104
|
+
|
|
105
|
+
### Docs
|
|
106
|
+
- **Meta viewport dinyatakan sebagai syarat**, bukan ditampilkan di contoh. Tanpanya mesin mobile
|
|
107
|
+
menata halaman di lebar bawaan sekitar 980px, `(max-width:720px)` tak pernah cocok, dan seluruh
|
|
108
|
+
lapisan responsif kit absen: shell berdiri dalam bentuk desktopnya di telepon. Itu bukan
|
|
109
|
+
hipotetis. Fixture tanpa tag itu melaporkan `window.innerWidth` 981 pada deskriptor iPhone 7 di
|
|
110
|
+
jalanan pertama suite WebKit, bentuk yang sama persis dengan laporan yang memulai suite itu.
|
|
111
|
+
|
|
12
112
|
## [3.9.4] - 2026-10-26
|
|
13
113
|
|
|
14
114
|
**Sembilan dari lima puluh enam, dan empat puluh delapan sisanya ranjau.** Tiga rilis berturut-turut
|
package/COMPONENTS.md
CHANGED
|
@@ -34,8 +34,9 @@ live docs.
|
|
|
34
34
|
invalid state does not belong to the control itself.
|
|
35
35
|
6. **Interactive components need their enhancer script.** Static ones (button, card, badge, table,
|
|
36
36
|
alert, breadcrumb, timeline, accordion, tree-without-cascade…) are CSS-only.
|
|
37
|
-
7. **On Vue, React or Blazor,
|
|
38
|
-
`FdyDatepicker` · `FdyMonthpicker` · `FdyDateRange` · `
|
|
37
|
+
7. **On Vue, React or Blazor, thirteen components have a typed wrapper. Use it.** `FdyCombo` ·
|
|
38
|
+
`FdyDatepicker` · `FdyMonthpicker` · `FdyDateRange` · `FdyTimepicker` · `FdyAutocomplete` ·
|
|
39
|
+
`FdyCascade` · `FdyCfl` ·
|
|
39
40
|
`FdyChart` · `FdyTable` · `FdyModal` · `FdyDrawer` · `FdyAppShell`, from `@cahyo-dimas/freeday/vue`, `/react`, or the
|
|
40
41
|
`Freeday.Blazor` RCL. Each is flagged at its own section below. Hand-writing their raw markup in
|
|
41
42
|
those stacks *looks* right at first, because the enhancer initialises once and the first render is
|
|
@@ -1020,6 +1021,7 @@ grid's own title.
|
|
|
1020
1021
|
| `startPlaceholder?` · `endPlaceholder?` | `string` | One per field. |
|
|
1021
1022
|
| `ariaLabel?` · `ariaLabelledby?` · `describedby?` | `string` | Names the group (`role="group"`), or points at the text that does. |
|
|
1022
1023
|
| `disabled?` · `readonly?` · `invalid?` | `boolean` | Applied to both pickers together. |
|
|
1024
|
+
| `prevMonthLabel?` · `nextMonthLabel?` · `prevYearLabel?` · `nextYearLabel?` · `prevYearsLabel?` · `nextYearsLabel?` · `chooseMonthLabel?` · `chooseYearLabel?` | `string` | Forwarded verbatim to **both** pickers. Until 3.11.0 this was the one picker in the kit whose calendar nav could not be named in the page's own language: the single picker took these, the range dropped them. Blazor adds `BackToMonthsLabel`, since the raw seed both pickers are built from has that button. |
|
|
1023
1025
|
|
|
1024
1026
|
Blazor splits the value into two scalars, `From` / `FromChanged` and `To` / `ToChanged`, because a
|
|
1025
1027
|
C# binding cannot express one object bound in two places, and it adds `Separator`.
|
|
@@ -1106,10 +1108,52 @@ it has always been, down to the `YYYY-MM-DD` it reports.
|
|
|
1106
1108
|
```
|
|
1107
1109
|
|
|
1108
1110
|
## Time picker — `data-fdy-timepicker`
|
|
1109
|
-
|
|
1111
|
+
> **Typed wrapper: `<FdyTimepicker>`**. Vue (`v-model`) · React (`value`/`onChange`) · Blazor (`@bind-Value`). In those stacks use the wrapper; the markup below is for stacks without an adapter (and is what the wrapper renders).
|
|
1112
|
+
|
|
1113
|
+
24-hour `HH:MM` listbox. **Author an empty `<div>`** — the enhancer builds everything. Needs
|
|
1110
1114
|
`freeday-timepicker.js`. Classes: `.fdy-timepicker` (+`--error`) · `__trigger` `__value`
|
|
1111
1115
|
(+`--placeholder`) `__icon` `__panel` `__opt`.
|
|
1112
1116
|
|
|
1117
|
+
Seed attributes: `data-step` (minutes, default 30), `data-min` (default `00:00`), `data-max`
|
|
1118
|
+
(default `23:59`), `data-value`, `data-label`, `data-placeholder` (default `--:--`), `data-id`,
|
|
1119
|
+
`data-describedby`, `data-disabled`, `data-readonly`, `data-invalid`. Emits a bubbling
|
|
1120
|
+
`fdy-time-select` (`detail {value}`). `FreedayTimepicker.setState(root, { disabled, readonly,
|
|
1121
|
+
invalid })` changes the three states afterwards, which is what a host that renders its seed once
|
|
1122
|
+
and never again (Blazor) needs.
|
|
1123
|
+
|
|
1124
|
+
**Use this instead of `<input type="time">`**, and not for theming alone: the native picker is
|
|
1125
|
+
drawn by the *operating system*, so iOS shows a scroll wheel, Android a clock dial and desktop a
|
|
1126
|
+
stepper, each with its own width and value format, and no CSS reaches any of them. A phone and a
|
|
1127
|
+
browser at the same width therefore disagree about a screen that is otherwise identical.
|
|
1128
|
+
|
|
1129
|
+
```html
|
|
1130
|
+
<div data-fdy-timepicker data-step="15" data-min="06:00" data-max="22:00"
|
|
1131
|
+
data-value="07:00" data-label="Jam mulai"></div>
|
|
1132
|
+
```
|
|
1133
|
+
|
|
1134
|
+
### Props — `<FdyTimepicker>`
|
|
1135
|
+
|
|
1136
|
+
| Prop | Type | What it does |
|
|
1137
|
+
|---|---|---|
|
|
1138
|
+
| `modelValue` · `value` | `string \| null` | `HH:MM`, 24-hour. `''`/`null` for empty. A loose `H:MM` is normalised for matching. Blazor: `Value` / `@bind-Value`. |
|
|
1139
|
+
| `onChange` | `(value: string) => void` | React. Vue emits `update:modelValue` and `change`, Blazor `ValueChanged`. |
|
|
1140
|
+
| `step?` | `number` | Minutes between options. Default 30. |
|
|
1141
|
+
| `min?` · `max?` | `string` | `HH:MM` bounds, inclusive. Default `00:00` to `23:59`. |
|
|
1142
|
+
| `placeholder?` | `string` | Shown when there is no value. Default `--:--`. |
|
|
1143
|
+
| `ariaLabel?` · `ariaLabelledby?` · `describedby?` | `string` | Names the trigger, or points at the text that does. Blazor: `Label` / `Describedby`. |
|
|
1144
|
+
| `id?` | `string` | Id for the trigger. It is a `<button>`, which is **not** a labelable element, so a `<label for>` will not activate it — name it with `ariaLabel`/`ariaLabelledby`. |
|
|
1145
|
+
| `disabled?` · `readonly?` · `invalid?` | `boolean` | `readonly` keeps tab order and shows the time but will not open. |
|
|
1146
|
+
|
|
1147
|
+
Keyboard: `ArrowDown`/`ArrowUp` move one option, `Home`/`End` jump to the ends, `Enter`/`Space`
|
|
1148
|
+
pick, `Escape` closes. The highlight is **clamped, not cyclic** — `ArrowUp` at `00:00` stays there,
|
|
1149
|
+
because wrapping to `23:30` reads as a glitch in a list this long — and it is scrolled into view,
|
|
1150
|
+
since the panel is `max-height:15rem` and a highlight nobody can see is no highlight.
|
|
1151
|
+
|
|
1152
|
+
**Deliberate difference between the two paths.** The wrappers keep focus on the **trigger** with
|
|
1153
|
+
`aria-activedescendant` on it, which is what `FdyCombo`, `FdyDatepicker` and `FdyAutocomplete` do;
|
|
1154
|
+
the raw enhancer moves focus **into the panel**. Both are valid APG listbox patterns, and the Vue
|
|
1155
|
+
and React adapters follow their own family rather than the enhancer.
|
|
1156
|
+
|
|
1113
1157
|
## Datetime picker — `data-fdy-datetimepicker`
|
|
1114
1158
|
A **composition** of the two above, not a monolith: nest one datepicker and one timepicker inside
|
|
1115
1159
|
the wrapper. `freeday-datetime.js` joins them and emits one `fdy-datetime-change` with
|
package/README.id.md
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
> **Lebih banyak _free day_ buat dev. UI kit-nya sudah siap pakai.**
|
|
6
6
|
|
|
7
7
|
[](https://cahyo-dimas.github.io/freeday-ui-kit/)
|
|
8
|
-
[](https://github.com/cahyo-dimas/freeday-ui-kit/tree/v3.11.0)
|
|
9
9
|
|
|
10
10
|
UI KIT yang token-driven & framework-agnostic. Satu sumber kebenaran untuk warna, tipografi,
|
|
11
11
|
spasi, dan komponen. Blueprint: `docs/superpowers/specs/2026-07-21-freeday-ui-kit-design.md`.
|
|
@@ -44,9 +44,9 @@ enhancer:
|
|
|
44
44
|
| **Blazor (net8.0)** | RCL `Freeday.Blazor` | `@bind-Value` |
|
|
45
45
|
| HTML statis · Svelte · template server-rendered | *(tanpa wrapper)* markup mentah + enhancer, di bawah | event `fdy-*` |
|
|
46
46
|
|
|
47
|
-
|
|
48
|
-
`FdyAutocomplete` · `FdyCascade` · `FdyCfl` · `FdyChart` · `FdyTable` · `FdyModal` · `FdyDrawer` ·
|
|
49
|
-
`FdyAppShell`. Menulis markup mentah untuk
|
|
47
|
+
Ketiga belasnya: `FdyCombo` · `FdyDatepicker` · `FdyMonthpicker` · `FdyDateRange` ·
|
|
48
|
+
`FdyTimepicker` · `FdyAutocomplete` · `FdyCascade` · `FdyCfl` · `FdyChart` · `FdyTable` · `FdyModal` · `FdyDrawer` ·
|
|
49
|
+
`FdyAppShell`. Menulis markup mentah untuk ketiga belas ini di dalam Vue/React/Blazor *kelihatan* baik-baik saja pada mulanya, karena render
|
|
50
50
|
pertamanya memang benar. Setelah itu ia rusak diam-diam: DOM yang di-render framework belakangan tak pernah ter-hydrate, dan state widget
|
|
51
51
|
berakhir di DOM alih-alih di state framework-mu. Selebihnya (button, card, badge, alert, markup
|
|
52
52
|
tabel, layout, dan komponen interaktif yang tak punya wrapper) sama persis di semua stack. Untuk
|
|
@@ -256,8 +256,14 @@ terlihat, HTML native dulu sebelum ARIA, komponen interaktif ikut pola WAI-ARIA
|
|
|
256
256
|
|
|
257
257
|
## Dukungan browser
|
|
258
258
|
**Chrome 105 · Safari 15.4 · Firefox 121.** Floor-nya ditentukan `:has()`, dan oleh generasi Safari
|
|
259
|
-
15.4 untuk native `<dialog>`/`::backdrop
|
|
260
|
-
|
|
259
|
+
15.4 untuk native `<dialog>`/`::backdrop` dan `accent-color`. `conic-gradient` dan `scroll-snap`
|
|
260
|
+
lebih tua lagi.
|
|
261
|
+
|
|
262
|
+
`test/baseline.test.mjs` membaca tiga angka itu dari baris di atas, mengenumerasi fitur CSS yang
|
|
263
|
+
dipakai kedua stylesheet yang dikirim, dan gagal kalau salah satunya butuh rilis yang tak dijangkau
|
|
264
|
+
floor itu. Sebelum uji itu ada, floor-nya cuma kalimat yang tak bisa ditegakkan siapa pun, dan di
|
|
265
|
+
hari uji ini ditulis sudah ada lima rilis keluar dalam satu hari, empat di antaranya menambal cacat
|
|
266
|
+
Safari yang ketemu di iPhone 7 sesudah terkirim.
|
|
261
267
|
|
|
262
268
|
Dulu floor itu ditentukan `color-mix()` di Safari 16.4, dan sekarang tidak lagi. Harganya memang tak
|
|
263
269
|
pernah pantas: deklarasi yang mencampur sebuah token membawa `var()`, jadi ia dianggap sah saat
|
|
@@ -268,11 +274,33 @@ sekarang ditulis `rgba(var(--color-primary-rgb), .26)`, warnanya sama dan sudah
|
|
|
268
274
|
Safari 9; empat aturan yang memang tak bisa dijawab secara statis membawa pasangan `@supports` yang
|
|
269
275
|
sungguhan. `test/color-mix.test.mjs` menjaga agar yang berikutnya tetap jujur.
|
|
270
276
|
|
|
271
|
-
Yang paling baru dipakai kit ini
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
277
|
+
Yang paling baru dipakai kit ini memang melewati floor itu, dengan sengaja, dan tiap satunya
|
|
278
|
+
terdaftar di `test/baseline.test.mjs` beserta apa yang hilang di browser di bawah floor:
|
|
279
|
+
|
|
280
|
+
- `@container` di dialog choose-from-list dipagari `@supports`, dan satu media query lebar viewport
|
|
281
|
+
menumpuk barisnya di bawahnya. Yang tak bisa dilihat cadangan itu adalah dialog sempit di dalam
|
|
282
|
+
viewport lebar, yaitu panel yang didok di desktop, dan di situ dialognya tetap memakai tabel yang
|
|
283
|
+
digulir seperti selama ini.
|
|
284
|
+
- `@starting-style` dan transisi `allow-discrete` menganimasikan modal dan drawer. Di bawah floor
|
|
285
|
+
at-rule-nya dilewati dan shorthand-nya dibuang saat parse, jadi keduanya buka dan tutup tanpa
|
|
286
|
+
animasi, selalu di keadaan akhirnya dan tak pernah separuh jalan.
|
|
287
|
+
- `text-wrap: balance` menyeimbangkan dua kelas judul. Tanpa itu judulnya patah di tempat ia patah
|
|
288
|
+
sebelumnya.
|
|
289
|
+
- `overscroll-behavior: contain` menghentikan gulir di ujung nav dan di dua rail halaman yang
|
|
290
|
+
sticky. Tanpa itu gulirnya lanjut ke halaman di belakangnya, seperti sebelum properti ini ada.
|
|
291
|
+
Tidak ada gantinya di CSS di bawah Safari 16; pilihan lainnya scroll lock di JS, dan shell ini
|
|
292
|
+
sengaja tidak melakukannya.
|
|
293
|
+
- `scrollbar-width: none` menyembunyikan scrollbar carousel, dengan `::-webkit-scrollbar` di
|
|
294
|
+
sebelahnya yang mengerjakan hal sama untuk setiap WebKit di dalam floor.
|
|
295
|
+
- `100dvh` membatasi tinggi rail sticky di layar dari 960px. Safari sudah punya unit itu sejak rilis
|
|
296
|
+
floor-nya sendiri, jadi satu-satunya mesin di dalam floor yang belum punya adalah tiga rilis
|
|
297
|
+
Chrome sebelum unit itu mendarat di sana, dan di situ batasnya hilang dan aside yang panjang
|
|
298
|
+
tumbuh melewati viewport alih-alih digulir di dalam dirinya.
|
|
299
|
+
|
|
300
|
+
Blur backdrop pakai `-webkit-backdrop-filter` + `backdrop-filter`, dan `user-select` membawa kembar
|
|
301
|
+
`-webkit-`-nya dengan cara yang sama. Uji yang sama menegaskan kedua pasangan itu aturan per aturan,
|
|
302
|
+
jadi properti standarnya tak pernah dikirim sendirian. Belum ada CSS build/autoprefixer, jadi
|
|
303
|
+
dukungan di bawah floor itu jadi tanggung jawab konsumen.
|
|
276
304
|
|
|
277
305
|
## Lisensi
|
|
278
306
|
[MIT](LICENSE) © 2026 Cahyo D. Kurnianto. Bebas dipakai, diubah, dan didistribusikan asal
|
package/README.md
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
> **More free days for devs. The UI kit is ready to use.**
|
|
6
6
|
|
|
7
7
|
[](https://cahyo-dimas.github.io/freeday-ui-kit/)
|
|
8
|
-
[](https://github.com/cahyo-dimas/freeday-ui-kit/tree/v3.11.0)
|
|
9
9
|
|
|
10
10
|
A token-driven, framework-agnostic UI kit. One source of truth for color, typography,
|
|
11
11
|
spacing, and components. Blueprint: `docs/superpowers/specs/2026-07-21-freeday-ui-kit-design.md`.
|
|
@@ -44,8 +44,8 @@ enhancer:
|
|
|
44
44
|
| **Blazor (net8.0)** | `Freeday.Blazor` RCL | `@bind-Value` |
|
|
45
45
|
| Static HTML · Svelte · server-rendered templates | *(no wrapper)* raw markup + enhancers, below | `fdy-*` events |
|
|
46
46
|
|
|
47
|
-
The
|
|
48
|
-
`FdyCascade` · `FdyCfl` · `FdyChart` · `FdyTable` · `FdyModal` · `FdyDrawer` · `FdyAppShell`.
|
|
47
|
+
The thirteen: `FdyCombo` · `FdyDatepicker` · `FdyMonthpicker` · `FdyDateRange` · `FdyTimepicker` ·
|
|
48
|
+
`FdyAutocomplete` · `FdyCascade` · `FdyCfl` · `FdyChart` · `FdyTable` · `FdyModal` · `FdyDrawer` · `FdyAppShell`.
|
|
49
49
|
Hand-writing the raw
|
|
50
50
|
markup for these inside Vue/React/Blazor *looks* fine at first, because the first render is correct.
|
|
51
51
|
Then it breaks quietly:
|
|
@@ -266,8 +266,14 @@ the "Accessibility" section in `docs/index.html`.
|
|
|
266
266
|
|
|
267
267
|
## Browser support
|
|
268
268
|
**Chrome 105 · Safari 15.4 · Firefox 121.** The floor is set by `:has()`, and by the Safari 15.4
|
|
269
|
-
generation of native `<dialog>`/`::backdrop
|
|
270
|
-
|
|
269
|
+
generation of native `<dialog>`/`::backdrop` and `accent-color`. `conic-gradient` and `scroll-snap`
|
|
270
|
+
are older still.
|
|
271
|
+
|
|
272
|
+
`test/baseline.test.mjs` reads those three numbers out of the line above, enumerates the CSS
|
|
273
|
+
features both shipped stylesheets use, and fails when one of them needs a release the floor does not
|
|
274
|
+
reach. Until that test existed the floor was a sentence nobody could enforce, and the day it was
|
|
275
|
+
written five releases had gone out in one day, four of them fixing Safari defects found on an
|
|
276
|
+
iPhone 7 after shipping.
|
|
271
277
|
|
|
272
278
|
`color-mix()` used to set that floor at Safari 16.4, and it no longer does. It was never worth it:
|
|
273
279
|
a declaration that mixes a token carries `var()`, so it is assumed valid at parse time and only
|
|
@@ -278,11 +284,32 @@ written `rgba(var(--color-primary-rgb), .26)`, which is the same colour and pars
|
|
|
278
284
|
the four rules that cannot be answered statically carry a real `@supports` counterpart.
|
|
279
285
|
`test/color-mix.test.mjs` keeps the next one honest.
|
|
280
286
|
|
|
281
|
-
The newest things the kit touches
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
287
|
+
The newest things the kit touches reach past that floor on purpose, and each one is listed in
|
|
288
|
+
`test/baseline.test.mjs` with what a browser below the floor loses:
|
|
289
|
+
|
|
290
|
+
- `@container` in the choose-from-list dialog is fenced with `@supports`, and a viewport-width media
|
|
291
|
+
query stacks the rows underneath it. The case the fallback cannot see is a narrow dialog inside a
|
|
292
|
+
wide viewport, which is a docked panel on a desktop, and there the dialog keeps the scrolling
|
|
293
|
+
table it always had.
|
|
294
|
+
- `@starting-style` and the `allow-discrete` transitions animate the modal and the drawer. Below the
|
|
295
|
+
floor the at-rule is skipped and the shorthand is dropped at parse time, so both open and close
|
|
296
|
+
with no animation, always at their end state and never halfway.
|
|
297
|
+
- `text-wrap: balance` balances two heading classes. Without it a heading wraps where it used to.
|
|
298
|
+
- `overscroll-behavior: contain` stops a scroll at the end of the nav and of the sticky page rails.
|
|
299
|
+
Without it that scroll carries on into the page behind, the way it did before the property
|
|
300
|
+
existed. There is no CSS substitute below Safari 16; the alternative is a scroll lock in JS, which
|
|
301
|
+
this shell deliberately does not do.
|
|
302
|
+
- `scrollbar-width: none` hides the carousel scrollbar, with `::-webkit-scrollbar` beside it doing
|
|
303
|
+
the same job for every WebKit inside the floor.
|
|
304
|
+
- `100dvh` caps the sticky rails on screens from 960px. Safari has had the unit since the floor
|
|
305
|
+
release itself, so the only engines inside the floor without it are the three Chrome releases
|
|
306
|
+
before it landed there, and on those the cap goes away and a long aside grows past the viewport
|
|
307
|
+
instead of scrolling inside itself.
|
|
308
|
+
|
|
309
|
+
Backdrop blur uses `-webkit-backdrop-filter` + `backdrop-filter`, and `user-select` carries its
|
|
310
|
+
`-webkit-` twin the same way. The same test asserts both pairings rule by rule, so the standard
|
|
311
|
+
property never ships alone. There's no CSS build or autoprefixer step, so supporting anything below
|
|
312
|
+
the floor is the consumer's responsibility.
|
|
286
313
|
|
|
287
314
|
## License
|
|
288
315
|
[MIT](LICENSE) © 2026 Cahyo D. Kurnianto. Free to use, modify, and distribute, as long as the
|
|
@@ -8,9 +8,27 @@
|
|
|
8
8
|
<div @ref="Root">
|
|
9
9
|
<div data-fdy-daterange role="group" aria-label="@AriaLabel">
|
|
10
10
|
<div data-fdy-datepicker data-role="from"
|
|
11
|
-
data-value="@From" data-placeholder="@FromPlaceholder" data-min="@Min" data-max="@Max"
|
|
11
|
+
data-value="@From" data-placeholder="@FromPlaceholder" data-min="@Min" data-max="@Max"
|
|
12
|
+
data-fdy-text-prev-month="@PrevMonthLabel"
|
|
13
|
+
data-fdy-text-next-month="@NextMonthLabel"
|
|
14
|
+
data-fdy-text-prev-year="@PrevYearLabel"
|
|
15
|
+
data-fdy-text-next-year="@NextYearLabel"
|
|
16
|
+
data-fdy-text-prev-years="@PrevYearsLabel"
|
|
17
|
+
data-fdy-text-next-years="@NextYearsLabel"
|
|
18
|
+
data-fdy-text-choose-month="@ChooseMonthLabel"
|
|
19
|
+
data-fdy-text-choose-year="@ChooseYearLabel"
|
|
20
|
+
data-fdy-text-back-to-months="@BackToMonthsLabel"></div>
|
|
12
21
|
<span class="fdy-daterange__sep">@Separator</span>
|
|
13
22
|
<div data-fdy-datepicker data-role="to"
|
|
14
|
-
data-value="@To" data-placeholder="@ToPlaceholder" data-min="@Min" data-max="@Max"
|
|
23
|
+
data-value="@To" data-placeholder="@ToPlaceholder" data-min="@Min" data-max="@Max"
|
|
24
|
+
data-fdy-text-prev-month="@PrevMonthLabel"
|
|
25
|
+
data-fdy-text-next-month="@NextMonthLabel"
|
|
26
|
+
data-fdy-text-prev-year="@PrevYearLabel"
|
|
27
|
+
data-fdy-text-next-year="@NextYearLabel"
|
|
28
|
+
data-fdy-text-prev-years="@PrevYearsLabel"
|
|
29
|
+
data-fdy-text-next-years="@NextYearsLabel"
|
|
30
|
+
data-fdy-text-choose-month="@ChooseMonthLabel"
|
|
31
|
+
data-fdy-text-choose-year="@ChooseYearLabel"
|
|
32
|
+
data-fdy-text-back-to-months="@BackToMonthsLabel"></div>
|
|
15
33
|
</div>
|
|
16
34
|
</div>
|
|
@@ -23,6 +23,26 @@ public partial class FdyDateRange
|
|
|
23
23
|
[Parameter] public string? Max { get; set; }
|
|
24
24
|
[Parameter] public string Separator { get; set; } = "–";
|
|
25
25
|
|
|
26
|
+
/* The calendars' own navigation labels, forwarded verbatim to BOTH pickers. Month and weekday
|
|
27
|
+
NAMES follow the page's `lang` through Intl and need nothing here; these are the buttons
|
|
28
|
+
around them. Until now the range was the one picker in the kit whose nav could not be named
|
|
29
|
+
in the page's own language -- FdyDatepicker took these, FdyDateRange dropped them, so an
|
|
30
|
+
Indonesian app got "Previous month" on the only date control it could not reach. Raised
|
|
31
|
+
from keamanan-cluster (#095). */
|
|
32
|
+
[Parameter] public string? PrevMonthLabel { get; set; }
|
|
33
|
+
[Parameter] public string? NextMonthLabel { get; set; }
|
|
34
|
+
[Parameter] public string? PrevYearLabel { get; set; }
|
|
35
|
+
[Parameter] public string? NextYearLabel { get; set; }
|
|
36
|
+
[Parameter] public string? PrevYearsLabel { get; set; }
|
|
37
|
+
[Parameter] public string? NextYearsLabel { get; set; }
|
|
38
|
+
[Parameter] public string? ChooseMonthLabel { get; set; }
|
|
39
|
+
[Parameter] public string? ChooseYearLabel { get; set; }
|
|
40
|
+
|
|
41
|
+
/// <summary>The year grid's title, back to months. Blazor only, because the raw seed both
|
|
42
|
+
/// pickers are built from supports it and <see cref="FdyDatepicker"/> already exposes it;
|
|
43
|
+
/// the Vue and React adapters build no such button.</summary>
|
|
44
|
+
[Parameter] public string? BackToMonthsLabel { get; set; }
|
|
45
|
+
|
|
26
46
|
private int _token;
|
|
27
47
|
|
|
28
48
|
// initAll(Root) links the daterange (descendant) and inits both child pickers.
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
@namespace Freeday.Blazor
|
|
2
|
+
@inherits FreedayComponentBase<FdyTimepicker>
|
|
3
|
+
|
|
4
|
+
@* Seed-based wrapper over freeday-timepicker.js: the enhancer builds the input-styled trigger
|
|
5
|
+
+ time listbox from this empty div and emits fdy-time-select. The enhancer owns that DOM, so
|
|
6
|
+
the seed renders once (ShouldRender => false) and the picked time is read back through
|
|
7
|
+
@bind-Value. Value is "HH:MM" (24-hour) or "".
|
|
8
|
+
|
|
9
|
+
This is what replaces <input type="time">, and not for theming alone: the native picker is
|
|
10
|
+
drawn by the OPERATING SYSTEM, so iOS shows a scroll wheel, Android a clock dial and desktop a
|
|
11
|
+
stepper, each with its own width and value format, and no CSS reaches any of them (#094). *@
|
|
12
|
+
<div @ref="Root" data-fdy-timepicker
|
|
13
|
+
data-value="@Value"
|
|
14
|
+
data-label="@Label"
|
|
15
|
+
data-placeholder="@Placeholder"
|
|
16
|
+
data-step="@StepAttribute"
|
|
17
|
+
data-min="@Min"
|
|
18
|
+
data-max="@Max"
|
|
19
|
+
data-id="@Id"
|
|
20
|
+
data-describedby="@Describedby"
|
|
21
|
+
data-disabled="@(Disabled ? "true" : null)"
|
|
22
|
+
data-readonly="@(Readonly ? "true" : null)"
|
|
23
|
+
data-invalid="@(Invalid ? "true" : null)"></div>
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
using Microsoft.AspNetCore.Components;
|
|
2
|
+
using Microsoft.JSInterop;
|
|
3
|
+
|
|
4
|
+
namespace Freeday.Blazor;
|
|
5
|
+
|
|
6
|
+
public partial class FdyTimepicker
|
|
7
|
+
{
|
|
8
|
+
/// <summary>Selected time as <c>HH:MM</c> (24-hour), or "" when unset. Two-way bindable
|
|
9
|
+
/// via <c>@bind-Value</c>.</summary>
|
|
10
|
+
[Parameter] public string? Value { get; set; }
|
|
11
|
+
[Parameter] public EventCallback<string?> ValueChanged { get; set; }
|
|
12
|
+
|
|
13
|
+
/// <summary>Accessible label for the trigger.</summary>
|
|
14
|
+
[Parameter] public string? Label { get; set; }
|
|
15
|
+
|
|
16
|
+
/// <summary>Shown when there is no value. The enhancer's own default is <c>--:--</c>.</summary>
|
|
17
|
+
[Parameter] public string? Placeholder { get; set; }
|
|
18
|
+
|
|
19
|
+
/// <summary>Minutes between options. The enhancer's own default is 30.</summary>
|
|
20
|
+
[Parameter] public int? Step { get; set; }
|
|
21
|
+
|
|
22
|
+
/* null, not "30", for the default: an attribute the enhancer does not need is one no reader
|
|
23
|
+
of the seed has to interpret, and the enhancer already falls back to 30. */
|
|
24
|
+
private string? StepAttribute => Step is null ? null : Step.Value.ToString();
|
|
25
|
+
|
|
26
|
+
/// <summary>Earliest selectable time (<c>HH:MM</c>). Default <c>00:00</c>.</summary>
|
|
27
|
+
[Parameter] public string? Min { get; set; }
|
|
28
|
+
|
|
29
|
+
/// <summary>Latest selectable time (<c>HH:MM</c>). Default <c>23:59</c>.</summary>
|
|
30
|
+
[Parameter] public string? Max { get; set; }
|
|
31
|
+
|
|
32
|
+
/// <summary>Id for the trigger the enhancer builds, so <c>aria-describedby</c> targets and
|
|
33
|
+
/// other references can point at it. Note the trigger is a <c><button></c>, which is not
|
|
34
|
+
/// a labelable element, so a <c><label for></c> will not activate it — use
|
|
35
|
+
/// <see cref="Label"/>.</summary>
|
|
36
|
+
[Parameter] public string? Id { get; set; }
|
|
37
|
+
|
|
38
|
+
/// <summary>Id of the help or error text the trigger describes itself with.</summary>
|
|
39
|
+
[Parameter] public string? Describedby { get; set; }
|
|
40
|
+
|
|
41
|
+
/// <summary>Greyed and out of the tab order.</summary>
|
|
42
|
+
[Parameter] public bool Disabled { get; set; }
|
|
43
|
+
|
|
44
|
+
/// <summary>Locked/view mode: focusable and showing its time, but the list will not open.
|
|
45
|
+
/// Unlike <see cref="Disabled"/> it keeps tab order and is not greyed.</summary>
|
|
46
|
+
[Parameter] public bool Readonly { get; set; }
|
|
47
|
+
|
|
48
|
+
/// <summary>Marks the field invalid (<c>aria-invalid</c> + the error styling).</summary>
|
|
49
|
+
[Parameter] public bool Invalid { get; set; }
|
|
50
|
+
|
|
51
|
+
// The enhancer owns this control's DOM; init it directly (initAll would skip Root itself).
|
|
52
|
+
protected override ValueTask HydrateAsync() => JS.InvokeVoidAsync("FreedayTimepicker.init", Root);
|
|
53
|
+
|
|
54
|
+
protected override async ValueTask OnHydratedAsync()
|
|
55
|
+
=> await SubscribeAsync("fdy-time-select", nameof(OnSelect));
|
|
56
|
+
|
|
57
|
+
// The enhancer owns the built trigger + listbox; never let Blazor re-render the seed.
|
|
58
|
+
protected override bool ShouldRender() => !Hydrated;
|
|
59
|
+
|
|
60
|
+
/* Which is exactly why the three states are pushed rather than re-rendered: the seed above is
|
|
61
|
+
written once, so a page that disables this field later would otherwise be ignored. */
|
|
62
|
+
protected override async Task OnParametersSetAsync()
|
|
63
|
+
{
|
|
64
|
+
if (!Hydrated) return;
|
|
65
|
+
await JS.InvokeVoidAsync("FreedayTimepicker.setState", Root,
|
|
66
|
+
new { disabled = Disabled, @readonly = Readonly, invalid = Invalid });
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/// <summary>Invoked by the bridge when the reader picks a time (enhancer's fdy-time-select).</summary>
|
|
70
|
+
[JSInvokable]
|
|
71
|
+
public async Task OnSelect(SelectDetail detail)
|
|
72
|
+
{
|
|
73
|
+
Value = detail.Value;
|
|
74
|
+
await ValueChanged.InvokeAsync(detail.Value);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/// <summary>The detail shape of the enhancer's <c>fdy-time-select</c> event.</summary>
|
|
78
|
+
public sealed record SelectDetail(string Value);
|
|
79
|
+
}
|
|
@@ -29,6 +29,19 @@ export interface FdyDateRangeProps {
|
|
|
29
29
|
endPlaceholder?: string;
|
|
30
30
|
ariaLabel?: string;
|
|
31
31
|
ariaLabelledby?: string;
|
|
32
|
+
/* Forwarded verbatim to BOTH pickers. Without these the range was the one picker in the kit
|
|
33
|
+
whose calendar nav could not be named in the page's own language: FdyDatepicker takes them,
|
|
34
|
+
FdyDateRange dropped them, so an Indonesian app got "Previous month" on the only date control
|
|
35
|
+
it could not reach. Flat `xxxLabel` props, not a `labels` object, because that is the shape
|
|
36
|
+
every other component in the kit already uses. Raised from keamanan-cluster (#095). */
|
|
37
|
+
prevMonthLabel?: string;
|
|
38
|
+
nextMonthLabel?: string;
|
|
39
|
+
prevYearLabel?: string;
|
|
40
|
+
nextYearLabel?: string;
|
|
41
|
+
prevYearsLabel?: string;
|
|
42
|
+
nextYearsLabel?: string;
|
|
43
|
+
chooseMonthLabel?: string;
|
|
44
|
+
chooseYearLabel?: string;
|
|
32
45
|
}
|
|
33
46
|
|
|
34
47
|
export function FdyDateRange(props: FdyDateRangeProps): JSX.Element {
|
|
@@ -57,6 +70,14 @@ export function FdyDateRange(props: FdyDateRangeProps): JSX.Element {
|
|
|
57
70
|
invalid={props.invalid}
|
|
58
71
|
describedby={props.describedby}
|
|
59
72
|
placeholder={props.startPlaceholder ?? 'Dari'}
|
|
73
|
+
prevMonthLabel={props.prevMonthLabel}
|
|
74
|
+
nextMonthLabel={props.nextMonthLabel}
|
|
75
|
+
prevYearLabel={props.prevYearLabel}
|
|
76
|
+
nextYearLabel={props.nextYearLabel}
|
|
77
|
+
prevYearsLabel={props.prevYearsLabel}
|
|
78
|
+
nextYearsLabel={props.nextYearsLabel}
|
|
79
|
+
chooseMonthLabel={props.chooseMonthLabel}
|
|
80
|
+
chooseYearLabel={props.chooseYearLabel}
|
|
60
81
|
/>
|
|
61
82
|
<span className="fdy-daterange__sep" aria-hidden="true">–</span>
|
|
62
83
|
<FdyDatepicker
|
|
@@ -70,6 +91,14 @@ export function FdyDateRange(props: FdyDateRangeProps): JSX.Element {
|
|
|
70
91
|
invalid={props.invalid}
|
|
71
92
|
describedby={props.describedby}
|
|
72
93
|
placeholder={props.endPlaceholder ?? 'Sampai'}
|
|
94
|
+
prevMonthLabel={props.prevMonthLabel}
|
|
95
|
+
nextMonthLabel={props.nextMonthLabel}
|
|
96
|
+
prevYearLabel={props.prevYearLabel}
|
|
97
|
+
nextYearLabel={props.nextYearLabel}
|
|
98
|
+
prevYearsLabel={props.prevYearsLabel}
|
|
99
|
+
nextYearsLabel={props.nextYearsLabel}
|
|
100
|
+
chooseMonthLabel={props.chooseMonthLabel}
|
|
101
|
+
chooseYearLabel={props.chooseYearLabel}
|
|
73
102
|
/>
|
|
74
103
|
</div>
|
|
75
104
|
);
|