@cahyo-dimas/freeday 1.36.0 → 1.37.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 +21 -0
- package/COMPONENTS.md +30 -10
- package/dist/freeday.bundle.css +39 -9
- package/dist/freeday.css +39 -9
- package/package.json +1 -1
- package/src/components/filterbar.css +8 -0
- package/src/components/table.css +31 -9
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,27 @@
|
|
|
3
3
|
Semua perubahan penting dicatat di sini. Format longgar mengikuti
|
|
4
4
|
[Keep a Changelog](https://keepachangelog.com/); tiap versi = git tag.
|
|
5
5
|
|
|
6
|
+
## [1.37.0] — 2026-08-19
|
|
7
|
+
One note from the back-office app (IDU_EMATE_APPL_WEB, #014).
|
|
8
|
+
### Added
|
|
9
|
+
- **`.fdy-table__freeze` + `--fdy-freeze-left`** — freeze **any number** of columns, not just the
|
|
10
|
+
first. 1.35.0 froze `tbody th` at a hard-coded `left:0`, which suits a rate matrix's single row
|
|
11
|
+
header and cannot express a wide table with two identity columns: they all landed on 0 and
|
|
12
|
+
stacked. Mark every cell of a frozen column and give that column its offset; the offsets belong
|
|
13
|
+
to the caller because they are sums of *rendered* widths, which CSS cannot compute.
|
|
14
|
+
`.fdy-table__freeze--edge` marks where the frozen block ends.
|
|
15
|
+
- **A bare control in a `.fdy-filterbar` gets `--control-h`.** The bar aligns `flex-end` so
|
|
16
|
+
labelled fields line up on their inputs; a `.fdy-check` / `.fdy-switch` / `.fdy-radio` / lone
|
|
17
|
+
`.fdy-btn` has no label row, so flex-end left it sitting below the input's centre line. Now its
|
|
18
|
+
box ends where an input's box ends and the control centres on that line.
|
|
19
|
+
### Changed
|
|
20
|
+
- **BREAKING (from 1.35.0): the header freeze moved to `.fdy-table--sticky-head`.** Freezing a row
|
|
21
|
+
needs a vertical scrollport; a table that only freezes columns scrolls with the **page**, where
|
|
22
|
+
`top:0` sticks the header under the viewport edge — over the consuming app's own top bar.
|
|
23
|
+
`.fdy-table--sticky` is now the enabler (separate borders) and each axis is asked for
|
|
24
|
+
explicitly. `tbody th` no longer freezes implicitly; use `.fdy-table__freeze`. 1.35.0 and 1.36.0
|
|
25
|
+
are unpublished, so no released version carried the old contract.
|
|
26
|
+
|
|
6
27
|
## [1.36.0] — 2026-08-19
|
|
7
28
|
One note from the back-office app (IDU_EMATE_APPL_WEB, #013).
|
|
8
29
|
### Added
|
package/COMPONENTS.md
CHANGED
|
@@ -639,7 +639,11 @@ Responsive two-column document header. Children are `.fdy-field`; `.fdy-field--f
|
|
|
639
639
|
## Filter bar — `.fdy-filterbar`
|
|
640
640
|
A consistent filter row of `.fdy-field`s with a width rhythm (`--w-sm` · default · `--w-lg` ·
|
|
641
641
|
`--w-xl` · `--w-2xl`), one `--w-grow` field (usually search) absorbing the slack, and
|
|
642
|
-
`.fdy-filterbar__actions` pinned at the end.
|
|
642
|
+
`.fdy-filterbar__actions` pinned at the end. A control with **no label of its own** (a
|
|
643
|
+
`.fdy-check`, `.fdy-switch`, `.fdy-radio`, or a lone `.fdy-btn`) is given `--control-h` so it
|
|
644
|
+
centres on the input line instead of hanging below it — the bar aligns `flex-end` to line up
|
|
645
|
+
labelled fields, which would otherwise drop a 20px checkbox below a 32px input's centre.
|
|
646
|
+
`--actions-inline` keeps the actions on the control
|
|
643
647
|
line. Zero JS. Composes with `.fdy-table-toolbar` on a shared baseline.
|
|
644
648
|
|
|
645
649
|
## Slider — `.fdy-slider`
|
|
@@ -695,20 +699,36 @@ Semantic static table. Wrap in `.fdy-table-wrap` (bordered surface) or `.fdy-tab
|
|
|
695
699
|
```
|
|
696
700
|
|
|
697
701
|
**Frozen axes — `.fdy-table--sticky`.** For a grid read against two axes at once (a rate
|
|
698
|
-
matrix, a timetable)
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
702
|
+
matrix, a timetable) or a wide one whose identity columns must stay visible. `.fdy-table--sticky`
|
|
703
|
+
is the enabler: it separates the borders, because a collapsed border belongs to the table rather
|
|
704
|
+
than the cell and scrolls out from under whatever you froze. Then ask for the axes you have:
|
|
705
|
+
|
|
706
|
+
- **Header row** — add `.fdy-table--sticky-head`, and put `.fdy-table-scroll--frozen` on the
|
|
707
|
+
wrapper (it scrolls both ways and is the scrollport the freeze resolves against; size it with
|
|
708
|
+
`--fdy-table-frozen-h`, default `30rem`). It is a separate modifier because a table that only
|
|
709
|
+
freezes columns scrolls with the **page**, and `top:0` against the page sticks the header under
|
|
710
|
+
the viewport edge — over the app's own top bar.
|
|
711
|
+
- **Columns** — put `.fdy-table__freeze` on **every cell of the column, header included**, and give
|
|
712
|
+
each frozen column its own `--fdy-freeze-left`: `0` for the first, then the summed widths of the
|
|
713
|
+
frozen columns to its left. Mark the last one `.fdy-table__freeze--edge` so the reader can see
|
|
714
|
+
where the frozen block ends. One frozen column needs no variable at all.
|
|
715
|
+
|
|
716
|
+
The offsets are the caller's job because they depend on rendered column widths, which CSS cannot
|
|
717
|
+
sum — measure them once after render (and on resize) and set the variable.
|
|
704
718
|
|
|
705
719
|
```html
|
|
706
720
|
<div class="fdy-table-scroll fdy-table-scroll--frozen" style="--fdy-table-frozen-h:26rem">
|
|
707
|
-
<table class="fdy-table fdy-table--sticky">
|
|
721
|
+
<table class="fdy-table fdy-table--sticky fdy-table--sticky-head">
|
|
708
722
|
<caption class="fdy-visually-hidden">Exchange rates, August 2026</caption>
|
|
709
|
-
<thead><tr
|
|
723
|
+
<thead><tr>
|
|
724
|
+
<th scope="col" class="fdy-table__freeze fdy-table__freeze--edge">Date</th>
|
|
725
|
+
<th scope="col" class="fdy-table__num">USD</th>
|
|
726
|
+
</tr></thead>
|
|
710
727
|
<tbody>
|
|
711
|
-
<tr
|
|
728
|
+
<tr>
|
|
729
|
+
<th scope="row" class="fdy-table__freeze fdy-table__freeze--edge">1 Aug</th>
|
|
730
|
+
<td class="fdy-table__num">16,240</td>
|
|
731
|
+
</tr>
|
|
712
732
|
</tbody>
|
|
713
733
|
</table>
|
|
714
734
|
</div>
|
package/dist/freeday.bundle.css
CHANGED
|
@@ -1298,6 +1298,14 @@ a { color: var(--color-primary); }
|
|
|
1298
1298
|
* `flex:1 1 16rem` reserves 16rem for line-breaking), NOT its rendered width — so the grow basis,
|
|
1299
1299
|
* not the visible width, decides the wrap point. Margins can't keep the actions off a lonely wrapped
|
|
1300
1300
|
* row; to avoid stranded actions, tune the --w-grow basis or drop a field so the bar fits one row. */
|
|
1301
|
+
/* A control that carries NO label of its own — a checkbox, a switch, a lone
|
|
1302
|
+
button — in a bar whose `align-items:flex-end` exists to line up LABELLED
|
|
1303
|
+
fields. Flex-end puts such a control's bottom on the inputs' bottom, so a
|
|
1304
|
+
20px checkbox sits well below the 32px input's centre line and reads as
|
|
1305
|
+
dropped. Giving it the height of a control lands its box exactly where an
|
|
1306
|
+
input's box ends, and its own centring then puts it on the input's centre
|
|
1307
|
+
line. Raised from IDU_EMATE_APPL_WEB (#014). */
|
|
1308
|
+
.fdy-filterbar>.fdy-check,.fdy-filterbar>.fdy-radio,.fdy-filterbar>.fdy-switch,.fdy-filterbar>.fdy-btn{min-height:var(--control-h);}
|
|
1301
1309
|
.fdy-filterbar__actions{display:flex;align-items:center;gap:var(--space-2);margin-left:auto;}
|
|
1302
1310
|
/* Opt-in: sit the actions inline right after the last field instead of at the far edge — so when the
|
|
1303
1311
|
* bar wraps they read as attached to the filters rather than shoved to the right of a lonely row. */
|
|
@@ -1667,15 +1675,37 @@ fieldset.fdy-field>legend{padding:0;float:none;margin-bottom:var(--space-2);}
|
|
|
1667
1675
|
back on the cell that sticks. */
|
|
1668
1676
|
.fdy-table--sticky{border-collapse:separate;border-spacing:0;}
|
|
1669
1677
|
.fdy-table--sticky th,.fdy-table--sticky td{border-bottom:var(--bw) solid var(--color-border-muted);}
|
|
1670
|
-
|
|
1671
|
-
/*
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
.
|
|
1676
|
-
.fdy-table--sticky
|
|
1677
|
-
|
|
1678
|
-
|
|
1678
|
+
|
|
1679
|
+
/* Freezing the HEADER ROW is its own modifier because it needs a vertical
|
|
1680
|
+
scrollport (`.fdy-table-scroll--frozen`). A table that only freezes columns
|
|
1681
|
+
scrolls with the PAGE, and `top:0` against the page sticks the header under
|
|
1682
|
+
the viewport edge — over the app's own top bar — which is worse than not
|
|
1683
|
+
freezing it. Ask for the axis you actually have. */
|
|
1684
|
+
.fdy-table--sticky-head thead th{position:sticky;top:0;z-index:2;border-bottom:var(--bw) solid var(--color-border);}
|
|
1685
|
+
|
|
1686
|
+
/* Freezing a COLUMN: put `.fdy-table__freeze` on every cell of it, header
|
|
1687
|
+
included, and give each frozen column its own `--fdy-freeze-left` — 0 for the
|
|
1688
|
+
first, the summed widths of the frozen columns left of it after that. One
|
|
1689
|
+
frozen column needs no variable at all. Mark the last one `--edge` so the
|
|
1690
|
+
reader can see where the frozen block ends.
|
|
1691
|
+
|
|
1692
|
+
The offsets are the caller's job on purpose: they depend on rendered column
|
|
1693
|
+
widths, which CSS cannot sum, and hard-coding them here would only work for
|
|
1694
|
+
tables whose columns are all the same width. */
|
|
1695
|
+
.fdy-table--sticky .fdy-table__freeze{position:sticky;left:var(--fdy-freeze-left,0);}
|
|
1696
|
+
/* A frozen body cell slides OVER the data, so it must be OPAQUE — otherwise the
|
|
1697
|
+
cells beneath show through it. A `th` already carries the header tint from the
|
|
1698
|
+
base rule, and that tint is usually the whole point: it is what marks a column
|
|
1699
|
+
as identity rather than data. So only a `td` is given a surface here. A table
|
|
1700
|
+
that wants its frozen `th` to read as a body row instead — a rate matrix, where
|
|
1701
|
+
a hovered row should band unbroken across the freeze line — says so itself. */
|
|
1702
|
+
.fdy-table--sticky tbody .fdy-table__freeze{z-index:1;}
|
|
1703
|
+
.fdy-table--sticky tbody td.fdy-table__freeze{background:var(--color-surface);}
|
|
1704
|
+
.fdy-table--sticky tbody tr:hover td.fdy-table__freeze{background:var(--color-surface-2);}
|
|
1705
|
+
/* A frozen header cell is stuck on both axes wherever the head is frozen too, so
|
|
1706
|
+
it has to outrank both. */
|
|
1707
|
+
.fdy-table--sticky thead .fdy-table__freeze{z-index:3;}
|
|
1708
|
+
.fdy-table--sticky .fdy-table__freeze--edge{border-right:var(--bw) solid var(--color-border);}
|
|
1679
1709
|
|
|
1680
1710
|
/* The scrollport a sticky cell sticks to. Both axes scroll here, and the height is a
|
|
1681
1711
|
custom property so a page can size it without out-specifying this rule. */
|
package/dist/freeday.css
CHANGED
|
@@ -915,6 +915,14 @@ a { color: var(--color-primary); }
|
|
|
915
915
|
* `flex:1 1 16rem` reserves 16rem for line-breaking), NOT its rendered width — so the grow basis,
|
|
916
916
|
* not the visible width, decides the wrap point. Margins can't keep the actions off a lonely wrapped
|
|
917
917
|
* row; to avoid stranded actions, tune the --w-grow basis or drop a field so the bar fits one row. */
|
|
918
|
+
/* A control that carries NO label of its own — a checkbox, a switch, a lone
|
|
919
|
+
button — in a bar whose `align-items:flex-end` exists to line up LABELLED
|
|
920
|
+
fields. Flex-end puts such a control's bottom on the inputs' bottom, so a
|
|
921
|
+
20px checkbox sits well below the 32px input's centre line and reads as
|
|
922
|
+
dropped. Giving it the height of a control lands its box exactly where an
|
|
923
|
+
input's box ends, and its own centring then puts it on the input's centre
|
|
924
|
+
line. Raised from IDU_EMATE_APPL_WEB (#014). */
|
|
925
|
+
.fdy-filterbar>.fdy-check,.fdy-filterbar>.fdy-radio,.fdy-filterbar>.fdy-switch,.fdy-filterbar>.fdy-btn{min-height:var(--control-h);}
|
|
918
926
|
.fdy-filterbar__actions{display:flex;align-items:center;gap:var(--space-2);margin-left:auto;}
|
|
919
927
|
/* Opt-in: sit the actions inline right after the last field instead of at the far edge — so when the
|
|
920
928
|
* bar wraps they read as attached to the filters rather than shoved to the right of a lonely row. */
|
|
@@ -1284,15 +1292,37 @@ fieldset.fdy-field>legend{padding:0;float:none;margin-bottom:var(--space-2);}
|
|
|
1284
1292
|
back on the cell that sticks. */
|
|
1285
1293
|
.fdy-table--sticky{border-collapse:separate;border-spacing:0;}
|
|
1286
1294
|
.fdy-table--sticky th,.fdy-table--sticky td{border-bottom:var(--bw) solid var(--color-border-muted);}
|
|
1287
|
-
|
|
1288
|
-
/*
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
.
|
|
1293
|
-
.fdy-table--sticky
|
|
1294
|
-
|
|
1295
|
-
|
|
1295
|
+
|
|
1296
|
+
/* Freezing the HEADER ROW is its own modifier because it needs a vertical
|
|
1297
|
+
scrollport (`.fdy-table-scroll--frozen`). A table that only freezes columns
|
|
1298
|
+
scrolls with the PAGE, and `top:0` against the page sticks the header under
|
|
1299
|
+
the viewport edge — over the app's own top bar — which is worse than not
|
|
1300
|
+
freezing it. Ask for the axis you actually have. */
|
|
1301
|
+
.fdy-table--sticky-head thead th{position:sticky;top:0;z-index:2;border-bottom:var(--bw) solid var(--color-border);}
|
|
1302
|
+
|
|
1303
|
+
/* Freezing a COLUMN: put `.fdy-table__freeze` on every cell of it, header
|
|
1304
|
+
included, and give each frozen column its own `--fdy-freeze-left` — 0 for the
|
|
1305
|
+
first, the summed widths of the frozen columns left of it after that. One
|
|
1306
|
+
frozen column needs no variable at all. Mark the last one `--edge` so the
|
|
1307
|
+
reader can see where the frozen block ends.
|
|
1308
|
+
|
|
1309
|
+
The offsets are the caller's job on purpose: they depend on rendered column
|
|
1310
|
+
widths, which CSS cannot sum, and hard-coding them here would only work for
|
|
1311
|
+
tables whose columns are all the same width. */
|
|
1312
|
+
.fdy-table--sticky .fdy-table__freeze{position:sticky;left:var(--fdy-freeze-left,0);}
|
|
1313
|
+
/* A frozen body cell slides OVER the data, so it must be OPAQUE — otherwise the
|
|
1314
|
+
cells beneath show through it. A `th` already carries the header tint from the
|
|
1315
|
+
base rule, and that tint is usually the whole point: it is what marks a column
|
|
1316
|
+
as identity rather than data. So only a `td` is given a surface here. A table
|
|
1317
|
+
that wants its frozen `th` to read as a body row instead — a rate matrix, where
|
|
1318
|
+
a hovered row should band unbroken across the freeze line — says so itself. */
|
|
1319
|
+
.fdy-table--sticky tbody .fdy-table__freeze{z-index:1;}
|
|
1320
|
+
.fdy-table--sticky tbody td.fdy-table__freeze{background:var(--color-surface);}
|
|
1321
|
+
.fdy-table--sticky tbody tr:hover td.fdy-table__freeze{background:var(--color-surface-2);}
|
|
1322
|
+
/* A frozen header cell is stuck on both axes wherever the head is frozen too, so
|
|
1323
|
+
it has to outrank both. */
|
|
1324
|
+
.fdy-table--sticky thead .fdy-table__freeze{z-index:3;}
|
|
1325
|
+
.fdy-table--sticky .fdy-table__freeze--edge{border-right:var(--bw) solid var(--color-border);}
|
|
1296
1326
|
|
|
1297
1327
|
/* The scrollport a sticky cell sticks to. Both axes scroll here, and the height is a
|
|
1298
1328
|
custom property so a page can size it without out-specifying this rule. */
|
package/package.json
CHANGED
|
@@ -28,6 +28,14 @@
|
|
|
28
28
|
* `flex:1 1 16rem` reserves 16rem for line-breaking), NOT its rendered width — so the grow basis,
|
|
29
29
|
* not the visible width, decides the wrap point. Margins can't keep the actions off a lonely wrapped
|
|
30
30
|
* row; to avoid stranded actions, tune the --w-grow basis or drop a field so the bar fits one row. */
|
|
31
|
+
/* A control that carries NO label of its own — a checkbox, a switch, a lone
|
|
32
|
+
button — in a bar whose `align-items:flex-end` exists to line up LABELLED
|
|
33
|
+
fields. Flex-end puts such a control's bottom on the inputs' bottom, so a
|
|
34
|
+
20px checkbox sits well below the 32px input's centre line and reads as
|
|
35
|
+
dropped. Giving it the height of a control lands its box exactly where an
|
|
36
|
+
input's box ends, and its own centring then puts it on the input's centre
|
|
37
|
+
line. Raised from IDU_EMATE_APPL_WEB (#014). */
|
|
38
|
+
.fdy-filterbar>.fdy-check,.fdy-filterbar>.fdy-radio,.fdy-filterbar>.fdy-switch,.fdy-filterbar>.fdy-btn{min-height:var(--control-h);}
|
|
31
39
|
.fdy-filterbar__actions{display:flex;align-items:center;gap:var(--space-2);margin-left:auto;}
|
|
32
40
|
/* Opt-in: sit the actions inline right after the last field instead of at the far edge — so when the
|
|
33
41
|
* bar wraps they read as attached to the filters rather than shoved to the right of a lonely row. */
|
package/src/components/table.css
CHANGED
|
@@ -47,15 +47,37 @@
|
|
|
47
47
|
back on the cell that sticks. */
|
|
48
48
|
.fdy-table--sticky{border-collapse:separate;border-spacing:0;}
|
|
49
49
|
.fdy-table--sticky th,.fdy-table--sticky td{border-bottom:var(--bw) solid var(--color-border-muted);}
|
|
50
|
-
|
|
51
|
-
/*
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
.
|
|
56
|
-
.fdy-table--sticky
|
|
57
|
-
|
|
58
|
-
|
|
50
|
+
|
|
51
|
+
/* Freezing the HEADER ROW is its own modifier because it needs a vertical
|
|
52
|
+
scrollport (`.fdy-table-scroll--frozen`). A table that only freezes columns
|
|
53
|
+
scrolls with the PAGE, and `top:0` against the page sticks the header under
|
|
54
|
+
the viewport edge — over the app's own top bar — which is worse than not
|
|
55
|
+
freezing it. Ask for the axis you actually have. */
|
|
56
|
+
.fdy-table--sticky-head thead th{position:sticky;top:0;z-index:2;border-bottom:var(--bw) solid var(--color-border);}
|
|
57
|
+
|
|
58
|
+
/* Freezing a COLUMN: put `.fdy-table__freeze` on every cell of it, header
|
|
59
|
+
included, and give each frozen column its own `--fdy-freeze-left` — 0 for the
|
|
60
|
+
first, the summed widths of the frozen columns left of it after that. One
|
|
61
|
+
frozen column needs no variable at all. Mark the last one `--edge` so the
|
|
62
|
+
reader can see where the frozen block ends.
|
|
63
|
+
|
|
64
|
+
The offsets are the caller's job on purpose: they depend on rendered column
|
|
65
|
+
widths, which CSS cannot sum, and hard-coding them here would only work for
|
|
66
|
+
tables whose columns are all the same width. */
|
|
67
|
+
.fdy-table--sticky .fdy-table__freeze{position:sticky;left:var(--fdy-freeze-left,0);}
|
|
68
|
+
/* A frozen body cell slides OVER the data, so it must be OPAQUE — otherwise the
|
|
69
|
+
cells beneath show through it. A `th` already carries the header tint from the
|
|
70
|
+
base rule, and that tint is usually the whole point: it is what marks a column
|
|
71
|
+
as identity rather than data. So only a `td` is given a surface here. A table
|
|
72
|
+
that wants its frozen `th` to read as a body row instead — a rate matrix, where
|
|
73
|
+
a hovered row should band unbroken across the freeze line — says so itself. */
|
|
74
|
+
.fdy-table--sticky tbody .fdy-table__freeze{z-index:1;}
|
|
75
|
+
.fdy-table--sticky tbody td.fdy-table__freeze{background:var(--color-surface);}
|
|
76
|
+
.fdy-table--sticky tbody tr:hover td.fdy-table__freeze{background:var(--color-surface-2);}
|
|
77
|
+
/* A frozen header cell is stuck on both axes wherever the head is frozen too, so
|
|
78
|
+
it has to outrank both. */
|
|
79
|
+
.fdy-table--sticky thead .fdy-table__freeze{z-index:3;}
|
|
80
|
+
.fdy-table--sticky .fdy-table__freeze--edge{border-right:var(--bw) solid var(--color-border);}
|
|
59
81
|
|
|
60
82
|
/* The scrollport a sticky cell sticks to. Both axes scroll here, and the height is a
|
|
61
83
|
custom property so a page can size it without out-specifying this rule. */
|