@cahyo-dimas/freeday 3.14.0 → 3.14.1
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 +41 -0
- package/README.id.md +1 -1
- package/README.md +1 -1
- package/dist/freeday.bundle.css +15 -4
- package/dist/freeday.css +15 -4
- package/docs/getting-started.md +1 -1
- package/package.json +2 -2
- package/src/components/app-shell.css +2 -1
- package/src/components/drawer.css +2 -1
- package/src/components/modal.css +11 -2
package/CHANGELOG.md
CHANGED
|
@@ -9,6 +9,47 @@ 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.14.1] - 2026-10-30
|
|
13
|
+
|
|
14
|
+
**Badan `FdyModal` kembali setinggi isinya di iPhone.** Di iPhone 7 sungguhan (iOS 15), setiap modal
|
|
15
|
+
menampilkan kepala dan kaki dengan badan tinggal selarik, tergulir sampai dasar, dan formulirnya
|
|
16
|
+
tak terlihat. "Tambah security" dan "Tulis info" di app ronda tak dapat dipakai sama sekali dari HP
|
|
17
|
+
(`CATATAN-FREEDAY.md` §16).
|
|
18
|
+
|
|
19
|
+
### Fixed
|
|
20
|
+
- **`.fdy-modal__body` memakai `flex:1 1 auto`, bukan `flex:1`** (`#104`). Basis shorthand itu 0%,
|
|
21
|
+
dan `.fdy-modal` hanya punya `max-height`, sehingga persentasenya diresolusikan terhadap tinggi
|
|
22
|
+
yang tak tentu. Mesin terkini membacanya sebagai `content`, sedangkan WebKit lama membacanya
|
|
23
|
+
sebagai 0: dialog setinggi kepala ditambah kaki, dan badan tinggal padding 40px dengan
|
|
24
|
+
formulirnya meluap di dalamnya. Basis `0px` mereproduksinya di Chrome sampai ke pikselnya (badan
|
|
25
|
+
39,7px untuk isi 358px), dan `auto` menghasilkan tata letak yang identik dengan sebelumnya di mesin
|
|
26
|
+
terkini (dialog 498,7px, badan 355,7px, di kedua bacaan). Mekanismenya terukur. Bahwa Safari 15
|
|
27
|
+
memang membaca 0% sebagai 0 disimpulkan dari gejalanya dan belum diukur di perangkat, sebab tak
|
|
28
|
+
ada WebKit setua itu yang dapat dijalankan di sini.
|
|
29
|
+
- **`100vh` diikuti `100dvh`** di `max-height` modal, tinggi drawer, dan tinggi sidebar sticky
|
|
30
|
+
(`#104`). Di Safari iOS `100vh` adalah viewport besar, seolah bilah alat tak ada, jadi kotak yang
|
|
31
|
+
diukur dengannya berjalan ke bawah bilah itu. Sidebar overlay sudah memakai `100dvh` sejak lama;
|
|
32
|
+
tiga tempat ini tertinggal. Mesin tanpa `dvh` memakai nilai pertama.
|
|
33
|
+
|
|
34
|
+
### Catatan
|
|
35
|
+
- Dugaan di catatan app, bahwa `100vh` penyebab utamanya, tidak cocok dengan gejalanya: `100vh` yang
|
|
36
|
+
kebesaran membuat dialog terlalu tinggi, bukan badannya terlalu pendek. Tetap diperbaiki karena
|
|
37
|
+
ia cacat tersendiri.
|
|
38
|
+
- Drawer dan nav sidebar memakai pola `flex:1` yang sama tetapi tidak terkena, sebab kontainernya
|
|
39
|
+
punya tinggi pasti.
|
|
40
|
+
|
|
41
|
+
### Gerbang
|
|
42
|
+
- `css.test.mjs`: item flex yang menjadi wilayah gulir (`min-height:0` + `overflow`) tak boleh
|
|
43
|
+
memakai basis nol atau persen, kecuali kontainernya bertinggi pasti dan tercatat. Setiap `100vh`
|
|
44
|
+
yang mengukur kotak wajib diikuti `100dvh`, kecuali tinggi minimum halaman.
|
|
45
|
+
- `browser/modal-phone.mjs` di 375×667: badan modal pendek setinggi isinya, modal panjang berhenti
|
|
46
|
+
di `max-height` dengan kaki tetap di layar, dan basis terkomputasi `auto`. Dengan basis `0px`
|
|
47
|
+
uji ini merah dengan "40px shown of 358px", angka yang sama dengan di iPhone.
|
|
48
|
+
- `webkit/modal-phone.spec.mjs`: tata letak yang sama di WebKit dengan deskriptor iPhone 7 di CI. WebKit
|
|
49
|
+
Playwright adalah mesin terkini yang membaca 0% dengan benar, jadi berkas ini menjaga hasilnya,
|
|
50
|
+
bukan penyebabnya; penyebabnya dijaga dua gerbang di atas.
|
|
51
|
+
- Empat mutasi diverifikasi merah.
|
|
52
|
+
|
|
12
53
|
## [3.14.0] - 2026-10-29
|
|
13
54
|
|
|
14
55
|
**Daftar terurut lewat seret dan papan ketik, dan satu atribut untuk berkata "ini bukan urusan
|
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.14.1)
|
|
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.14.1)
|
|
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`.
|
package/dist/freeday.bundle.css
CHANGED
|
@@ -1285,7 +1285,8 @@ a { color: var(--color-primary-strong); }
|
|
|
1285
1285
|
* > (.fdy-app__topbar, .fdy-app__main)). The __content wrapper gives the sticky
|
|
1286
1286
|
* topbar a tall containing block so it can travel, a bare grid cell can't. */
|
|
1287
1287
|
.fdy-app{display:flex;align-items:stretch;min-height:100vh;background:var(--color-surface-2);}
|
|
1288
|
-
|
|
1288
|
+
/* 100vh then 100dvh: on iOS Safari 100vh is the LARGE viewport, as if the toolbar were gone, so a box sized by it runs under the toolbar. An engine without dvh keeps the first value. */
|
|
1289
|
+
.fdy-app__sidebar{position:sticky;top:0;align-self:flex-start;height:100vh;height:100dvh;overflow:hidden;flex:none;width:var(--fdy-app-sidebar-w,15.5rem);box-sizing:border-box;background:var(--color-surface-raised);backdrop-filter:var(--surface-filter);-webkit-backdrop-filter:var(--surface-filter);border-right:var(--bw) solid var(--color-border);display:flex;flex-direction:column;transition:width var(--dur-slow) var(--ease-standard),border-right-width var(--dur-slow) var(--ease-standard);}
|
|
1289
1290
|
/* `min-height:0` is the height-axis twin of `min-width:0`, and its absence was invisible for as long
|
|
1290
1291
|
* as the shell scrolled the PAGE (#055 §2). A consumer that pins the shell to the viewport and
|
|
1291
1292
|
* scrolls .fdy-app__main instead hits it immediately: a column flex item's automatic minimum size is
|
|
@@ -2472,7 +2473,8 @@ a { color: var(--color-primary-strong); }
|
|
|
2472
2473
|
/* display is gated behind [open] so the native <dialog> stays hidden until opened.
|
|
2473
2474
|
* An unconditional display here would beat the UA `dialog:not([open]){display:none}`
|
|
2474
2475
|
* rule (author origin wins over user-agent) and leave the drawer visible on load. */
|
|
2475
|
-
|
|
2476
|
+
/* 100vh then 100dvh: on iOS Safari 100vh is the LARGE viewport, as if the toolbar were gone, so a box sized by it runs under the toolbar. An engine without dvh keeps the first value. */
|
|
2477
|
+
.fdy-drawer{position:fixed;inset:0 auto 0 0;margin:0;padding:0;height:100vh;height:100dvh;max-height:none;width:min(20rem,82vw);flex-direction:column;border:0;background:var(--color-surface-raised);backdrop-filter:var(--surface-filter);-webkit-backdrop-filter:var(--surface-filter);color:var(--color-text);box-shadow:var(--shadow-4),var(--surface-inset);overflow:hidden;transform:translateX(-100%);transition-property:transform,overlay,display;transition-duration:var(--dur-slow);transition-timing-function:var(--ease-standard),ease,ease;transition-behavior:normal,allow-discrete,allow-discrete;}
|
|
2476
2478
|
.fdy-drawer[open]{display:flex;transform:none;}
|
|
2477
2479
|
.fdy-drawer--right{inset:0 0 0 auto;transform:translateX(100%);}
|
|
2478
2480
|
.fdy-drawer::backdrop{background:rgba(10,12,25,.5);-webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px);opacity:0;transition-property:opacity,overlay,display;transition-duration:var(--dur-slow);transition-timing-function:var(--ease-standard),ease,ease;transition-behavior:normal,allow-discrete,allow-discrete;}
|
|
@@ -2779,7 +2781,8 @@ fieldset.fdy-field>legend{padding:0;float:none;margin-bottom:var(--space-2);}
|
|
|
2779
2781
|
.fdy-btn-split__toggle svg{display:block;width:1rem;height:1rem;}
|
|
2780
2782
|
|
|
2781
2783
|
/* Freeday. Modal (native <dialog>) */
|
|
2782
|
-
|
|
2784
|
+
/* 100vh then 100dvh: on iOS Safari 100vh is the LARGE viewport, as if the toolbar were gone, so a box sized by it runs under the toolbar. An engine without dvh keeps the first value. */
|
|
2785
|
+
.fdy-modal{width:min(32rem,calc(100vw - var(--space-8)));max-height:calc(100vh - var(--space-16));max-height:calc(100dvh - var(--space-16));padding:0;border:var(--bw) solid var(--color-border);border-radius:var(--radius-xl);background:var(--color-surface-raised);backdrop-filter:var(--surface-filter);-webkit-backdrop-filter:var(--surface-filter);color:var(--color-text);box-shadow:var(--shadow-lift-hover),var(--surface-inset);overflow:hidden;flex-direction:column;opacity:0;transform:translateY(8px) scale(.98);/* Longhands, not the `transition` shorthand. A shorthand carrying one keyword the engine does not know is INVALID AT PARSE, so the whole declaration is thrown away -- and `allow-discrete` is unknown below Safari 17.4, which is under this kit's floor. The result was a modal and a drawer that opened and closed with no animation at all on an iPhone 7. Split this way only `transition-behavior` is dropped there, and the opacity/transform half survives. The lists align BY INDEX and reproduce the shorthand exactly, including `ease` for the discrete pair and `normal` for the continuous one -- verified by comparing computed styles before and after (#097). */transition-property:opacity,transform,overlay,display;transition-duration:var(--dur-base);transition-timing-function:var(--ease-spring),var(--ease-spring),ease,ease;transition-behavior:normal,normal,allow-discrete,allow-discrete;}
|
|
2783
2786
|
.fdy-modal--sm{width:min(24rem,calc(100vw - var(--space-8)));}
|
|
2784
2787
|
.fdy-modal--md{width:min(32rem,calc(100vw - var(--space-8)));}
|
|
2785
2788
|
.fdy-modal--lg{width:min(48rem,calc(100vw - var(--space-8)));}
|
|
@@ -2789,7 +2792,15 @@ fieldset.fdy-field>legend{padding:0;float:none;margin-bottom:var(--space-2);}
|
|
|
2789
2792
|
.fdy-modal__title{font-family:var(--font-display);font-size:var(--text-lg);font-weight:var(--weight-semibold);color:var(--color-text);margin:0 auto 0 0;}
|
|
2790
2793
|
.fdy-modal__close{border:0;background:transparent;color:var(--color-text-muted);font-size:var(--text-xl);line-height:1;cursor:pointer;padding:var(--space-1);border-radius:var(--radius-sm);}
|
|
2791
2794
|
.fdy-modal__close:hover{background:var(--color-surface-2);color:var(--color-text);}
|
|
2792
|
-
|
|
2795
|
+
/* `1 1 auto`, NOT `flex:1`. The shorthand's basis is 0%, and `.fdy-modal` has only a max-height, so
|
|
2796
|
+
* the percentage resolves against an indefinite height. Current engines read that as `content`;
|
|
2797
|
+
* older WebKit read it as 0, sized the dialog to header + footer, and left the body its 40px of
|
|
2798
|
+
* padding, with the form overflowing inside it. That was every modal on an iPhone 7 (iOS 15),
|
|
2799
|
+
* reported from a real device (CATATAN-FREEDAY §16). A 0px basis reproduces it in Chrome to the
|
|
2800
|
+
* pixel. `auto` lays out identically in current engines (measured: 498.7px dialog, 355.7px body,
|
|
2801
|
+
* both readings) and leaves no indefinite percentage for any engine to read. min-height:0 is
|
|
2802
|
+
* still what lets a long body shrink and scroll once the dialog reaches its max-height. */
|
|
2803
|
+
.fdy-modal__body{flex:1 1 auto;min-height:0;padding:var(--space-5);overflow:auto;}
|
|
2793
2804
|
.fdy-modal__footer{flex:none;display:flex;gap:var(--space-2);justify-content:flex-end;padding:var(--space-4) var(--space-5);border-top:var(--bw) solid var(--color-border-muted);background:var(--color-surface-2);}
|
|
2794
2805
|
/* Symmetric enter AND exit (fade + rise + subtle scale) on the native <dialog>. @starting-style
|
|
2795
2806
|
* animates the entry; overlay/display allow-discrete keep it painted through the exit so it
|
package/dist/freeday.css
CHANGED
|
@@ -108,7 +108,8 @@ a { color: var(--color-primary-strong); }
|
|
|
108
108
|
* > (.fdy-app__topbar, .fdy-app__main)). The __content wrapper gives the sticky
|
|
109
109
|
* topbar a tall containing block so it can travel, a bare grid cell can't. */
|
|
110
110
|
.fdy-app{display:flex;align-items:stretch;min-height:100vh;background:var(--color-surface-2);}
|
|
111
|
-
|
|
111
|
+
/* 100vh then 100dvh: on iOS Safari 100vh is the LARGE viewport, as if the toolbar were gone, so a box sized by it runs under the toolbar. An engine without dvh keeps the first value. */
|
|
112
|
+
.fdy-app__sidebar{position:sticky;top:0;align-self:flex-start;height:100vh;height:100dvh;overflow:hidden;flex:none;width:var(--fdy-app-sidebar-w,15.5rem);box-sizing:border-box;background:var(--color-surface-raised);backdrop-filter:var(--surface-filter);-webkit-backdrop-filter:var(--surface-filter);border-right:var(--bw) solid var(--color-border);display:flex;flex-direction:column;transition:width var(--dur-slow) var(--ease-standard),border-right-width var(--dur-slow) var(--ease-standard);}
|
|
112
113
|
/* `min-height:0` is the height-axis twin of `min-width:0`, and its absence was invisible for as long
|
|
113
114
|
* as the shell scrolled the PAGE (#055 §2). A consumer that pins the shell to the viewport and
|
|
114
115
|
* scrolls .fdy-app__main instead hits it immediately: a column flex item's automatic minimum size is
|
|
@@ -1295,7 +1296,8 @@ a { color: var(--color-primary-strong); }
|
|
|
1295
1296
|
/* display is gated behind [open] so the native <dialog> stays hidden until opened.
|
|
1296
1297
|
* An unconditional display here would beat the UA `dialog:not([open]){display:none}`
|
|
1297
1298
|
* rule (author origin wins over user-agent) and leave the drawer visible on load. */
|
|
1298
|
-
|
|
1299
|
+
/* 100vh then 100dvh: on iOS Safari 100vh is the LARGE viewport, as if the toolbar were gone, so a box sized by it runs under the toolbar. An engine without dvh keeps the first value. */
|
|
1300
|
+
.fdy-drawer{position:fixed;inset:0 auto 0 0;margin:0;padding:0;height:100vh;height:100dvh;max-height:none;width:min(20rem,82vw);flex-direction:column;border:0;background:var(--color-surface-raised);backdrop-filter:var(--surface-filter);-webkit-backdrop-filter:var(--surface-filter);color:var(--color-text);box-shadow:var(--shadow-4),var(--surface-inset);overflow:hidden;transform:translateX(-100%);transition-property:transform,overlay,display;transition-duration:var(--dur-slow);transition-timing-function:var(--ease-standard),ease,ease;transition-behavior:normal,allow-discrete,allow-discrete;}
|
|
1299
1301
|
.fdy-drawer[open]{display:flex;transform:none;}
|
|
1300
1302
|
.fdy-drawer--right{inset:0 0 0 auto;transform:translateX(100%);}
|
|
1301
1303
|
.fdy-drawer::backdrop{background:rgba(10,12,25,.5);-webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px);opacity:0;transition-property:opacity,overlay,display;transition-duration:var(--dur-slow);transition-timing-function:var(--ease-standard),ease,ease;transition-behavior:normal,allow-discrete,allow-discrete;}
|
|
@@ -1602,7 +1604,8 @@ fieldset.fdy-field>legend{padding:0;float:none;margin-bottom:var(--space-2);}
|
|
|
1602
1604
|
.fdy-btn-split__toggle svg{display:block;width:1rem;height:1rem;}
|
|
1603
1605
|
|
|
1604
1606
|
/* Freeday. Modal (native <dialog>) */
|
|
1605
|
-
|
|
1607
|
+
/* 100vh then 100dvh: on iOS Safari 100vh is the LARGE viewport, as if the toolbar were gone, so a box sized by it runs under the toolbar. An engine without dvh keeps the first value. */
|
|
1608
|
+
.fdy-modal{width:min(32rem,calc(100vw - var(--space-8)));max-height:calc(100vh - var(--space-16));max-height:calc(100dvh - var(--space-16));padding:0;border:var(--bw) solid var(--color-border);border-radius:var(--radius-xl);background:var(--color-surface-raised);backdrop-filter:var(--surface-filter);-webkit-backdrop-filter:var(--surface-filter);color:var(--color-text);box-shadow:var(--shadow-lift-hover),var(--surface-inset);overflow:hidden;flex-direction:column;opacity:0;transform:translateY(8px) scale(.98);/* Longhands, not the `transition` shorthand. A shorthand carrying one keyword the engine does not know is INVALID AT PARSE, so the whole declaration is thrown away -- and `allow-discrete` is unknown below Safari 17.4, which is under this kit's floor. The result was a modal and a drawer that opened and closed with no animation at all on an iPhone 7. Split this way only `transition-behavior` is dropped there, and the opacity/transform half survives. The lists align BY INDEX and reproduce the shorthand exactly, including `ease` for the discrete pair and `normal` for the continuous one -- verified by comparing computed styles before and after (#097). */transition-property:opacity,transform,overlay,display;transition-duration:var(--dur-base);transition-timing-function:var(--ease-spring),var(--ease-spring),ease,ease;transition-behavior:normal,normal,allow-discrete,allow-discrete;}
|
|
1606
1609
|
.fdy-modal--sm{width:min(24rem,calc(100vw - var(--space-8)));}
|
|
1607
1610
|
.fdy-modal--md{width:min(32rem,calc(100vw - var(--space-8)));}
|
|
1608
1611
|
.fdy-modal--lg{width:min(48rem,calc(100vw - var(--space-8)));}
|
|
@@ -1612,7 +1615,15 @@ fieldset.fdy-field>legend{padding:0;float:none;margin-bottom:var(--space-2);}
|
|
|
1612
1615
|
.fdy-modal__title{font-family:var(--font-display);font-size:var(--text-lg);font-weight:var(--weight-semibold);color:var(--color-text);margin:0 auto 0 0;}
|
|
1613
1616
|
.fdy-modal__close{border:0;background:transparent;color:var(--color-text-muted);font-size:var(--text-xl);line-height:1;cursor:pointer;padding:var(--space-1);border-radius:var(--radius-sm);}
|
|
1614
1617
|
.fdy-modal__close:hover{background:var(--color-surface-2);color:var(--color-text);}
|
|
1615
|
-
|
|
1618
|
+
/* `1 1 auto`, NOT `flex:1`. The shorthand's basis is 0%, and `.fdy-modal` has only a max-height, so
|
|
1619
|
+
* the percentage resolves against an indefinite height. Current engines read that as `content`;
|
|
1620
|
+
* older WebKit read it as 0, sized the dialog to header + footer, and left the body its 40px of
|
|
1621
|
+
* padding, with the form overflowing inside it. That was every modal on an iPhone 7 (iOS 15),
|
|
1622
|
+
* reported from a real device (CATATAN-FREEDAY §16). A 0px basis reproduces it in Chrome to the
|
|
1623
|
+
* pixel. `auto` lays out identically in current engines (measured: 498.7px dialog, 355.7px body,
|
|
1624
|
+
* both readings) and leaves no indefinite percentage for any engine to read. min-height:0 is
|
|
1625
|
+
* still what lets a long body shrink and scroll once the dialog reaches its max-height. */
|
|
1626
|
+
.fdy-modal__body{flex:1 1 auto;min-height:0;padding:var(--space-5);overflow:auto;}
|
|
1616
1627
|
.fdy-modal__footer{flex:none;display:flex;gap:var(--space-2);justify-content:flex-end;padding:var(--space-4) var(--space-5);border-top:var(--bw) solid var(--color-border-muted);background:var(--color-surface-2);}
|
|
1617
1628
|
/* Symmetric enter AND exit (fade + rise + subtle scale) on the native <dialog>. @starting-style
|
|
1618
1629
|
* animates the entry; overlay/display allow-discrete keep it painted through the exit so it
|
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.14.
|
|
201
|
+
Lands in `package.json` as `"@cahyo-dimas/freeday": "^3.14.1"` (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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cahyo-dimas/freeday",
|
|
3
|
-
"version": "3.14.
|
|
3
|
+
"version": "3.14.1",
|
|
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 browser/app-owned.mjs browser/sortable.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 browser/sortable.mjs browser/modal-phone.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",
|
|
@@ -6,7 +6,8 @@
|
|
|
6
6
|
* > (.fdy-app__topbar, .fdy-app__main)). The __content wrapper gives the sticky
|
|
7
7
|
* topbar a tall containing block so it can travel, a bare grid cell can't. */
|
|
8
8
|
.fdy-app{display:flex;align-items:stretch;min-height:100vh;background:var(--color-surface-2);}
|
|
9
|
-
|
|
9
|
+
/* 100vh then 100dvh: on iOS Safari 100vh is the LARGE viewport, as if the toolbar were gone, so a box sized by it runs under the toolbar. An engine without dvh keeps the first value. */
|
|
10
|
+
.fdy-app__sidebar{position:sticky;top:0;align-self:flex-start;height:100vh;height:100dvh;overflow:hidden;flex:none;width:var(--fdy-app-sidebar-w,15.5rem);box-sizing:border-box;background:var(--color-surface-raised);backdrop-filter:var(--surface-filter);-webkit-backdrop-filter:var(--surface-filter);border-right:var(--bw) solid var(--color-border);display:flex;flex-direction:column;transition:width var(--dur-slow) var(--ease-standard),border-right-width var(--dur-slow) var(--ease-standard);}
|
|
10
11
|
/* `min-height:0` is the height-axis twin of `min-width:0`, and its absence was invisible for as long
|
|
11
12
|
* as the shell scrolled the PAGE (#055 §2). A consumer that pins the shell to the viewport and
|
|
12
13
|
* scrolls .fdy-app__main instead hits it immediately: a column flex item's automatic minimum size is
|
|
@@ -4,7 +4,8 @@
|
|
|
4
4
|
/* display is gated behind [open] so the native <dialog> stays hidden until opened.
|
|
5
5
|
* An unconditional display here would beat the UA `dialog:not([open]){display:none}`
|
|
6
6
|
* rule (author origin wins over user-agent) and leave the drawer visible on load. */
|
|
7
|
-
|
|
7
|
+
/* 100vh then 100dvh: on iOS Safari 100vh is the LARGE viewport, as if the toolbar were gone, so a box sized by it runs under the toolbar. An engine without dvh keeps the first value. */
|
|
8
|
+
.fdy-drawer{position:fixed;inset:0 auto 0 0;margin:0;padding:0;height:100vh;height:100dvh;max-height:none;width:min(20rem,82vw);flex-direction:column;border:0;background:var(--color-surface-raised);backdrop-filter:var(--surface-filter);-webkit-backdrop-filter:var(--surface-filter);color:var(--color-text);box-shadow:var(--shadow-4),var(--surface-inset);overflow:hidden;transform:translateX(-100%);transition-property:transform,overlay,display;transition-duration:var(--dur-slow);transition-timing-function:var(--ease-standard),ease,ease;transition-behavior:normal,allow-discrete,allow-discrete;}
|
|
8
9
|
.fdy-drawer[open]{display:flex;transform:none;}
|
|
9
10
|
.fdy-drawer--right{inset:0 0 0 auto;transform:translateX(100%);}
|
|
10
11
|
.fdy-drawer::backdrop{background:rgba(10,12,25,.5);-webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px);opacity:0;transition-property:opacity,overlay,display;transition-duration:var(--dur-slow);transition-timing-function:var(--ease-standard),ease,ease;transition-behavior:normal,allow-discrete,allow-discrete;}
|
package/src/components/modal.css
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
/* Freeday. Modal (native <dialog>) */
|
|
2
|
-
|
|
2
|
+
/* 100vh then 100dvh: on iOS Safari 100vh is the LARGE viewport, as if the toolbar were gone, so a box sized by it runs under the toolbar. An engine without dvh keeps the first value. */
|
|
3
|
+
.fdy-modal{width:min(32rem,calc(100vw - var(--space-8)));max-height:calc(100vh - var(--space-16));max-height:calc(100dvh - var(--space-16));padding:0;border:var(--bw) solid var(--color-border);border-radius:var(--radius-xl);background:var(--color-surface-raised);backdrop-filter:var(--surface-filter);-webkit-backdrop-filter:var(--surface-filter);color:var(--color-text);box-shadow:var(--shadow-lift-hover),var(--surface-inset);overflow:hidden;flex-direction:column;opacity:0;transform:translateY(8px) scale(.98);/* Longhands, not the `transition` shorthand. A shorthand carrying one keyword the engine does not know is INVALID AT PARSE, so the whole declaration is thrown away -- and `allow-discrete` is unknown below Safari 17.4, which is under this kit's floor. The result was a modal and a drawer that opened and closed with no animation at all on an iPhone 7. Split this way only `transition-behavior` is dropped there, and the opacity/transform half survives. The lists align BY INDEX and reproduce the shorthand exactly, including `ease` for the discrete pair and `normal` for the continuous one -- verified by comparing computed styles before and after (#097). */transition-property:opacity,transform,overlay,display;transition-duration:var(--dur-base);transition-timing-function:var(--ease-spring),var(--ease-spring),ease,ease;transition-behavior:normal,normal,allow-discrete,allow-discrete;}
|
|
3
4
|
.fdy-modal--sm{width:min(24rem,calc(100vw - var(--space-8)));}
|
|
4
5
|
.fdy-modal--md{width:min(32rem,calc(100vw - var(--space-8)));}
|
|
5
6
|
.fdy-modal--lg{width:min(48rem,calc(100vw - var(--space-8)));}
|
|
@@ -9,7 +10,15 @@
|
|
|
9
10
|
.fdy-modal__title{font-family:var(--font-display);font-size:var(--text-lg);font-weight:var(--weight-semibold);color:var(--color-text);margin:0 auto 0 0;}
|
|
10
11
|
.fdy-modal__close{border:0;background:transparent;color:var(--color-text-muted);font-size:var(--text-xl);line-height:1;cursor:pointer;padding:var(--space-1);border-radius:var(--radius-sm);}
|
|
11
12
|
.fdy-modal__close:hover{background:var(--color-surface-2);color:var(--color-text);}
|
|
12
|
-
|
|
13
|
+
/* `1 1 auto`, NOT `flex:1`. The shorthand's basis is 0%, and `.fdy-modal` has only a max-height, so
|
|
14
|
+
* the percentage resolves against an indefinite height. Current engines read that as `content`;
|
|
15
|
+
* older WebKit read it as 0, sized the dialog to header + footer, and left the body its 40px of
|
|
16
|
+
* padding, with the form overflowing inside it. That was every modal on an iPhone 7 (iOS 15),
|
|
17
|
+
* reported from a real device (CATATAN-FREEDAY §16). A 0px basis reproduces it in Chrome to the
|
|
18
|
+
* pixel. `auto` lays out identically in current engines (measured: 498.7px dialog, 355.7px body,
|
|
19
|
+
* both readings) and leaves no indefinite percentage for any engine to read. min-height:0 is
|
|
20
|
+
* still what lets a long body shrink and scroll once the dialog reaches its max-height. */
|
|
21
|
+
.fdy-modal__body{flex:1 1 auto;min-height:0;padding:var(--space-5);overflow:auto;}
|
|
13
22
|
.fdy-modal__footer{flex:none;display:flex;gap:var(--space-2);justify-content:flex-end;padding:var(--space-4) var(--space-5);border-top:var(--bw) solid var(--color-border-muted);background:var(--color-surface-2);}
|
|
14
23
|
/* Symmetric enter AND exit (fade + rise + subtle scale) on the native <dialog>. @starting-style
|
|
15
24
|
* animates the entry; overlay/display allow-discrete keep it painted through the exit so it
|