@cahyo-dimas/freeday 3.0.0 → 3.1.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 +74 -0
- package/COMPONENTS.md +26 -2
- package/README.id.md +1 -1
- package/README.md +1 -1
- package/adapters/blazor/FdyTableFooter.razor +1 -1
- package/adapters/react/components/FdyTableFooter.tsx +1 -1
- package/adapters/vue/components/FdyTableFooter.vue +1 -1
- package/dist/freeday-table.js +7 -0
- package/dist/freeday.bundle.css +38 -6
- package/dist/freeday.css +37 -5
- package/dist/freeday.js +7 -0
- package/docs/getting-started.md +1 -1
- package/package.json +2 -2
- package/src/components/busy.css +10 -1
- package/src/components/composition.css +15 -2
- package/src/components/filterbar.css +3 -2
- package/src/components/input.css +9 -0
package/CHANGELOG.md
CHANGED
|
@@ -9,6 +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.1.0] - 2026-08-27
|
|
13
|
+
|
|
14
|
+
**Dua cacat lebar yang dilaporkan dari layar sungguhan, dan keduanya tak kelihatan di DOM.** Markup-nya
|
|
15
|
+
benar, class-nya benar, kotaknya cuma berhenti lebih awal. Rilis ini juga membuat satu kalimat
|
|
16
|
+
`COMPONENTS.md` jadi benar setelah lama tidak.
|
|
17
|
+
|
|
18
|
+
### Fixed
|
|
19
|
+
- **Kontrol di dalam `.fdy-field` kini selebar field-nya** (`improvement-notes` #051, dari
|
|
20
|
+
`IDU_EMATE_APPL_WEB` dan `IDU_EMATE_ACCT_WEB`). `.fdy-input-group`, `.fdy-combo`,
|
|
21
|
+
`.fdy-autocomplete` dan `.fdy-cascade` masing-masing di-cap `22rem` — cap untuk kontrol yang
|
|
22
|
+
berdiri sendiri, tanpa field yang bisa memberinya lebar — dan cap itu hanya dilepas **di satu
|
|
23
|
+
container**, `.fdy-filterbar`, yang menyebut dua dari empatnya. Akibatnya baris `--full` di
|
|
24
|
+
`.fdy-form-grid` memegang combo 352px di bawah label 600px, sementara `.fdy-input`
|
|
25
|
+
di sebelahnya (yang tak pernah punya cap) mengisi penuh: satu form terlihat tak sejajar dengan
|
|
26
|
+
dirinya sendiri. Yang paling mahal justru versi yang dilaporkan pengguna tanpa diminta — *"jarak
|
|
27
|
+
search ke filter status agak jauh, ya?"* — pada toolbar dengan field `26rem`: kontrolnya 352px,
|
|
28
|
+
jadi **64px ruang mati ada DI DALAM field**, dan `gap:var(--space-3)` yang ditulis penulisnya
|
|
29
|
+
terbaca 76px di layar. Tak ada satu pun langkah debug yang wajar bisa melihatnya: gap-nya benar,
|
|
30
|
+
flex-nya benar.
|
|
31
|
+
Perbaikannya satu aturan di `input.css`, bukan selector ketiga di samping filterbar, dan bentuknya
|
|
32
|
+
**sudah ada di kit sejak #017** — `.fdy-field>.fdy-datepicker` melepas cap picker dengan komentar
|
|
33
|
+
"a picker fills the field *like every other control*". Kalimat itu tidak benar untuk empat kontrol
|
|
34
|
+
di atas, dan sekarang benar. Cap `22rem` tetap ada **di `.fdy-field`**, jadi field yang tak
|
|
35
|
+
dilebarkan siapa pun tak berubah sedikit pun.
|
|
36
|
+
Ikut terangkat, dan tak ada di laporan mana pun: `.fdy-autocomplete` dan `.fdy-cascade` di field
|
|
37
|
+
`--w-2xl` (25rem) berhenti 48px lebih pendek **di dalam filterbar sendiri** — container yang kit
|
|
38
|
+
kira sudah beres. Aturan lama di `filterbar.css` dihapus, bukan dibiarkan di samping yang baru:
|
|
39
|
+
dua aturan yang mengatakan hal sama persis adalah cara filterbar jadi tahu sesuatu yang tak
|
|
40
|
+
diketahui `input.css`.
|
|
41
|
+
- **`.fdy-pagination` akhirnya benar-benar dikirim** (#050 §2). `COMPONENTS.md` menyuruh konsumen
|
|
42
|
+
menulis `<nav class="fdy-pagination" data-fdy-table-pagination>`, dan class blok itu **nol match di
|
|
43
|
+
seluruh paket** — bukan di enhancer, bukan di tiga footer typed. Tak ada yang tampak berbeda,
|
|
44
|
+
karena blok itu memang tak punya rule (`NEXT-UP` #9), tapi selector konsumen atau asersi e2e pada
|
|
45
|
+
blok itu **lulus terhadap markup tulisan tangan dan gagal terhadap keluaran kit sendiri**, padahal
|
|
46
|
+
kedua jalur seharusnya bisa saling menggantikan. Enhancer kini menyetelnya sekali saat init;
|
|
47
|
+
`FdyTableFooter` Vue/React/Blazor merendernya.
|
|
48
|
+
|
|
49
|
+
### Added
|
|
50
|
+
- **`.fdy-stats--inline`** — strip KPI yang **memeluk angkanya** alih-alih membentang, untuk yang
|
|
51
|
+
duduk di samping judul halaman (#050 §1). Ini jawaban atas cacat yang tak bisa diperbaiki dengan
|
|
52
|
+
dokumentasi saja: `.fdy-stat` membawa `container-type:inline-size` (itu yang memberi `__value`
|
|
53
|
+
tipe fluidnya), dan **inline-size containment berarti tile tak menyumbang lebar intrinsik sama
|
|
54
|
+
sekali**. Jadi floor `11rem` bawaan bukan pilihan rasa — ia satu-satunya yang memberi track itu
|
|
55
|
+
ukuran — dan konsumen yang me-retrack grid ke konten mendapat tiga track nol: tiga label saling
|
|
56
|
+
menimpa (`COMPAMEMBERSTA…`) dan halaman meluber ke samping. Terukur dari header
|
|
57
|
+
`IDU_EMATE_ACCT_WEB`: strip 40px, seluruhnya gap. `justify-items` lebih tajam lagi — apa pun
|
|
58
|
+
selain `stretch` mengecilkan tile ke sumbangan nol itu **walau track-nya sudah benar lebarnya**.
|
|
59
|
+
`--inline` melepas container-nya, jadi tile-nya berukuran sesuai kontennya sendiri dan `__value`
|
|
60
|
+
memakai `--text-3xl` datar: track yang seukuran kontennya tak pernah jadi track sempit yang
|
|
61
|
+
membuat tipe fluid itu ada. Konsumen tak perlu lagi menebak floor sendiri.
|
|
62
|
+
|
|
63
|
+
### Docs
|
|
64
|
+
- **`COMPONENTS.md` §Stats akhirnya menyebut containment-nya.** `container-type`, `cqw`,
|
|
65
|
+
`inline-size` dan `contain` nol match di seluruh berkas itu sebelum rilis ini, padahal detail
|
|
66
|
+
implementasi tipe `__value` itu bocor langsung ke kontrak layout siapa pun yang me-retrack grid-nya.
|
|
67
|
+
Kini tertulis sebagai batasan: override `grid-template-columns` wajib punya floor eksplisit, dan
|
|
68
|
+
`justify-items` harus tetap `stretch`.
|
|
69
|
+
- **§Field menyebut cap-nya.** `22rem` dan `max-width` juga nol match di `COMPONENTS.md` sebelum ini,
|
|
70
|
+
jadi cap maupun pengecualian filterbar-nya hanya bisa ditemukan dengan mengukur form yang sudah
|
|
71
|
+
dirender. Aturannya sekarang satu kalimat: **beri ukuran pada field, jangan pada kontrolnya.**
|
|
72
|
+
|
|
73
|
+
### Guarded
|
|
74
|
+
- `test/css.test.mjs`: bentuk CSS-nya — keempat kontrol dilepas di `.fdy-field`, `.fdy-field`
|
|
75
|
+
mempertahankan cap-nya sendiri, aturan filterbar lama tak boleh kembali, dan `--inline` harus
|
|
76
|
+
keluar dari container maupun clamp `cqw`-nya.
|
|
77
|
+
- `browser/field-width.mjs` (6 test, Chrome sungguhan): hasilnya — keduanya adalah **outcome layout**
|
|
78
|
+
yang tak terlihat di stylesheet. Termasuk asersi bahwa gap yang terlihat pembaca sama dengan gap
|
|
79
|
+
yang ditulis penulisnya, dan tile `--inline` diukur terhadap referensi yang berukuran-konten
|
|
80
|
+
secara konstruksi, bukan sekadar "bukan nol": tanpa itu, satu track yang masih memegang floor
|
|
81
|
+
`11rem` lolos karena strip-nya tetap masuk akal.
|
|
82
|
+
- `test/docs.test.mjs`: berkas mana pun yang merender `__element` sebuah blok harus menyebut bloknya.
|
|
83
|
+
Dicari **secara struktur**, bukan dari daftar empat berkas yang salah — renderer pager kelima
|
|
84
|
+
adalah yang tak akan diingat siapa pun.
|
|
85
|
+
|
|
12
86
|
## [3.0.0] - 2026-08-26
|
|
13
87
|
|
|
14
88
|
**Kenapa MAJOR padahal rilis ini seluruhnya aditif.** Tak ada satu pun perubahan di bawah yang
|
package/COMPONENTS.md
CHANGED
|
@@ -227,7 +227,22 @@ carry the doctrine in markup.
|
|
|
227
227
|
sits half a label-height low in it, so labelled fields belong in `.fdy-filterbar`
|
|
228
228
|
(`align-items:flex-end`). In a toolbar, hide the label with `.fdy-visually-hidden`.
|
|
229
229
|
- `.fdy-stats` is a KPI grid of `.fdy-stat` (`__label` `__value` `__meta`). Deliberately **not**
|
|
230
|
-
cards. `.fdy-stats--boxed` for one shared surface with dividers
|
|
230
|
+
cards. `.fdy-stats--boxed` for one shared surface with dividers; `.fdy-stats--inline` for a strip
|
|
231
|
+
that **hugs its numbers** instead of spanning the row, which is what a page header wants.
|
|
232
|
+
- **A `.fdy-stat` in the default grid is size-contained, and that constrains what you may override.**
|
|
233
|
+
It carries `container-type:inline-size` — that is what gives `__value` its fluid type — and
|
|
234
|
+
inline-size containment means the tile contributes **no intrinsic width**. Two consequences, and
|
|
235
|
+
re-tracking the grid hits both at once:
|
|
236
|
+
- Content-based track sizing cannot work: `auto`, `max-content`, `min-content` and `minmax(0, …)`
|
|
237
|
+
all resolve to a **zero** track. The default `minmax(11rem, 1fr)` floor is not a style choice,
|
|
238
|
+
it is the only thing giving these tracks a size, so **any `grid-template-columns` override needs
|
|
239
|
+
an explicit floor of its own**.
|
|
240
|
+
- `justify-items` must stay `stretch`. A non-stretched grid item is sized to its (zero)
|
|
241
|
+
contribution, so `start` collapses the tile to nothing **even when the track is correctly wide**.
|
|
242
|
+
|
|
243
|
+
Use `--inline` rather than working around either: it drops the container, so its tiles size to
|
|
244
|
+
their own content, and its `__value` keeps the flat `--text-3xl`. A hugging track is never the
|
|
245
|
+
narrow track the fluid type exists for.
|
|
231
246
|
|
|
232
247
|
```html
|
|
233
248
|
<div class="fdy-page">
|
|
@@ -409,6 +424,13 @@ native control, otherwise a `<div>` + explicitly associated label.
|
|
|
409
424
|
|
|
410
425
|
- `.fdy-field` (+ `--full` inside `.fdy-form-grid`; widths `--w-sm` `--w-lg` `--w-xl` `--w-2xl`
|
|
411
426
|
`--w-grow` inside `.fdy-filterbar`)
|
|
427
|
+
- **The field owns the width; the control in it follows.** `.fdy-field` caps at `22rem` so a lone
|
|
428
|
+
field does not run the width of the page. `.fdy-form-grid` and `.fdy-filterbar` lift that cap, and
|
|
429
|
+
so does any width you state yourself — and in every one of those cases the control (`.fdy-input`,
|
|
430
|
+
`.fdy-input-group`, `.fdy-combo`, `.fdy-autocomplete`, `.fdy-cascade`, and the pickers) spans the
|
|
431
|
+
field. So **size the field, never the control**: styling the control instead leaves the field
|
|
432
|
+
wider than what is in it, and that dead space is invisible in the DOM — it reads on screen as a
|
|
433
|
+
gap you did not write.
|
|
412
434
|
- `.fdy-label` (+`--required`) · `.fdy-input` (+`--error`) · `.fdy-textarea` · `.fdy-help` (+`--error`)
|
|
413
435
|
|
|
414
436
|
**Grouped controls are a `<fieldset>`, not a new block.** Put `.fdy-field` on the fieldset and
|
|
@@ -1216,7 +1238,9 @@ and breaks the moment the class changes.
|
|
|
1216
1238
|
## Pagination — `.fdy-pagination`
|
|
1217
1239
|
The block class on the `<nav>` is a **structural hook only**. It carries no rule of its own; the
|
|
1218
1240
|
`__list` / `__link` / `__ellipsis` elements do all the styling, and the data table targets
|
|
1219
|
-
`data-fdy-table-pagination`. Keep it on the wrapper anyway, for consistency with the rest of the kit
|
|
1241
|
+
`data-fdy-table-pagination`. Keep it on the wrapper anyway, for consistency with the rest of the kit
|
|
1242
|
+
— and the kit keeps it too: the enhancer sets it on the element it finds, and all three typed
|
|
1243
|
+
footers render it, so a selector or an e2e assertion on the block matches either path.
|
|
1220
1244
|
|
|
1221
1245
|
`<nav class="fdy-pagination" aria-label="Pagination">` → `<ul class="fdy-pagination__list">`;
|
|
1222
1246
|
each item is a `.fdy-pagination__link` (`<button>` when navigable, `<span aria-current="page">`
|
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.1.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.1.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`.
|
|
@@ -75,7 +75,7 @@ export function FdyTableFooter(props: FdyTableFooterProps): JSX.Element | null {
|
|
|
75
75
|
)}
|
|
76
76
|
|
|
77
77
|
{hasPager && (
|
|
78
|
-
<nav aria-label="Pagination">
|
|
78
|
+
<nav className="fdy-pagination" aria-label="Pagination">
|
|
79
79
|
<ul className="fdy-pagination__list">
|
|
80
80
|
<li>
|
|
81
81
|
<button type="button" className="fdy-pagination__link" aria-label="Previous page" disabled={currentPage1 === 1} onClick={(): void => goTo(currentPage1 - 1)}>‹</button>
|
package/dist/freeday-table.js
CHANGED
|
@@ -84,6 +84,13 @@
|
|
|
84
84
|
var countEl = root.querySelector('[data-fdy-table-count]');
|
|
85
85
|
var infoEl = root.querySelector('[data-fdy-table-info]');
|
|
86
86
|
var pagerEl = root.querySelector('[data-fdy-table-pagination]');
|
|
87
|
+
/* COMPONENTS.md documents the wrapper as <nav class="fdy-pagination" data-fdy-table-pagination>
|
|
88
|
+
and nothing in the kit ever wrote that class, here or in the three typed footers (#050 §2).
|
|
89
|
+
It carries no rule (NEXT-UP #9), so nothing rendered differently, but a consumer selector or
|
|
90
|
+
an e2e assertion on the block passed against hand-written markup and failed against the kit's
|
|
91
|
+
own output, and the raw and typed paths are supposed to be interchangeable. Set once at init,
|
|
92
|
+
not per render: the wrapper outlives every pager we build into it. */
|
|
93
|
+
if (pagerEl) pagerEl.classList.add('fdy-pagination');
|
|
87
94
|
var pageSizeEl = root.querySelector('[data-fdy-table-page-size]');
|
|
88
95
|
var selectAll = root.querySelector('[data-fdy-select-all]');
|
|
89
96
|
var pageSize = parseInt(root.getAttribute('data-page-size'), 10) || 0; // 0 = no pagination
|
package/dist/freeday.bundle.css
CHANGED
|
@@ -1242,7 +1242,16 @@ a { color: var(--color-primary); }
|
|
|
1242
1242
|
|
|
1243
1243
|
/* The caption sits on a solid surface, not on the scrim. A scrim is semi-transparent over unknown
|
|
1244
1244
|
* content, so text on it has no computable contrast ratio and no gate could ever cover it. On
|
|
1245
|
-
* --color-surface it is the same pair the contrast suite already checks.
|
|
1245
|
+
* --color-surface it is the same pair the contrast suite already checks.
|
|
1246
|
+
*
|
|
1247
|
+
* THIS IS ALSO WHY THIS PANEL DOES NOT JOIN THE GLASS AXIS, and the omission is a decision rather
|
|
1248
|
+
* than an oversight. Every other raised panel reads --color-surface-raised and frosts under
|
|
1249
|
+
* [data-style="glass"]; this one stays opaque. The glass gate asserts its ink against the panel
|
|
1250
|
+
* composited over the PAGE GROUND (--color-surface-2), which is what sits behind a card or a modal.
|
|
1251
|
+
* Behind this one is the scrim, over arbitrary content — the very case that has no computable
|
|
1252
|
+
* ratio. A frosted busy panel would be the one surface in the kit whose caption nothing could
|
|
1253
|
+
* verify, while it is up precisely because the app is doing something the reader must not
|
|
1254
|
+
* interrupt. Left opaque on purpose; do not "fix" it for consistency. */
|
|
1246
1255
|
.fdy-busy__panel{display:flex;flex-direction:column;align-items:center;gap:var(--space-4);padding:var(--space-6) var(--space-8);border-radius:var(--radius-lg);background:var(--color-surface);box-shadow:var(--shadow-lift);max-width:min(20rem,calc(100vw - var(--space-8)));}
|
|
1247
1256
|
.fdy-busy__mark{display:flex;align-items:center;justify-content:center;min-height:2.5rem;}
|
|
1248
1257
|
.fdy-busy__caption{margin:0;font-size:var(--text-sm);font-weight:var(--weight-medium);color:var(--color-text);text-align:center;}
|
|
@@ -1670,9 +1679,22 @@ a { color: var(--color-primary); }
|
|
|
1670
1679
|
grid track, `container-type:inline-size` on a standalone .fdy-stat would stop it sizing to its
|
|
1671
1680
|
own content. The unconditional rule above stays as the fallback wherever @container is missing. */
|
|
1672
1681
|
@supports (container-type:inline-size){
|
|
1673
|
-
.fdy-stats>.fdy-stat{container-type:inline-size;}
|
|
1674
|
-
.fdy-stats>.fdy-stat .fdy-stat__value{font-size:clamp(var(--text-xl),11cqw,var(--text-3xl));}
|
|
1675
|
-
}
|
|
1682
|
+
.fdy-stats:not(.fdy-stats--inline)>.fdy-stat{container-type:inline-size;}
|
|
1683
|
+
.fdy-stats:not(.fdy-stats--inline)>.fdy-stat .fdy-stat__value{font-size:clamp(var(--text-xl),11cqw,var(--text-3xl));}
|
|
1684
|
+
}
|
|
1685
|
+
/* The price of that container, and the reason --inline opts out of it (#050). `container-type`
|
|
1686
|
+
applies inline-size CONTAINMENT: the tile's min-content and max-content contributions are both
|
|
1687
|
+
ZERO. So the 11rem floor above is not a taste choice, it is the only thing giving these tracks a
|
|
1688
|
+
size, and re-tracking the grid on content (`auto`, `max-content`, `minmax(0,…)`) resolves every
|
|
1689
|
+
track to 0. `justify-items` is the sharper edge: anything but the default `stretch` sizes the
|
|
1690
|
+
tile to that zero contribution even when the track is correctly wide, and three labels paint on
|
|
1691
|
+
top of each other. Measured from IDU_EMATE_ACCT_WEB's page header, where a hugging strip came out
|
|
1692
|
+
40px wide, all of it gap.
|
|
1693
|
+
--inline is the shape that header wanted: a strip that hugs its numbers and sits beside a page
|
|
1694
|
+
title, instead of a full-width band whose 11rem floor collapses to one column at 390px. It cannot
|
|
1695
|
+
have both, so it drops the container and keeps the flat --text-3xl the base rule already sets;
|
|
1696
|
+
a track sized to its own content is never the narrow track the clamp exists for. */
|
|
1697
|
+
.fdy-stats--inline{grid-template-columns:none;grid-auto-flow:column;grid-auto-columns:minmax(0,max-content);}
|
|
1676
1698
|
.fdy-stats--boxed{background:var(--color-surface);border:var(--bw) solid var(--color-border);border-radius:var(--radius-lg);box-shadow:var(--shadow-1);gap:0;}
|
|
1677
1699
|
.fdy-stats--boxed .fdy-stat{padding:var(--space-5);border-right:var(--bw) solid var(--color-border-muted);}
|
|
1678
1700
|
.fdy-stats--boxed .fdy-stat:last-child{border-right:0;}
|
|
@@ -1878,8 +1900,9 @@ a { color: var(--color-primary); }
|
|
|
1878
1900
|
/* Fields are direct children. Drop the standalone field's 22rem cap; default to the
|
|
1879
1901
|
* medium column width with no unbounded growth (that's what caused the raggedness). */
|
|
1880
1902
|
.fdy-filterbar>.fdy-field{max-width:none;flex:0 0 auto;width:12rem;}
|
|
1881
|
-
/* Controls fill their field's column
|
|
1882
|
-
|
|
1903
|
+
/* Controls fill their field's column: released in input.css for every field, not just this one.
|
|
1904
|
+
The rule used to live here, naming the input group and the combo only, which is why an
|
|
1905
|
+
.fdy-autocomplete or an .fdy-cascade in a --w-2xl field still stopped 48px short of it (#051). */
|
|
1883
1906
|
/* Column-width rhythm, pick one per field so bars across the app line up. */
|
|
1884
1907
|
.fdy-filterbar>.fdy-field--w-sm{width:9rem;}
|
|
1885
1908
|
.fdy-filterbar>.fdy-field--w-lg{width:15rem;}
|
|
@@ -1956,6 +1979,15 @@ a { color: var(--color-primary); }
|
|
|
1956
1979
|
|
|
1957
1980
|
/* Freeday. Field & Input */
|
|
1958
1981
|
.fdy-field{display:flex;flex-direction:column;gap:var(--space-2);max-width:22rem;}
|
|
1982
|
+
/* Inside a labelled field, a control fills the field (#051). The 22rem cap those controls carry is
|
|
1983
|
+
for one standing on its own, with no field to take a width from; #017 already released the date
|
|
1984
|
+
and time pickers here for exactly this reason, and its comment claims a picker then fills its
|
|
1985
|
+
field "like every other control". That was not true of these four: a `--full` row in a
|
|
1986
|
+
.fdy-form-grid held a 352px combo under a 600px label, and a 26rem toolbar search field hid 64px
|
|
1987
|
+
of dead space INSIDE itself, so an author who wrote `gap:var(--space-3)` measured 76px on screen.
|
|
1988
|
+
The field's own max-width above is what governs, and it still caps a field nobody has widened, so
|
|
1989
|
+
this changes nothing wherever the cap was already doing its job. */
|
|
1990
|
+
.fdy-field>.fdy-input-group,.fdy-field>.fdy-combo,.fdy-field>.fdy-autocomplete,.fdy-field>.fdy-cascade{max-width:none;}
|
|
1959
1991
|
/* A grouped field is legitimately a <fieldset> (it needs a <legend>), e.g. a radio/checkbox group.
|
|
1960
1992
|
Neutralise the UA groove border / padding / min-inline-size so it lays out identically to the
|
|
1961
1993
|
<div> form (min-inline-size:min-content would otherwise block the filterbar column widths). */
|
package/dist/freeday.css
CHANGED
|
@@ -364,7 +364,16 @@ a { color: var(--color-primary); }
|
|
|
364
364
|
|
|
365
365
|
/* The caption sits on a solid surface, not on the scrim. A scrim is semi-transparent over unknown
|
|
366
366
|
* content, so text on it has no computable contrast ratio and no gate could ever cover it. On
|
|
367
|
-
* --color-surface it is the same pair the contrast suite already checks.
|
|
367
|
+
* --color-surface it is the same pair the contrast suite already checks.
|
|
368
|
+
*
|
|
369
|
+
* THIS IS ALSO WHY THIS PANEL DOES NOT JOIN THE GLASS AXIS, and the omission is a decision rather
|
|
370
|
+
* than an oversight. Every other raised panel reads --color-surface-raised and frosts under
|
|
371
|
+
* [data-style="glass"]; this one stays opaque. The glass gate asserts its ink against the panel
|
|
372
|
+
* composited over the PAGE GROUND (--color-surface-2), which is what sits behind a card or a modal.
|
|
373
|
+
* Behind this one is the scrim, over arbitrary content — the very case that has no computable
|
|
374
|
+
* ratio. A frosted busy panel would be the one surface in the kit whose caption nothing could
|
|
375
|
+
* verify, while it is up precisely because the app is doing something the reader must not
|
|
376
|
+
* interrupt. Left opaque on purpose; do not "fix" it for consistency. */
|
|
368
377
|
.fdy-busy__panel{display:flex;flex-direction:column;align-items:center;gap:var(--space-4);padding:var(--space-6) var(--space-8);border-radius:var(--radius-lg);background:var(--color-surface);box-shadow:var(--shadow-lift);max-width:min(20rem,calc(100vw - var(--space-8)));}
|
|
369
378
|
.fdy-busy__mark{display:flex;align-items:center;justify-content:center;min-height:2.5rem;}
|
|
370
379
|
.fdy-busy__caption{margin:0;font-size:var(--text-sm);font-weight:var(--weight-medium);color:var(--color-text);text-align:center;}
|
|
@@ -792,9 +801,22 @@ a { color: var(--color-primary); }
|
|
|
792
801
|
grid track, `container-type:inline-size` on a standalone .fdy-stat would stop it sizing to its
|
|
793
802
|
own content. The unconditional rule above stays as the fallback wherever @container is missing. */
|
|
794
803
|
@supports (container-type:inline-size){
|
|
795
|
-
.fdy-stats>.fdy-stat{container-type:inline-size;}
|
|
796
|
-
.fdy-stats>.fdy-stat .fdy-stat__value{font-size:clamp(var(--text-xl),11cqw,var(--text-3xl));}
|
|
804
|
+
.fdy-stats:not(.fdy-stats--inline)>.fdy-stat{container-type:inline-size;}
|
|
805
|
+
.fdy-stats:not(.fdy-stats--inline)>.fdy-stat .fdy-stat__value{font-size:clamp(var(--text-xl),11cqw,var(--text-3xl));}
|
|
797
806
|
}
|
|
807
|
+
/* The price of that container, and the reason --inline opts out of it (#050). `container-type`
|
|
808
|
+
applies inline-size CONTAINMENT: the tile's min-content and max-content contributions are both
|
|
809
|
+
ZERO. So the 11rem floor above is not a taste choice, it is the only thing giving these tracks a
|
|
810
|
+
size, and re-tracking the grid on content (`auto`, `max-content`, `minmax(0,…)`) resolves every
|
|
811
|
+
track to 0. `justify-items` is the sharper edge: anything but the default `stretch` sizes the
|
|
812
|
+
tile to that zero contribution even when the track is correctly wide, and three labels paint on
|
|
813
|
+
top of each other. Measured from IDU_EMATE_ACCT_WEB's page header, where a hugging strip came out
|
|
814
|
+
40px wide, all of it gap.
|
|
815
|
+
--inline is the shape that header wanted: a strip that hugs its numbers and sits beside a page
|
|
816
|
+
title, instead of a full-width band whose 11rem floor collapses to one column at 390px. It cannot
|
|
817
|
+
have both, so it drops the container and keeps the flat --text-3xl the base rule already sets;
|
|
818
|
+
a track sized to its own content is never the narrow track the clamp exists for. */
|
|
819
|
+
.fdy-stats--inline{grid-template-columns:none;grid-auto-flow:column;grid-auto-columns:minmax(0,max-content);}
|
|
798
820
|
.fdy-stats--boxed{background:var(--color-surface);border:var(--bw) solid var(--color-border);border-radius:var(--radius-lg);box-shadow:var(--shadow-1);gap:0;}
|
|
799
821
|
.fdy-stats--boxed .fdy-stat{padding:var(--space-5);border-right:var(--bw) solid var(--color-border-muted);}
|
|
800
822
|
.fdy-stats--boxed .fdy-stat:last-child{border-right:0;}
|
|
@@ -1000,8 +1022,9 @@ a { color: var(--color-primary); }
|
|
|
1000
1022
|
/* Fields are direct children. Drop the standalone field's 22rem cap; default to the
|
|
1001
1023
|
* medium column width with no unbounded growth (that's what caused the raggedness). */
|
|
1002
1024
|
.fdy-filterbar>.fdy-field{max-width:none;flex:0 0 auto;width:12rem;}
|
|
1003
|
-
/* Controls fill their field's column
|
|
1004
|
-
|
|
1025
|
+
/* Controls fill their field's column: released in input.css for every field, not just this one.
|
|
1026
|
+
The rule used to live here, naming the input group and the combo only, which is why an
|
|
1027
|
+
.fdy-autocomplete or an .fdy-cascade in a --w-2xl field still stopped 48px short of it (#051). */
|
|
1005
1028
|
/* Column-width rhythm, pick one per field so bars across the app line up. */
|
|
1006
1029
|
.fdy-filterbar>.fdy-field--w-sm{width:9rem;}
|
|
1007
1030
|
.fdy-filterbar>.fdy-field--w-lg{width:15rem;}
|
|
@@ -1078,6 +1101,15 @@ a { color: var(--color-primary); }
|
|
|
1078
1101
|
|
|
1079
1102
|
/* Freeday. Field & Input */
|
|
1080
1103
|
.fdy-field{display:flex;flex-direction:column;gap:var(--space-2);max-width:22rem;}
|
|
1104
|
+
/* Inside a labelled field, a control fills the field (#051). The 22rem cap those controls carry is
|
|
1105
|
+
for one standing on its own, with no field to take a width from; #017 already released the date
|
|
1106
|
+
and time pickers here for exactly this reason, and its comment claims a picker then fills its
|
|
1107
|
+
field "like every other control". That was not true of these four: a `--full` row in a
|
|
1108
|
+
.fdy-form-grid held a 352px combo under a 600px label, and a 26rem toolbar search field hid 64px
|
|
1109
|
+
of dead space INSIDE itself, so an author who wrote `gap:var(--space-3)` measured 76px on screen.
|
|
1110
|
+
The field's own max-width above is what governs, and it still caps a field nobody has widened, so
|
|
1111
|
+
this changes nothing wherever the cap was already doing its job. */
|
|
1112
|
+
.fdy-field>.fdy-input-group,.fdy-field>.fdy-combo,.fdy-field>.fdy-autocomplete,.fdy-field>.fdy-cascade{max-width:none;}
|
|
1081
1113
|
/* A grouped field is legitimately a <fieldset> (it needs a <legend>), e.g. a radio/checkbox group.
|
|
1082
1114
|
Neutralise the UA groove border / padding / min-inline-size so it lays out identically to the
|
|
1083
1115
|
<div> form (min-inline-size:min-content would otherwise block the filterbar column widths). */
|
package/dist/freeday.js
CHANGED
|
@@ -3905,6 +3905,13 @@
|
|
|
3905
3905
|
var countEl = root.querySelector('[data-fdy-table-count]');
|
|
3906
3906
|
var infoEl = root.querySelector('[data-fdy-table-info]');
|
|
3907
3907
|
var pagerEl = root.querySelector('[data-fdy-table-pagination]');
|
|
3908
|
+
/* COMPONENTS.md documents the wrapper as <nav class="fdy-pagination" data-fdy-table-pagination>
|
|
3909
|
+
and nothing in the kit ever wrote that class, here or in the three typed footers (#050 §2).
|
|
3910
|
+
It carries no rule (NEXT-UP #9), so nothing rendered differently, but a consumer selector or
|
|
3911
|
+
an e2e assertion on the block passed against hand-written markup and failed against the kit's
|
|
3912
|
+
own output, and the raw and typed paths are supposed to be interchangeable. Set once at init,
|
|
3913
|
+
not per render: the wrapper outlives every pager we build into it. */
|
|
3914
|
+
if (pagerEl) pagerEl.classList.add('fdy-pagination');
|
|
3908
3915
|
var pageSizeEl = root.querySelector('[data-fdy-table-page-size]');
|
|
3909
3916
|
var selectAll = root.querySelector('[data-fdy-select-all]');
|
|
3910
3917
|
var pageSize = parseInt(root.getAttribute('data-page-size'), 10) || 0; // 0 = no pagination
|
package/docs/getting-started.md
CHANGED
|
@@ -191,7 +191,7 @@ live docs also have a copy button per component.
|
|
|
191
191
|
```bash
|
|
192
192
|
npm i @cahyo-dimas/freeday
|
|
193
193
|
```
|
|
194
|
-
Lands in `package.json` as `"@cahyo-dimas/freeday": "^3.
|
|
194
|
+
Lands in `package.json` as `"@cahyo-dimas/freeday": "^3.1.0"` (public npm package). `dist/` is
|
|
195
195
|
committed and published → no build step; `npm ci` runs without auth.
|
|
196
196
|
|
|
197
197
|
### 2. Import the CSS + enhancers **once** in your entry (`src/main.ts`)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cahyo-dimas/freeday",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.1.0",
|
|
4
4
|
"description": "Freeday: token-driven, framework-agnostic UI KIT (design source-of-truth).",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -92,7 +92,7 @@
|
|
|
92
92
|
"scripts": {
|
|
93
93
|
"build": "node tokens/build.mjs",
|
|
94
94
|
"test": "node --test",
|
|
95
|
-
"test:browser": "node --test --test-concurrency=3 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/cfl-multi.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/picker-states.mjs browser/harness-contract.mjs",
|
|
95
|
+
"test:browser": "node --test --test-concurrency=3 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/crowding.mjs browser/over-dialog.mjs browser/chart-scale.mjs browser/overlay-stack.mjs browser/chart-a11y.mjs browser/app-shell.mjs browser/picker-states.mjs browser/harness-contract.mjs",
|
|
96
96
|
"prepack": "node tokens/build.mjs",
|
|
97
97
|
"version": "node tokens/build.mjs && git add dist",
|
|
98
98
|
"typecheck:react": "tsc -p adapters/react/tsconfig.json --noEmit",
|
package/src/components/busy.css
CHANGED
|
@@ -21,7 +21,16 @@
|
|
|
21
21
|
|
|
22
22
|
/* The caption sits on a solid surface, not on the scrim. A scrim is semi-transparent over unknown
|
|
23
23
|
* content, so text on it has no computable contrast ratio and no gate could ever cover it. On
|
|
24
|
-
* --color-surface it is the same pair the contrast suite already checks.
|
|
24
|
+
* --color-surface it is the same pair the contrast suite already checks.
|
|
25
|
+
*
|
|
26
|
+
* THIS IS ALSO WHY THIS PANEL DOES NOT JOIN THE GLASS AXIS, and the omission is a decision rather
|
|
27
|
+
* than an oversight. Every other raised panel reads --color-surface-raised and frosts under
|
|
28
|
+
* [data-style="glass"]; this one stays opaque. The glass gate asserts its ink against the panel
|
|
29
|
+
* composited over the PAGE GROUND (--color-surface-2), which is what sits behind a card or a modal.
|
|
30
|
+
* Behind this one is the scrim, over arbitrary content — the very case that has no computable
|
|
31
|
+
* ratio. A frosted busy panel would be the one surface in the kit whose caption nothing could
|
|
32
|
+
* verify, while it is up precisely because the app is doing something the reader must not
|
|
33
|
+
* interrupt. Left opaque on purpose; do not "fix" it for consistency. */
|
|
25
34
|
.fdy-busy__panel{display:flex;flex-direction:column;align-items:center;gap:var(--space-4);padding:var(--space-6) var(--space-8);border-radius:var(--radius-lg);background:var(--color-surface);box-shadow:var(--shadow-lift);max-width:min(20rem,calc(100vw - var(--space-8)));}
|
|
26
35
|
.fdy-busy__mark{display:flex;align-items:center;justify-content:center;min-height:2.5rem;}
|
|
27
36
|
.fdy-busy__caption{margin:0;font-size:var(--text-sm);font-weight:var(--weight-medium);color:var(--color-text);text-align:center;}
|
|
@@ -60,9 +60,22 @@
|
|
|
60
60
|
grid track, `container-type:inline-size` on a standalone .fdy-stat would stop it sizing to its
|
|
61
61
|
own content. The unconditional rule above stays as the fallback wherever @container is missing. */
|
|
62
62
|
@supports (container-type:inline-size){
|
|
63
|
-
.fdy-stats>.fdy-stat{container-type:inline-size;}
|
|
64
|
-
.fdy-stats>.fdy-stat .fdy-stat__value{font-size:clamp(var(--text-xl),11cqw,var(--text-3xl));}
|
|
63
|
+
.fdy-stats:not(.fdy-stats--inline)>.fdy-stat{container-type:inline-size;}
|
|
64
|
+
.fdy-stats:not(.fdy-stats--inline)>.fdy-stat .fdy-stat__value{font-size:clamp(var(--text-xl),11cqw,var(--text-3xl));}
|
|
65
65
|
}
|
|
66
|
+
/* The price of that container, and the reason --inline opts out of it (#050). `container-type`
|
|
67
|
+
applies inline-size CONTAINMENT: the tile's min-content and max-content contributions are both
|
|
68
|
+
ZERO. So the 11rem floor above is not a taste choice, it is the only thing giving these tracks a
|
|
69
|
+
size, and re-tracking the grid on content (`auto`, `max-content`, `minmax(0,…)`) resolves every
|
|
70
|
+
track to 0. `justify-items` is the sharper edge: anything but the default `stretch` sizes the
|
|
71
|
+
tile to that zero contribution even when the track is correctly wide, and three labels paint on
|
|
72
|
+
top of each other. Measured from IDU_EMATE_ACCT_WEB's page header, where a hugging strip came out
|
|
73
|
+
40px wide, all of it gap.
|
|
74
|
+
--inline is the shape that header wanted: a strip that hugs its numbers and sits beside a page
|
|
75
|
+
title, instead of a full-width band whose 11rem floor collapses to one column at 390px. It cannot
|
|
76
|
+
have both, so it drops the container and keeps the flat --text-3xl the base rule already sets;
|
|
77
|
+
a track sized to its own content is never the narrow track the clamp exists for. */
|
|
78
|
+
.fdy-stats--inline{grid-template-columns:none;grid-auto-flow:column;grid-auto-columns:minmax(0,max-content);}
|
|
66
79
|
.fdy-stats--boxed{background:var(--color-surface);border:var(--bw) solid var(--color-border);border-radius:var(--radius-lg);box-shadow:var(--shadow-1);gap:0;}
|
|
67
80
|
.fdy-stats--boxed .fdy-stat{padding:var(--space-5);border-right:var(--bw) solid var(--color-border-muted);}
|
|
68
81
|
.fdy-stats--boxed .fdy-stat:last-child{border-right:0;}
|
|
@@ -13,8 +13,9 @@
|
|
|
13
13
|
/* Fields are direct children. Drop the standalone field's 22rem cap; default to the
|
|
14
14
|
* medium column width with no unbounded growth (that's what caused the raggedness). */
|
|
15
15
|
.fdy-filterbar>.fdy-field{max-width:none;flex:0 0 auto;width:12rem;}
|
|
16
|
-
/* Controls fill their field's column
|
|
17
|
-
|
|
16
|
+
/* Controls fill their field's column: released in input.css for every field, not just this one.
|
|
17
|
+
The rule used to live here, naming the input group and the combo only, which is why an
|
|
18
|
+
.fdy-autocomplete or an .fdy-cascade in a --w-2xl field still stopped 48px short of it (#051). */
|
|
18
19
|
/* Column-width rhythm, pick one per field so bars across the app line up. */
|
|
19
20
|
.fdy-filterbar>.fdy-field--w-sm{width:9rem;}
|
|
20
21
|
.fdy-filterbar>.fdy-field--w-lg{width:15rem;}
|
package/src/components/input.css
CHANGED
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
/* Freeday. Field & Input */
|
|
2
2
|
.fdy-field{display:flex;flex-direction:column;gap:var(--space-2);max-width:22rem;}
|
|
3
|
+
/* Inside a labelled field, a control fills the field (#051). The 22rem cap those controls carry is
|
|
4
|
+
for one standing on its own, with no field to take a width from; #017 already released the date
|
|
5
|
+
and time pickers here for exactly this reason, and its comment claims a picker then fills its
|
|
6
|
+
field "like every other control". That was not true of these four: a `--full` row in a
|
|
7
|
+
.fdy-form-grid held a 352px combo under a 600px label, and a 26rem toolbar search field hid 64px
|
|
8
|
+
of dead space INSIDE itself, so an author who wrote `gap:var(--space-3)` measured 76px on screen.
|
|
9
|
+
The field's own max-width above is what governs, and it still caps a field nobody has widened, so
|
|
10
|
+
this changes nothing wherever the cap was already doing its job. */
|
|
11
|
+
.fdy-field>.fdy-input-group,.fdy-field>.fdy-combo,.fdy-field>.fdy-autocomplete,.fdy-field>.fdy-cascade{max-width:none;}
|
|
3
12
|
/* A grouped field is legitimately a <fieldset> (it needs a <legend>), e.g. a radio/checkbox group.
|
|
4
13
|
Neutralise the UA groove border / padding / min-inline-size so it lays out identically to the
|
|
5
14
|
<div> form (min-inline-size:min-content would otherwise block the filterbar column widths). */
|