@cahyo-dimas/freeday 3.12.1 → 3.13.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 +70 -9
- package/COMPONENTS.md +31 -1
- package/README.id.md +1 -1
- package/README.md +1 -1
- package/dist/freeday-breakpoint.js +12 -2
- package/dist/freeday-cfl.js +3 -1
- package/dist/freeday-chip.js +10 -4
- package/dist/freeday-unhydrated.js +76 -0
- package/dist/freeday-upload.js +5 -3
- package/dist/freeday.bundle.css +2 -1
- package/dist/freeday.css +2 -1
- package/dist/freeday.js +107 -10
- package/docs/agent-onboarding.md +2 -1
- package/docs/getting-started.md +1 -1
- package/docs/integrations.md +2 -2
- package/package.json +2 -2
- package/src/components/input.css +2 -1
package/CHANGELOG.md
CHANGED
|
@@ -9,19 +9,80 @@ 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.13.0] - 2026-10-29
|
|
13
|
+
|
|
14
|
+
**Kit berhenti memutuskan hal yang bukan urusannya, dan markup yang tak pernah dihidrasi kini
|
|
15
|
+
bersuara.** Lima butir dari `CATATAN-FREEDAY.md` app ronda (§9 sampai §13), dikerjakan dalam satu
|
|
16
|
+
rilis. Tiga di antaranya gagal tanpa galat apa pun: chip yang hilang sesudah Batal, tombol simpan
|
|
17
|
+
yang mati, dan kelas yang tak cocok dengan aturan mana pun.
|
|
18
|
+
|
|
19
|
+
### Changed
|
|
20
|
+
- **`fdy-chip-remove` dan `fdy-upload-remove` kini dapat dibatalkan** (`#098`). Begitu
|
|
21
|
+
`.fdy-chip__remove` ditekan, enhancer chip langsung menghapus chip-nya, padahal kit tak tahu
|
|
22
|
+
apakah penghapusan itu perlu ditanyakan dulu. Matriks pola rotasi di app ronda memakai chip
|
|
23
|
+
sebagai tampilan dan punya dialog konfirmasi sendiri. Chip-nya hilang ketika dialog masih
|
|
24
|
+
terbuka, dan tetap hilang sesudah **Batal** ditekan. Datanya utuh, layarnya yang salah. Sekarang
|
|
25
|
+
event-nya `cancelable`, dan elemennya baru dihapus kalau tak ada listener yang memanggil
|
|
26
|
+
`preventDefault()`. Perubahan ini aditif: app yang tidak membatalkan mendapat perilaku yang persis
|
|
27
|
+
sama. Baris upload ikut diubah karena bentuknya sama, dan berkas yang sudah dipegang server
|
|
28
|
+
memang layak ditanyakan dulu sebelum dibuang.
|
|
29
|
+
|
|
30
|
+
### Added
|
|
31
|
+
- **Peringatan konsol untuk hook yang tak pernah dihidrasi** (`#099`): `src/freeday-unhydrated.js`,
|
|
32
|
+
sudah termasuk di import akar. Klik, fokus atau submit pertama di dalam elemen ber-hook yang tak
|
|
33
|
+
punya penanda siap mencetak satu `console.warn` per elemen. Pesannya menyebut hook-nya, dan
|
|
34
|
+
elemennya ikut sebagai argumen kedua supaya devtools menautkannya. Pemicunya §10: `useFreeday()`
|
|
35
|
+
yang dipasang di pembungkus yang salah membuat `data-fdy-validate` di luar pembungkus itu diam
|
|
36
|
+
total, tanpa kalimat validasi dan tanpa `fdy-form-valid`. Yang memberi tahu cuma dua uji e2e yang
|
|
37
|
+
merah. Catatannya meminta peringatan ini untuk form, tetapi kegagalannya berlaku untuk setiap
|
|
38
|
+
hook, jadi tabelnya memuat 29 hook dari 24 enhancer. Peringatan dipicu interaksi, bukan saat
|
|
39
|
+
halaman dimuat, karena framework me-mount dan menghidrasi di antara keduanya.
|
|
40
|
+
- **`fdy-help--danger`** (`#100`), alias `fdy-help--error` di dalam aturan yang sama. Kit memakai
|
|
41
|
+
`--danger` sebagai kata nada di mana-mana (tombol, alert, lencana, toast), sehingga app menebak
|
|
42
|
+
`fdy-help--danger`. Kelas itu tak cocok dengan aturan apa pun, dan kalimat peringatannya tampil
|
|
43
|
+
abu-abu. Kontrol form sengaja tidak diberi alias. Keadaannya digerakkan `aria-invalid`, jadi
|
|
44
|
+
`--error` di sana jarang ditulis tangan. Aturan penamaannya kini tertulis di COMPONENTS.md.
|
|
45
|
+
|
|
46
|
+
### Fixed
|
|
47
|
+
- **`FreedayCfl` dan `FreedayBreakpoint` tak punya `initAll`** (`#099`), padahal hanya nama itu
|
|
48
|
+
yang dicari ketiga helper stack (`useFreeday` di Vue dan React, `FreedayBlazor.initAll`). Markup
|
|
49
|
+
CFL mentah di dalam subtree framework dilewati ketiganya dan dialognya tak pernah terbuka. Label
|
|
50
|
+
breakpoint yang di-mount belakangan tetap kosong sampai breakpoint berganti. Tak ada yang
|
|
51
|
+
melaporkan ini; keduanya ketemu saat mengaudit kelas cacat §10.
|
|
52
|
+
|
|
53
|
+
### Docs
|
|
54
|
+
- **`<ul>` polos adalah daftar berbutir yang didukung** (`#101`). `base.css` memang tak pernah
|
|
55
|
+
mereset daftar. Sekarang COMPONENTS.md menjanjikannya, dan sebuah uji menjaga janji itu.
|
|
56
|
+
- §13 (`required` di `FdyCombo`) sudah terkirim di 3.12.0 (`#096`). Tak ada kode baru; app tinggal
|
|
57
|
+
memakainya.
|
|
58
|
+
|
|
59
|
+
### Gerbang
|
|
60
|
+
- `docs.test.mjs`: setiap penanda siap yang dicap enhancer wajib ada di tabel peringatan, dicap di
|
|
61
|
+
berkas milik namespace yang disebut tabel, dan berkas itu wajib benar-benar meng-query selektor
|
|
62
|
+
pasangannya. Setiap enhancer yang menghidrasi markup wajib mengekspos `initAll`. Penjaga string
|
|
63
|
+
kini melewati teks `console.warn` (untuk devtools, tak pernah masuk DOM) dan identifier
|
|
64
|
+
PascalCase.
|
|
65
|
+
- `css.test.mjs`: `fdy-help--danger` harus satu aturan dengan `--error`, dan tak boleh ada aturan
|
|
66
|
+
tanpa cakupan yang mereset `ul`/`ol`/`li`.
|
|
67
|
+
- `browser/app-owned.mjs`, dengan mouse asli: chip dan baris upload yang dibatalkan tetap di
|
|
68
|
+
tempatnya, form yatim memperingatkan sekali sementara form yang terhidrasi diam, dan CFL serta
|
|
69
|
+
label breakpoint yang di-mount belakangan terhidrasi lewat `FreedayBlazor.initAll`.
|
|
70
|
+
- Tiga belas mutasi diverifikasi merah sebelum dipulihkan: enam pada perilaku, lima pada tabel dan
|
|
71
|
+
ekspor, dua pada CSS.
|
|
72
|
+
|
|
12
73
|
## [3.12.1] - 2026-10-27
|
|
13
74
|
|
|
14
75
|
**Modal dan drawer kembali beranimasi di bawah Safari 17.4, termasuk di iPhone 7 pemiliknya.**
|
|
15
76
|
|
|
16
77
|
### Fixed
|
|
17
78
|
- **Empat shorthand `transition` dipecah jadi longhand** (`#097`), di `modal.css` dan `drawer.css`.
|
|
18
|
-
Shorthand yang membawa satu keyword yang tak dikenal mesin **tidak sah saat parse**, jadi
|
|
19
|
-
deklarasinya dibuang
|
|
79
|
+
Shorthand yang membawa satu keyword yang tak dikenal mesin **tidak sah saat parse**, jadi seluruh
|
|
80
|
+
deklarasinya dibuang, dan `allow-discrete` tak dikenal di bawah Safari 17.4, yang ada di bawah
|
|
20
81
|
lantai dukungan kit. Akibatnya modal dan drawer buka-tutup tanpa animasi apa pun. Dipecah begini,
|
|
21
82
|
yang hilang di bawah lantai hanya `transition-behavior`, dan paruh opacity/transform-nya bertahan.
|
|
22
83
|
`overlay` dan `display` tetap terdaftar di `transition-property`, tempat nama yang tak cocok tetap
|
|
23
84
|
sah secara sintaks dan sekadar tak pernah cocok, jadi tak ada lagi yang ikut jatuh. Keluarnya
|
|
24
|
-
tetap seketika di sana sebab `display` memang tak dapat ditransisikan di bawah lantai
|
|
85
|
+
tetap seketika di sana sebab `display` memang tak dapat ditransisikan di bawah lantai, sama
|
|
25
86
|
seperti sebelumnya, jadi pemecahan ini tidak mengambil apa pun.
|
|
26
87
|
|
|
27
88
|
Ekuivalensinya di atas lantai **diukur, bukan dinalar**: `transition-property`,
|
|
@@ -94,7 +155,7 @@ perbaikan ini terdengar jauh lebih mahal daripada yang ternyata.
|
|
|
94
155
|
|
|
95
156
|
**Audit kontrol native di seluruh layar sebuah aplikasi konsumen, bukan di satu layar yang
|
|
96
157
|
mengeluh.** Pemiliknya melaporkan tampilan HP aslinya tak cocok dengan peramban di lebar yang sama,
|
|
97
|
-
dan dugaan pertama
|
|
158
|
+
dan dugaan pertama, termasuk dugaan saya, adalah CSS. Pengukuran menyangkalnya: dengan
|
|
98
159
|
stylesheet aplikasi yang sebenarnya, pada 375x667, Chromium dan WebKit menata `date`, `time`,
|
|
99
160
|
`number`, `search` dan `text` **identik**, 293x44 keenamnya, selisih satu piksel pada `y` yang
|
|
100
161
|
cuma pembulatan. Jadi yang berbeda bukan tata letaknya, melainkan **widget native-nya**: `date` dan
|
|
@@ -106,7 +167,7 @@ layar yang selebihnya sama.
|
|
|
106
167
|
Kit sudah mengatakan ini di tabelnya sendiri ("Use `.fdy-datepicker` / `.fdy-timepicker` /
|
|
107
168
|
`.fdy-datetimepicker` instead") dan sudah mengirim CSS plus enhancer-nya. Yang belum ada adalah
|
|
108
169
|
wrapper bertipe untuk timepicker, jadi aplikasi Vue/React/Blazor harus merakit sendiri
|
|
109
|
-
plumbing custom-event-nya
|
|
170
|
+
plumbing custom-event-nya, dan merakit sendiri adalah yang membuat empat `<input type="time">`
|
|
110
171
|
bertahan di satu formulir shift.
|
|
111
172
|
|
|
112
173
|
Catatan kejujuran: perbedaan iOS itu **tidak** direproduksi di sini. WebKit desktop bukan Mobile
|
|
@@ -116,8 +177,8 @@ lokal, dan kini diuji, adalah perilaku penggantinya.
|
|
|
116
177
|
|
|
117
178
|
### Added
|
|
118
179
|
- **`FdyTimepicker`** (`#094`), wrapper bertipe di **ketiga** stack, menjadikannya tiga belas.
|
|
119
|
-
Vue dan React mengimplementasikan listbox-nya secara native sebab ia kontrol form
|
|
120
|
-
|
|
180
|
+
Vue dan React mengimplementasikan listbox-nya secara native sebab ia kontrol form. Alasannya sama
|
|
181
|
+
dengan `FdyCombo`, dan `FdyChart` menyatakannya dari sisi sebaliknya: enhancer yang
|
|
121
182
|
menguasai DOM berkelahi dengan render framework dan tak menyisakan `v-model`. Blazor
|
|
122
183
|
menjembatani enhancer lewat seed, seperti `FdyDatepicker`. Sorotannya **dijepit, bukan
|
|
123
184
|
berputar**: pada daftar 48 opsi, ArrowUp di `00:00` yang melompat ke `23:30` terbaca sebagai
|
|
@@ -126,7 +187,7 @@ lokal, dan kini diuji, adalah perilaku penggantinya.
|
|
|
126
187
|
- **`data-id` dan `data-describedby` pada seed timepicker** (`#094`). Keduanya tak terbaca
|
|
127
188
|
sebelumnya, jadi host yang menampilkan teks galat tak punya cara menautkannya. Pemicunya
|
|
128
189
|
`<button>`, yang **bukan** elemen labelable, sehingga `<label for>` memang tak akan pernah
|
|
129
|
-
mengaktifkannya
|
|
190
|
+
mengaktifkannya, dan itu kini didokumentasikan.
|
|
130
191
|
- **`FreedayTimepicker.setState(root, { disabled, readonly, invalid })`** (`#094`), bentuknya sama
|
|
131
192
|
dengan `FreedayDatepicker.setState`. Tanpa ini, host yang merender seed-nya sekali lalu tidak
|
|
132
193
|
pernah lagi (Blazor, `ShouldRender => false`) memiliki tiga parameter keadaan yang tak ada yang
|
|
@@ -136,7 +197,7 @@ lokal, dan kini diuji, adalah perilaku penggantinya.
|
|
|
136
197
|
- **`FdyDateRange` membuang kedelapan prop label navigasi kalender** (`#095`), di ketiga stack.
|
|
137
198
|
`FdyDatepicker` menerimanya sejak 2.1.1; rentangnya tidak meneruskannya, sehingga rentang tanggal
|
|
138
199
|
adalah **satu-satunya** kontrol tanggal di kit yang navigasinya tak bisa dinamai dalam bahasa
|
|
139
|
-
halamannya sendiri
|
|
200
|
+
halamannya sendiri: aplikasi berbahasa Indonesia mendapat "Previous month" tepat di tempat yang
|
|
140
201
|
tak dapat ia jangkau. Diteruskan apa adanya ke kedua pemilih. Prop datar `xxxLabel`, bukan objek
|
|
141
202
|
`labels`, sebab bentuk itulah yang sudah dipakai setiap komponen lain di kit. Blazor menambah
|
|
142
203
|
`BackToMonthsLabel`, karena seed yang kedua pemilihnya dibangun dari situ punya tombol itu.
|
package/COMPONENTS.md
CHANGED
|
@@ -32,6 +32,10 @@ live docs.
|
|
|
32
32
|
state *and* the screen-reader state. Pair it with `aria-describedby` → the `id` of a
|
|
33
33
|
`.fdy-help.fdy-help--error`. The `--error` class modifiers exist only for the case where the
|
|
34
34
|
invalid state does not belong to the control itself.
|
|
35
|
+
**`--error` names a field's validation state, `--danger` names a tone** (button, alert, badge,
|
|
36
|
+
toast, menu item). `.fdy-help` is the one block that takes both, `--danger` being the same
|
|
37
|
+
colour, because help text is where either reading is natural: a sentence that warns without
|
|
38
|
+
any field being invalid.
|
|
35
39
|
6. **Interactive components need their enhancer script.** Static ones (button, card, badge, table,
|
|
36
40
|
alert, breadcrumb, timeline, accordion, tree-without-cascade…) are CSS-only.
|
|
37
41
|
7. **On Vue, React or Blazor, thirteen components have a typed wrapper. Use it.** `FdyCombo` ·
|
|
@@ -44,6 +48,10 @@ live docs.
|
|
|
44
48
|
breaks quietly: later-rendered DOM is never hydrated and the widget's state sits in the DOM
|
|
45
49
|
instead of your framework's. Everything else is the same markup everywhere; hydrate the other
|
|
46
50
|
interactive components with `useFreeday` (Vue/React) or `FreedayBlazor.initAll` (Blazor).
|
|
51
|
+
**Markup no `initAll` reached says so.** The first click, focus or submit inside a hook the kit
|
|
52
|
+
never enhanced logs one `console.warn` naming it, with the element attached. The usual cause is
|
|
53
|
+
a `useFreeday()` ref on a wrapper that does not contain it. `freeday-unhydrated.js` does this,
|
|
54
|
+
and it ships in the root import.
|
|
47
55
|
|
|
48
56
|
### Containment — why the kit's containers are `position:relative`
|
|
49
57
|
|
|
@@ -562,7 +570,7 @@ native control, otherwise a `<div>` + explicitly associated label.
|
|
|
562
570
|
`.fdy-field--full` on the fields — **not** a `max-width` override on the container. Both of this
|
|
563
571
|
kit's own consoles wrote that override, once per form, before this modifier reached outside the
|
|
564
572
|
grid.
|
|
565
|
-
- `.fdy-label` (+`--required`) · `.fdy-input` (+`--error`) · `.fdy-textarea` · `.fdy-help` (+`--error`)
|
|
573
|
+
- `.fdy-label` (+`--required`) · `.fdy-input` (+`--error`) · `.fdy-textarea` · `.fdy-help` (+`--error`, or its alias `--danger`)
|
|
566
574
|
|
|
567
575
|
**Grouped controls are a `<fieldset>`, not a new block.** Put `.fdy-field` on the fieldset and
|
|
568
576
|
`.fdy-label` on the legend. The kit already resets the UA border/padding and supplies the spacing:
|
|
@@ -1214,6 +1222,9 @@ zone.addEventListener('fdy-upload-add', (e) => {
|
|
|
1214
1222
|
zone.addEventListener('fdy-upload-remove', (e) => forget(e.detail.file)); // same element
|
|
1215
1223
|
```
|
|
1216
1224
|
|
|
1225
|
+
`fdy-upload-remove` is **cancelable** too: `preventDefault()` keeps the row, for a file the server
|
|
1226
|
+
already holds and the user should confirm losing. Remove it yourself afterwards with `row.el.remove()`.
|
|
1227
|
+
|
|
1217
1228
|
**Bring your own row:** omit the file list entirely (no `data-filelist`, and no `.fdy-filelist`
|
|
1218
1229
|
sibling) and the enhancer renders nothing while still dispatching `fdy-upload-add`, where `detail.row`
|
|
1219
1230
|
still works, its element simply isn't attached. Note the fallback when `data-filelist` is absent is
|
|
@@ -1757,6 +1768,10 @@ responsive `.fdy-datatable` should become below `md`, rather than a stack of `.f
|
|
|
1757
1768
|
control in the kit. Do not hand-roll it: an undimmed row that still lights up under the pointer
|
|
1758
1769
|
reads as clickable while it is refusing input.
|
|
1759
1770
|
- Not `.fdy-list-reset`, which only strips UA bullets/indent from a semantic list.
|
|
1771
|
+
- Not for three bullet points in a dialog either. **A plain bulleted list is a plain `<ul>`/`<ol>`,
|
|
1772
|
+
no class**, and that is supported: `base.css` deliberately leaves lists alone, so native bullets
|
|
1773
|
+
and indent survive (a test keeps it that way). The exception is a utility framework run with its
|
|
1774
|
+
preflight on, which strips them.
|
|
1760
1775
|
|
|
1761
1776
|
```html
|
|
1762
1777
|
<ul class="fdy-list">
|
|
@@ -2335,6 +2350,21 @@ Three roles inside a `.fdy-chips` row:
|
|
|
2335
2350
|
|
|
2336
2351
|
Interactive chips are managed by `freeday-chip.js`: wrap the row in `data-fdy-chips` (+
|
|
2337
2352
|
`data-single` for pick-one, `data-label` for the group name), give each `data-value`.
|
|
2353
|
+
|
|
2354
|
+
**Removal is cancelable.** Pressing `.fdy-chip__remove` fires `fdy-chip-remove` (`detail.value`) on
|
|
2355
|
+
the chip, then removes the chip only if no listener called `preventDefault()`. Cancel it whenever
|
|
2356
|
+
the removal is the app's call: a confirm step, or chips rendered from framework state, which
|
|
2357
|
+
should leave the DOM when the state changes and not before. Without that, Cancel in your own
|
|
2358
|
+
confirm dialog leaves the data intact and the chip gone.
|
|
2359
|
+
|
|
2360
|
+
```js
|
|
2361
|
+
row.addEventListener('fdy-chip-remove', async (e) => {
|
|
2362
|
+
e.preventDefault(); // the kit leaves the chip alone
|
|
2363
|
+
if (await Freeday.confirm({ title: `Remove ${e.detail.value}?`, tone: 'danger' })) {
|
|
2364
|
+
removeFromState(e.detail.value); // your render takes it out
|
|
2365
|
+
}
|
|
2366
|
+
});
|
|
2367
|
+
```
|
|
2338
2368
|
`--tone-1`…`--tone-8` for non-semantic category colours.
|
|
2339
2369
|
|
|
2340
2370
|
## Timeline — `.fdy-timeline`
|
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.13.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`.
|
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.13.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`.
|
|
@@ -26,10 +26,19 @@
|
|
|
26
26
|
if (bp === last) return;
|
|
27
27
|
last = bp;
|
|
28
28
|
root.setAttribute('data-breakpoint', bp);
|
|
29
|
-
|
|
29
|
+
fillLabels(document);
|
|
30
|
+
root.dispatchEvent(new CustomEvent('fdy-breakpoint-change', { bubbles: true, detail: { breakpoint: bp } }));
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/* Also run over late-mounted markup by the stack helpers, which find it through initAll: a label
|
|
34
|
+
rendered after load otherwise stayed empty until the next breakpoint change. */
|
|
35
|
+
function fillLabels(context) {
|
|
36
|
+
var ctx = context || document;
|
|
37
|
+
var bp = last || current();
|
|
38
|
+
if (ctx.matches && ctx.matches('[data-fdy-breakpoint-label]')) ctx.textContent = bp;
|
|
39
|
+
Array.prototype.forEach.call(ctx.querySelectorAll('[data-fdy-breakpoint-label]'), function (el) {
|
|
30
40
|
el.textContent = bp;
|
|
31
41
|
});
|
|
32
|
-
root.dispatchEvent(new CustomEvent('fdy-breakpoint-change', { bubbles: true, detail: { breakpoint: bp } }));
|
|
33
42
|
}
|
|
34
43
|
|
|
35
44
|
window.addEventListener('resize', update, { passive: true });
|
|
@@ -40,6 +49,7 @@
|
|
|
40
49
|
}
|
|
41
50
|
|
|
42
51
|
window.FreedayBreakpoint = {
|
|
52
|
+
initAll: fillLabels,
|
|
43
53
|
get: function () { return last || current(); },
|
|
44
54
|
current: current,
|
|
45
55
|
// true if the current breakpoint is `name` or wider (e.g. is('md') → md, lg, or xl)
|
package/dist/freeday-cfl.js
CHANGED
|
@@ -240,5 +240,7 @@
|
|
|
240
240
|
initTriggers();
|
|
241
241
|
}
|
|
242
242
|
|
|
243
|
-
|
|
243
|
+
/* initAll is what every stack helper looks for (useFreeday in Vue and React, FreedayBlazor.initAll):
|
|
244
|
+
without it they skipped this enhancer, and raw CFL markup rendered by a framework never opened. */
|
|
245
|
+
window.FreedayCfl = { init: initTriggers, initAll: initTriggers };
|
|
244
246
|
})();
|
package/dist/freeday-chip.js
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
/* Freeday, chip enhancer (optional, zero-dependency).
|
|
2
2
|
* Two behaviours, both progressive enhancement:
|
|
3
3
|
*
|
|
4
|
-
* 1. Removable chips, any .fdy-chip__remove button
|
|
5
|
-
*
|
|
4
|
+
* 1. Removable chips, any .fdy-chip__remove button emits a bubbling, CANCELABLE
|
|
5
|
+
* "fdy-chip-remove" (detail {value}) and then removes its chip, unless a listener called
|
|
6
|
+
* preventDefault(). Cancel it whenever the app owns the removal: a confirm step, or a chip
|
|
7
|
+
* rendered from framework state, which should leave the DOM when the state does.
|
|
6
8
|
* 2. Choice / filter groups, a [data-fdy-chips] container of interactive chips
|
|
7
9
|
* (.fdy-chip--choice / .fdy-chip--filter, each a <button>) toggles aria-pressed
|
|
8
10
|
* on click. Add data-single for one-at-a-time (radio-like) selection; filter
|
|
@@ -28,8 +30,12 @@
|
|
|
28
30
|
if (rm) rm.remove();
|
|
29
31
|
value = (clone.textContent || '').trim();
|
|
30
32
|
}
|
|
31
|
-
|
|
32
|
-
|
|
33
|
+
/* Cancelable, because the kit cannot know whether this removal needs asking first. Removing
|
|
34
|
+
unconditionally made a chip vanish while the app's own confirm dialog was still open, and
|
|
35
|
+
stay gone after Cancel, with the data intact and the screen wrong (CATATAN-FREEDAY §9). */
|
|
36
|
+
var ev = new CustomEvent('fdy-chip-remove', { bubbles: true, cancelable: true, detail: { value: value } });
|
|
37
|
+
chip.dispatchEvent(ev);
|
|
38
|
+
if (!ev.defaultPrevented) chip.remove();
|
|
33
39
|
});
|
|
34
40
|
}
|
|
35
41
|
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/* Freeday, un-hydrated hook warning (optional, zero-dependency, no markup of its own).
|
|
2
|
+
* Every enhancer marks the element it took over (`data-fdy-*-ready`). Markup that no initAll()
|
|
3
|
+
* ever reached carries the hook and not the mark, and it fails in the worst way available: it
|
|
4
|
+
* renders, looks finished, and does nothing, with no error anywhere. A `data-fdy-validate` form
|
|
5
|
+
* outside the subtree handed to useFreeday() neither paints a message nor fires fdy-form-valid,
|
|
6
|
+
* so its save button reads as dead (CATATAN-FREEDAY §10). The enhancer knows the attribute is
|
|
7
|
+
* there; the person who wrote it does not.
|
|
8
|
+
*
|
|
9
|
+
* So on the first click, focus or submit inside such an element this logs ONE console.warn per
|
|
10
|
+
* element, naming the hook, with the element itself as the second argument so devtools links it.
|
|
11
|
+
* Interaction, not load, is the trigger on purpose: a framework mounts and hydrates in between,
|
|
12
|
+
* and only once a person is touching the widget is "not enhanced yet" the same as "never".
|
|
13
|
+
*
|
|
14
|
+
* HOOKS pairs each hook selector with the ready flag its enhancer stamps on THAT element and the
|
|
15
|
+
* namespace that owns it. A hook whose enhancer is not loaded is skipped: that is a different
|
|
16
|
+
* mistake, and this message would misname it. test/docs.test.mjs fails if an enhancer gains a
|
|
17
|
+
* ready flag this table does not list.
|
|
18
|
+
*/
|
|
19
|
+
(function () {
|
|
20
|
+
'use strict';
|
|
21
|
+
|
|
22
|
+
var HOOKS = [
|
|
23
|
+
['[data-fdy-app]', 'fdyAppShellReady', 'FreedayAppShell'],
|
|
24
|
+
['[data-fdy-autocomplete]', 'fdyAcReady', 'FreedayAutocomplete'],
|
|
25
|
+
['[data-fdy-carousel]', 'fdyCarouselReady', 'FreedayCarousel'],
|
|
26
|
+
['[data-fdy-cascade]', 'fdyCascadeReady', 'FreedayCascade'],
|
|
27
|
+
['[data-fdy-cfl]', 'fdyCflBound', 'FreedayCfl'],
|
|
28
|
+
['[data-fdy-cfl-open]', 'fdyCflBound', 'FreedayCfl'],
|
|
29
|
+
['[data-fdy-chart]', 'fdyChartReady', 'FreedayChart'],
|
|
30
|
+
['[data-fdy-chips]', 'fdyChipsReady', 'FreedayChip'],
|
|
31
|
+
['.fdy-chip__remove', 'fdyChipRmReady', 'FreedayChip'],
|
|
32
|
+
['[data-fdy-datepicker]', 'fdyDpReady', 'FreedayDatepicker'],
|
|
33
|
+
['[data-fdy-daterange]', 'fdyDrReady', 'FreedayDatepicker'],
|
|
34
|
+
['[data-fdy-datetimepicker]', 'fdyDtReady', 'FreedayDatetime'],
|
|
35
|
+
['[data-fdy-drawer]', 'fdyDrawerBound', 'FreedayDrawer'],
|
|
36
|
+
['.fdy-drawer', 'fdyDrawerReady', 'FreedayDrawer'],
|
|
37
|
+
['[data-fdy-validate]', 'fdyFormReady', 'FreedayForm'],
|
|
38
|
+
['[data-fdy-mask]', 'fdyMaskReady', 'FreedayMask'],
|
|
39
|
+
['[data-fdy-password]', 'fdyPwReady', 'FreedayMask'],
|
|
40
|
+
['[data-fdy-menu]', 'fdyMenuReady', 'FreedayMenu'],
|
|
41
|
+
['[data-fdy-number]', 'fdyNumberReady', 'FreedayNumber'],
|
|
42
|
+
['[data-fdy-rating]', 'fdyRatingReady', 'FreedayRating'],
|
|
43
|
+
['[data-fdy-search]', 'fdySearchReady', 'FreedaySearch'],
|
|
44
|
+
['[data-fdy-combo]', 'fdyComboReady', 'FreedayCombo'],
|
|
45
|
+
['[data-fdy-slider]', 'fdySliderReady', 'FreedaySlider'],
|
|
46
|
+
['[data-fdy-stepper]', 'fdyStepperReady', 'FreedayStepper'],
|
|
47
|
+
['[data-fdy-table]', 'fdyTableReady', 'FreedayTable'],
|
|
48
|
+
['[data-fdy-tabs]', 'fdyTabsReady', 'FreedayTabs'],
|
|
49
|
+
['[data-fdy-timepicker]', 'fdyTpReady', 'FreedayTimepicker'],
|
|
50
|
+
['[data-fdy-tree]', 'fdyTreeReady', 'FreedayTree'],
|
|
51
|
+
['[data-fdy-dropzone]', 'fdyUploadReady', 'FreedayUpload']
|
|
52
|
+
];
|
|
53
|
+
|
|
54
|
+
var warned = typeof WeakSet === 'function' ? new WeakSet() : null;
|
|
55
|
+
|
|
56
|
+
function check(e) {
|
|
57
|
+
if (!warned || !e.target || !e.target.closest) return;
|
|
58
|
+
for (var i = 0; i < HOOKS.length; i++) {
|
|
59
|
+
var hook = HOOKS[i];
|
|
60
|
+
if (!window[hook[2]]) continue;
|
|
61
|
+
var el = e.target.closest(hook[0]);
|
|
62
|
+
if (!el || el.dataset[hook[1]] === '1' || warned.has(el)) continue;
|
|
63
|
+
warned.add(el);
|
|
64
|
+
console.warn('Freeday: this ' + hook[0] + ' was never enhanced, so it does nothing. Either it is '
|
|
65
|
+
+ 'outside every initAll() scope (Vue/React: inside the element given to useFreeday(); Blazor: '
|
|
66
|
+
+ 'FreedayBlazor.initAll after render; anything else: ' + hook[2] + '.initAll(el) once it is in '
|
|
67
|
+
+ 'the DOM), or its markup lacks a part the enhancer needs (see COMPONENTS.md).', el);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
['click', 'focusin', 'submit'].forEach(function (type) {
|
|
72
|
+
document.addEventListener(type, check, true);
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
window.FreedayUnhydrated = { hooks: HOOKS };
|
|
76
|
+
})();
|
package/dist/freeday-upload.js
CHANGED
|
@@ -18,7 +18,8 @@
|
|
|
18
18
|
* Emits bubbling CustomEvents. BOTH on the dropzone element, which is the one target a consumer
|
|
19
19
|
* needs to listen on:
|
|
20
20
|
* "fdy-upload-add" {file, rejected, reason, row}
|
|
21
|
-
* "fdy-upload-remove" {file}
|
|
21
|
+
* "fdy-upload-remove" {file}, cancelable: preventDefault() keeps the row (e.g. to confirm
|
|
22
|
+
* removing a file the server already holds, then call row.el.remove())
|
|
22
23
|
* `row` is the state machine over the rendered .fdy-file:
|
|
23
24
|
* .ready() (rest, where a dropped file starts) / .uploading() / .setProgress(pct) /
|
|
24
25
|
* .waiting(label) (sent, awaiting the server) / .done() / .fail(msg) / .el
|
|
@@ -111,8 +112,9 @@
|
|
|
111
112
|
Firing on both would look safer, but it makes the pair asymmetric, one `add` and, for
|
|
112
113
|
anyone delegating on a common ancestor, two `remove`s, which is its own silent bug. It
|
|
113
114
|
also fixes the listless case: a row that was never attached bubbles to nothing at all. */
|
|
114
|
-
|
|
115
|
-
|
|
115
|
+
var ev = new CustomEvent('fdy-upload-remove', { bubbles: true, cancelable: true, detail: { file: file } });
|
|
116
|
+
zone.dispatchEvent(ev);
|
|
117
|
+
if (!ev.defaultPrevented) el.remove();
|
|
116
118
|
});
|
|
117
119
|
el.appendChild(icon);
|
|
118
120
|
el.appendChild(meta);
|
package/dist/freeday.bundle.css
CHANGED
|
@@ -2696,7 +2696,8 @@ fieldset.fdy-field>legend{padding:0;float:none;margin-bottom:var(--space-2);}
|
|
|
2696
2696
|
remember to mark aria-hidden, and it cannot be forgotten. */
|
|
2697
2697
|
.fdy-label--required::after{content:"*" / "";margin-left:var(--space-1);color:var(--color-danger);}
|
|
2698
2698
|
.fdy-help{font-size:var(--text-xs);color:var(--color-text-muted);}
|
|
2699
|
-
|
|
2699
|
+
/* --danger is the tone word everywhere else in the kit; help text takes either (CATATAN-FREEDAY §11). */
|
|
2700
|
+
.fdy-help--error,.fdy-help--danger{color:var(--color-danger);}
|
|
2700
2701
|
|
|
2701
2702
|
/* Freeday. Keyboard key */
|
|
2702
2703
|
.fdy-kbd{display:inline-flex;align-items:center;justify-content:center;min-width:1.5rem;height:1.5rem;padding:0 var(--space-2);font-family:var(--font-mono);font-size:var(--text-xs);color:var(--color-text);background:var(--color-surface-2);border:var(--bw) solid var(--color-border-strong);border-bottom-width:2px;border-radius:var(--radius-sm);}
|
package/dist/freeday.css
CHANGED
|
@@ -1519,7 +1519,8 @@ fieldset.fdy-field>legend{padding:0;float:none;margin-bottom:var(--space-2);}
|
|
|
1519
1519
|
remember to mark aria-hidden, and it cannot be forgotten. */
|
|
1520
1520
|
.fdy-label--required::after{content:"*" / "";margin-left:var(--space-1);color:var(--color-danger);}
|
|
1521
1521
|
.fdy-help{font-size:var(--text-xs);color:var(--color-text-muted);}
|
|
1522
|
-
|
|
1522
|
+
/* --danger is the tone word everywhere else in the kit; help text takes either (CATATAN-FREEDAY §11). */
|
|
1523
|
+
.fdy-help--error,.fdy-help--danger{color:var(--color-danger);}
|
|
1523
1524
|
|
|
1524
1525
|
/* Freeday. Keyboard key */
|
|
1525
1526
|
.fdy-kbd{display:inline-flex;align-items:center;justify-content:center;min-width:1.5rem;height:1.5rem;padding:0 var(--space-2);font-family:var(--font-mono);font-size:var(--text-xs);color:var(--color-text);background:var(--color-surface-2);border:var(--bw) solid var(--color-border-strong);border-bottom-width:2px;border-radius:var(--radius-sm);}
|
package/dist/freeday.js
CHANGED
|
@@ -409,10 +409,19 @@
|
|
|
409
409
|
if (bp === last) return;
|
|
410
410
|
last = bp;
|
|
411
411
|
root.setAttribute('data-breakpoint', bp);
|
|
412
|
-
|
|
412
|
+
fillLabels(document);
|
|
413
|
+
root.dispatchEvent(new CustomEvent('fdy-breakpoint-change', { bubbles: true, detail: { breakpoint: bp } }));
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
/* Also run over late-mounted markup by the stack helpers, which find it through initAll: a label
|
|
417
|
+
rendered after load otherwise stayed empty until the next breakpoint change. */
|
|
418
|
+
function fillLabels(context) {
|
|
419
|
+
var ctx = context || document;
|
|
420
|
+
var bp = last || current();
|
|
421
|
+
if (ctx.matches && ctx.matches('[data-fdy-breakpoint-label]')) ctx.textContent = bp;
|
|
422
|
+
Array.prototype.forEach.call(ctx.querySelectorAll('[data-fdy-breakpoint-label]'), function (el) {
|
|
413
423
|
el.textContent = bp;
|
|
414
424
|
});
|
|
415
|
-
root.dispatchEvent(new CustomEvent('fdy-breakpoint-change', { bubbles: true, detail: { breakpoint: bp } }));
|
|
416
425
|
}
|
|
417
426
|
|
|
418
427
|
window.addEventListener('resize', update, { passive: true });
|
|
@@ -423,6 +432,7 @@
|
|
|
423
432
|
}
|
|
424
433
|
|
|
425
434
|
window.FreedayBreakpoint = {
|
|
435
|
+
initAll: fillLabels,
|
|
426
436
|
get: function () { return last || current(); },
|
|
427
437
|
current: current,
|
|
428
438
|
// true if the current breakpoint is `name` or wider (e.g. is('md') → md, lg, or xl)
|
|
@@ -1328,7 +1338,9 @@
|
|
|
1328
1338
|
initTriggers();
|
|
1329
1339
|
}
|
|
1330
1340
|
|
|
1331
|
-
|
|
1341
|
+
/* initAll is what every stack helper looks for (useFreeday in Vue and React, FreedayBlazor.initAll):
|
|
1342
|
+
without it they skipped this enhancer, and raw CFL markup rendered by a framework never opened. */
|
|
1343
|
+
window.FreedayCfl = { init: initTriggers, initAll: initTriggers };
|
|
1332
1344
|
})();
|
|
1333
1345
|
|
|
1334
1346
|
/* Freeday, chart renderer (optional, zero-dependency, no external chart lib).
|
|
@@ -1845,8 +1857,10 @@
|
|
|
1845
1857
|
/* Freeday, chip enhancer (optional, zero-dependency).
|
|
1846
1858
|
* Two behaviours, both progressive enhancement:
|
|
1847
1859
|
*
|
|
1848
|
-
* 1. Removable chips, any .fdy-chip__remove button
|
|
1849
|
-
*
|
|
1860
|
+
* 1. Removable chips, any .fdy-chip__remove button emits a bubbling, CANCELABLE
|
|
1861
|
+
* "fdy-chip-remove" (detail {value}) and then removes its chip, unless a listener called
|
|
1862
|
+
* preventDefault(). Cancel it whenever the app owns the removal: a confirm step, or a chip
|
|
1863
|
+
* rendered from framework state, which should leave the DOM when the state does.
|
|
1850
1864
|
* 2. Choice / filter groups, a [data-fdy-chips] container of interactive chips
|
|
1851
1865
|
* (.fdy-chip--choice / .fdy-chip--filter, each a <button>) toggles aria-pressed
|
|
1852
1866
|
* on click. Add data-single for one-at-a-time (radio-like) selection; filter
|
|
@@ -1872,8 +1886,12 @@
|
|
|
1872
1886
|
if (rm) rm.remove();
|
|
1873
1887
|
value = (clone.textContent || '').trim();
|
|
1874
1888
|
}
|
|
1875
|
-
|
|
1876
|
-
|
|
1889
|
+
/* Cancelable, because the kit cannot know whether this removal needs asking first. Removing
|
|
1890
|
+
unconditionally made a chip vanish while the app's own confirm dialog was still open, and
|
|
1891
|
+
stay gone after Cancel, with the data intact and the screen wrong (CATATAN-FREEDAY §9). */
|
|
1892
|
+
var ev = new CustomEvent('fdy-chip-remove', { bubbles: true, cancelable: true, detail: { value: value } });
|
|
1893
|
+
chip.dispatchEvent(ev);
|
|
1894
|
+
if (!ev.defaultPrevented) chip.remove();
|
|
1877
1895
|
});
|
|
1878
1896
|
}
|
|
1879
1897
|
|
|
@@ -5465,6 +5483,83 @@
|
|
|
5465
5483
|
window.FreedayTree = { init: initTree, initAll: initAll };
|
|
5466
5484
|
})();
|
|
5467
5485
|
|
|
5486
|
+
/* Freeday, un-hydrated hook warning (optional, zero-dependency, no markup of its own).
|
|
5487
|
+
* Every enhancer marks the element it took over (`data-fdy-*-ready`). Markup that no initAll()
|
|
5488
|
+
* ever reached carries the hook and not the mark, and it fails in the worst way available: it
|
|
5489
|
+
* renders, looks finished, and does nothing, with no error anywhere. A `data-fdy-validate` form
|
|
5490
|
+
* outside the subtree handed to useFreeday() neither paints a message nor fires fdy-form-valid,
|
|
5491
|
+
* so its save button reads as dead (CATATAN-FREEDAY §10). The enhancer knows the attribute is
|
|
5492
|
+
* there; the person who wrote it does not.
|
|
5493
|
+
*
|
|
5494
|
+
* So on the first click, focus or submit inside such an element this logs ONE console.warn per
|
|
5495
|
+
* element, naming the hook, with the element itself as the second argument so devtools links it.
|
|
5496
|
+
* Interaction, not load, is the trigger on purpose: a framework mounts and hydrates in between,
|
|
5497
|
+
* and only once a person is touching the widget is "not enhanced yet" the same as "never".
|
|
5498
|
+
*
|
|
5499
|
+
* HOOKS pairs each hook selector with the ready flag its enhancer stamps on THAT element and the
|
|
5500
|
+
* namespace that owns it. A hook whose enhancer is not loaded is skipped: that is a different
|
|
5501
|
+
* mistake, and this message would misname it. test/docs.test.mjs fails if an enhancer gains a
|
|
5502
|
+
* ready flag this table does not list.
|
|
5503
|
+
*/
|
|
5504
|
+
(function () {
|
|
5505
|
+
'use strict';
|
|
5506
|
+
|
|
5507
|
+
var HOOKS = [
|
|
5508
|
+
['[data-fdy-app]', 'fdyAppShellReady', 'FreedayAppShell'],
|
|
5509
|
+
['[data-fdy-autocomplete]', 'fdyAcReady', 'FreedayAutocomplete'],
|
|
5510
|
+
['[data-fdy-carousel]', 'fdyCarouselReady', 'FreedayCarousel'],
|
|
5511
|
+
['[data-fdy-cascade]', 'fdyCascadeReady', 'FreedayCascade'],
|
|
5512
|
+
['[data-fdy-cfl]', 'fdyCflBound', 'FreedayCfl'],
|
|
5513
|
+
['[data-fdy-cfl-open]', 'fdyCflBound', 'FreedayCfl'],
|
|
5514
|
+
['[data-fdy-chart]', 'fdyChartReady', 'FreedayChart'],
|
|
5515
|
+
['[data-fdy-chips]', 'fdyChipsReady', 'FreedayChip'],
|
|
5516
|
+
['.fdy-chip__remove', 'fdyChipRmReady', 'FreedayChip'],
|
|
5517
|
+
['[data-fdy-datepicker]', 'fdyDpReady', 'FreedayDatepicker'],
|
|
5518
|
+
['[data-fdy-daterange]', 'fdyDrReady', 'FreedayDatepicker'],
|
|
5519
|
+
['[data-fdy-datetimepicker]', 'fdyDtReady', 'FreedayDatetime'],
|
|
5520
|
+
['[data-fdy-drawer]', 'fdyDrawerBound', 'FreedayDrawer'],
|
|
5521
|
+
['.fdy-drawer', 'fdyDrawerReady', 'FreedayDrawer'],
|
|
5522
|
+
['[data-fdy-validate]', 'fdyFormReady', 'FreedayForm'],
|
|
5523
|
+
['[data-fdy-mask]', 'fdyMaskReady', 'FreedayMask'],
|
|
5524
|
+
['[data-fdy-password]', 'fdyPwReady', 'FreedayMask'],
|
|
5525
|
+
['[data-fdy-menu]', 'fdyMenuReady', 'FreedayMenu'],
|
|
5526
|
+
['[data-fdy-number]', 'fdyNumberReady', 'FreedayNumber'],
|
|
5527
|
+
['[data-fdy-rating]', 'fdyRatingReady', 'FreedayRating'],
|
|
5528
|
+
['[data-fdy-search]', 'fdySearchReady', 'FreedaySearch'],
|
|
5529
|
+
['[data-fdy-combo]', 'fdyComboReady', 'FreedayCombo'],
|
|
5530
|
+
['[data-fdy-slider]', 'fdySliderReady', 'FreedaySlider'],
|
|
5531
|
+
['[data-fdy-stepper]', 'fdyStepperReady', 'FreedayStepper'],
|
|
5532
|
+
['[data-fdy-table]', 'fdyTableReady', 'FreedayTable'],
|
|
5533
|
+
['[data-fdy-tabs]', 'fdyTabsReady', 'FreedayTabs'],
|
|
5534
|
+
['[data-fdy-timepicker]', 'fdyTpReady', 'FreedayTimepicker'],
|
|
5535
|
+
['[data-fdy-tree]', 'fdyTreeReady', 'FreedayTree'],
|
|
5536
|
+
['[data-fdy-dropzone]', 'fdyUploadReady', 'FreedayUpload']
|
|
5537
|
+
];
|
|
5538
|
+
|
|
5539
|
+
var warned = typeof WeakSet === 'function' ? new WeakSet() : null;
|
|
5540
|
+
|
|
5541
|
+
function check(e) {
|
|
5542
|
+
if (!warned || !e.target || !e.target.closest) return;
|
|
5543
|
+
for (var i = 0; i < HOOKS.length; i++) {
|
|
5544
|
+
var hook = HOOKS[i];
|
|
5545
|
+
if (!window[hook[2]]) continue;
|
|
5546
|
+
var el = e.target.closest(hook[0]);
|
|
5547
|
+
if (!el || el.dataset[hook[1]] === '1' || warned.has(el)) continue;
|
|
5548
|
+
warned.add(el);
|
|
5549
|
+
console.warn('Freeday: this ' + hook[0] + ' was never enhanced, so it does nothing. Either it is '
|
|
5550
|
+
+ 'outside every initAll() scope (Vue/React: inside the element given to useFreeday(); Blazor: '
|
|
5551
|
+
+ 'FreedayBlazor.initAll after render; anything else: ' + hook[2] + '.initAll(el) once it is in '
|
|
5552
|
+
+ 'the DOM), or its markup lacks a part the enhancer needs (see COMPONENTS.md).', el);
|
|
5553
|
+
}
|
|
5554
|
+
}
|
|
5555
|
+
|
|
5556
|
+
['click', 'focusin', 'submit'].forEach(function (type) {
|
|
5557
|
+
document.addEventListener(type, check, true);
|
|
5558
|
+
});
|
|
5559
|
+
|
|
5560
|
+
window.FreedayUnhydrated = { hooks: HOOKS };
|
|
5561
|
+
})();
|
|
5562
|
+
|
|
5468
5563
|
/* Freeday, file-upload enhancer (optional, zero-dependency).
|
|
5469
5564
|
* A drop target that also opens the file dialog on click / Enter / Space, validates each file
|
|
5470
5565
|
* (accept + max size), and renders a per-file row with explicit state. Actual upload is the
|
|
@@ -5485,7 +5580,8 @@
|
|
|
5485
5580
|
* Emits bubbling CustomEvents. BOTH on the dropzone element, which is the one target a consumer
|
|
5486
5581
|
* needs to listen on:
|
|
5487
5582
|
* "fdy-upload-add" {file, rejected, reason, row}
|
|
5488
|
-
* "fdy-upload-remove" {file}
|
|
5583
|
+
* "fdy-upload-remove" {file}, cancelable: preventDefault() keeps the row (e.g. to confirm
|
|
5584
|
+
* removing a file the server already holds, then call row.el.remove())
|
|
5489
5585
|
* `row` is the state machine over the rendered .fdy-file:
|
|
5490
5586
|
* .ready() (rest, where a dropped file starts) / .uploading() / .setProgress(pct) /
|
|
5491
5587
|
* .waiting(label) (sent, awaiting the server) / .done() / .fail(msg) / .el
|
|
@@ -5578,8 +5674,9 @@
|
|
|
5578
5674
|
Firing on both would look safer, but it makes the pair asymmetric, one `add` and, for
|
|
5579
5675
|
anyone delegating on a common ancestor, two `remove`s, which is its own silent bug. It
|
|
5580
5676
|
also fixes the listless case: a row that was never attached bubbles to nothing at all. */
|
|
5581
|
-
|
|
5582
|
-
|
|
5677
|
+
var ev = new CustomEvent('fdy-upload-remove', { bubbles: true, cancelable: true, detail: { file: file } });
|
|
5678
|
+
zone.dispatchEvent(ev);
|
|
5679
|
+
if (!ev.defaultPrevented) el.remove();
|
|
5583
5680
|
});
|
|
5584
5681
|
el.appendChild(icon);
|
|
5585
5682
|
el.appendChild(meta);
|
package/docs/agent-onboarding.md
CHANGED
|
@@ -229,4 +229,5 @@ Order of work that avoids a half-migrated mess:
|
|
|
229
229
|
- Keyboard: Tab reaches every control, focus is always visible, Esc closes overlays.
|
|
230
230
|
- Form errors carry `aria-invalid` + a linked message; icon-only buttons have `aria-label`.
|
|
231
231
|
- The interactive components on the screen have their enhancer loaded, and SPA-rendered DOM is
|
|
232
|
-
re-hydrated.
|
|
232
|
+
re-hydrated. Click each one once with devtools open: a `Freeday: this [data-fdy-…] was never
|
|
233
|
+
enhanced` warning means it sits outside every `initAll()` scope.
|
package/docs/getting-started.md
CHANGED
|
@@ -198,7 +198,7 @@ live docs also have a copy button per component.
|
|
|
198
198
|
```bash
|
|
199
199
|
npm i @cahyo-dimas/freeday
|
|
200
200
|
```
|
|
201
|
-
Lands in `package.json` as `"@cahyo-dimas/freeday": "^3.
|
|
201
|
+
Lands in `package.json` as `"@cahyo-dimas/freeday": "^3.13.0"` (public npm package). `dist/` is
|
|
202
202
|
committed and published → no build step; `npm ci` runs without auth.
|
|
203
203
|
|
|
204
204
|
### 2. Import the CSS + enhancers **once** in your entry (`src/main.ts`)
|
package/docs/integrations.md
CHANGED
|
@@ -40,8 +40,8 @@ Every integration comes down to one of these:
|
|
|
40
40
|
| `freeday-mask` | `fdy-mask` `{value,raw}` | `FreedayMask` |
|
|
41
41
|
| `freeday-form` | `fdy-form-invalid` `{invalid}` / `fdy-form-valid` | `FreedayForm` |
|
|
42
42
|
| `freeday-table` | `fdy-table-change` · `fdy-row-select` | `FreedayTable` |
|
|
43
|
-
| `freeday-chip` | `fdy-chip-change` `{value,pressed,selected}` · `fdy-chip-remove` `{value}
|
|
44
|
-
| `freeday-upload` | `fdy-upload-add` / `fdy-upload-remove` | `FreedayUpload` |
|
|
43
|
+
| `freeday-chip` | `fdy-chip-change` `{value,pressed,selected}` · `fdy-chip-remove` `{value}`, cancelable | `FreedayChip` |
|
|
44
|
+
| `freeday-upload` | `fdy-upload-add` / `fdy-upload-remove` (cancelable) | `FreedayUpload` |
|
|
45
45
|
| `freeday-stepper` | `fdy-step-change` | `FreedayStepper` |
|
|
46
46
|
| `freeday-carousel` | `fdy-carousel-change` | `FreedayCarousel` |
|
|
47
47
|
| `freeday-breakpoint` | `fdy-breakpoint-change` | `FreedayBreakpoint` |
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cahyo-dimas/freeday",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.13.0",
|
|
4
4
|
"description": "Freeday: token-driven, framework-agnostic UI KIT (design source-of-truth).",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -96,7 +96,7 @@
|
|
|
96
96
|
"scripts": {
|
|
97
97
|
"build": "node tokens/build.mjs",
|
|
98
98
|
"test": "node --test",
|
|
99
|
-
"test:browser": "node --test --test-concurrency=3 browser/color-mix.mjs browser/vanilla.mjs browser/adapter.mjs browser/layout.mjs browser/theme.mjs browser/state.mjs browser/root-init.mjs browser/upload-states.mjs browser/number.mjs browser/card-stretch.mjs browser/text-override.mjs browser/control-heights.mjs browser/field-width.mjs browser/cfl-multi.mjs browser/cfl-dialog-only.mjs browser/crowding.mjs browser/over-dialog.mjs browser/chart-scale.mjs browser/overlay-stack.mjs browser/chart-a11y.mjs browser/app-shell.mjs browser/bottom-nav.mjs browser/picker-states.mjs browser/tabs-strip.mjs browser/tabs-vertical.mjs browser/menu-align.mjs browser/cfl-narrow.mjs browser/form-reveal.mjs browser/confirm-search-copy.mjs browser/daterange-settled.mjs browser/display-parts.mjs browser/table-empty.mjs browser/table-footer-text.mjs browser/month-mode.mjs browser/monthpicker.mjs browser/page-columns.mjs browser/table-hover.mjs browser/typed-popover.mjs browser/filter-parity.mjs browser/filter-wrap.mjs browser/filter-stack.mjs browser/timepicker.mjs browser/form-kit-required.mjs browser/picker-in-modal.mjs browser/harness-contract.mjs",
|
|
99
|
+
"test:browser": "node --test --test-concurrency=3 browser/color-mix.mjs browser/vanilla.mjs browser/adapter.mjs browser/layout.mjs browser/theme.mjs browser/state.mjs browser/root-init.mjs browser/upload-states.mjs browser/number.mjs browser/card-stretch.mjs browser/text-override.mjs browser/control-heights.mjs browser/field-width.mjs browser/cfl-multi.mjs browser/cfl-dialog-only.mjs browser/crowding.mjs browser/over-dialog.mjs browser/chart-scale.mjs browser/overlay-stack.mjs browser/chart-a11y.mjs browser/app-shell.mjs browser/bottom-nav.mjs browser/picker-states.mjs browser/tabs-strip.mjs browser/tabs-vertical.mjs browser/menu-align.mjs browser/cfl-narrow.mjs browser/form-reveal.mjs browser/confirm-search-copy.mjs browser/daterange-settled.mjs browser/display-parts.mjs browser/table-empty.mjs browser/table-footer-text.mjs browser/month-mode.mjs browser/monthpicker.mjs browser/page-columns.mjs browser/table-hover.mjs browser/typed-popover.mjs browser/filter-parity.mjs browser/filter-wrap.mjs browser/filter-stack.mjs browser/timepicker.mjs browser/form-kit-required.mjs browser/picker-in-modal.mjs browser/harness-contract.mjs browser/app-owned.mjs",
|
|
100
100
|
"prepack": "node tokens/build.mjs",
|
|
101
101
|
"version": "node tokens/build.mjs && git add dist",
|
|
102
102
|
"typecheck:react": "tsc -p adapters/react/tsconfig.json --noEmit",
|
package/src/components/input.css
CHANGED
|
@@ -56,4 +56,5 @@ fieldset.fdy-field>legend{padding:0;float:none;margin-bottom:var(--space-2);}
|
|
|
56
56
|
remember to mark aria-hidden, and it cannot be forgotten. */
|
|
57
57
|
.fdy-label--required::after{content:"*" / "";margin-left:var(--space-1);color:var(--color-danger);}
|
|
58
58
|
.fdy-help{font-size:var(--text-xs);color:var(--color-text-muted);}
|
|
59
|
-
|
|
59
|
+
/* --danger is the tone word everywhere else in the kit; help text takes either (CATATAN-FREEDAY §11). */
|
|
60
|
+
.fdy-help--error,.fdy-help--danger{color:var(--color-danger);}
|