@cahyo-dimas/freeday 3.9.4 → 3.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +100 -0
- package/COMPONENTS.md +47 -3
- package/README.id.md +39 -11
- package/README.md +37 -10
- package/adapters/blazor/FdyDateRange.razor +20 -2
- package/adapters/blazor/FdyDateRange.razor.cs +20 -0
- package/adapters/blazor/FdyTimepicker.razor +23 -0
- package/adapters/blazor/FdyTimepicker.razor.cs +79 -0
- package/adapters/react/components/FdyDateRange.tsx +29 -0
- package/adapters/react/components/FdyTimepicker.tsx +212 -0
- package/adapters/react/index.d.ts +1 -0
- package/adapters/react/index.js +1 -0
- package/adapters/vue/components/FdyDateRange.vue +29 -0
- package/adapters/vue/components/FdyTimepicker.vue +276 -0
- package/adapters/vue/index.d.ts +1 -0
- package/adapters/vue/index.js +1 -0
- package/dist/freeday-timepicker.js +44 -1
- package/dist/freeday.bundle.css +74 -30
- package/dist/freeday.css +74 -30
- package/dist/freeday.js +44 -1
- package/docs/agent-onboarding.md +3 -3
- package/docs/getting-started.md +12 -5
- package/docs/integrations.md +2 -2
- package/package.json +4 -2
- package/src/base.css +0 -3
- package/src/components/avatar.css +1 -1
- package/src/components/breadcrumb.css +1 -1
- package/src/components/cfl.css +72 -25
package/dist/freeday.bundle.css
CHANGED
|
@@ -1213,9 +1213,6 @@ a { color: var(--color-primary-strong); }
|
|
|
1213
1213
|
* framework with its preflight OFF (the recommended pairing), a semantic <ul>/<ol> keeps native
|
|
1214
1214
|
* bullets + a 40px indent; add this class (or a Freeday list component) to normalise it. */
|
|
1215
1215
|
.fdy-list-reset { list-style: none; margin: 0; padding: 0; }
|
|
1216
|
-
@media (prefers-reduced-motion: reduce) {
|
|
1217
|
-
*, *::before, *::after { animation-duration: .001ms !important; transition-duration: .001ms !important; }
|
|
1218
|
-
}
|
|
1219
1216
|
|
|
1220
1217
|
/* ===========================================================================
|
|
1221
1218
|
* Reduce Motion: SETIAP transisi dinetralkan, bukan daftar yang dipelihara tangan.
|
|
@@ -1495,7 +1492,7 @@ a { color: var(--color-primary-strong); }
|
|
|
1495
1492
|
@media (prefers-reduced-motion:no-preference){.fdy-autocomplete__listbox:not([hidden]){animation:fdy-combo-in var(--dur-fast) var(--ease-standard);}}
|
|
1496
1493
|
|
|
1497
1494
|
/* Freeday. Avatar */
|
|
1498
|
-
.fdy-avatar{display:inline-flex;align-items:center;justify-content:center;flex:none;width:2.5rem;height:2.5rem;border-radius:var(--radius-full);background:var(--color-primary-soft);color:var(--color-primary-strong);font-family:var(--font-body);font-weight:var(--weight-semibold);font-size:var(--text-sm);line-height:1;overflow:hidden;user-select:none;}
|
|
1495
|
+
.fdy-avatar{display:inline-flex;align-items:center;justify-content:center;flex:none;width:2.5rem;height:2.5rem;border-radius:var(--radius-full);background:var(--color-primary-soft);color:var(--color-primary-strong);font-family:var(--font-body);font-weight:var(--weight-semibold);font-size:var(--text-sm);line-height:1;overflow:hidden;-webkit-user-select:none;user-select:none;}
|
|
1499
1496
|
.fdy-avatar img{width:100%;height:100%;object-fit:cover;}
|
|
1500
1497
|
/* --xs exists for an avatar INSIDE a control: `.fdy-btn--sm` is exactly 2rem tall, which is also
|
|
1501
1498
|
`--sm`'s size, so a small avatar in a small button fills it edge to edge and the ghost border
|
|
@@ -1651,7 +1648,7 @@ a { color: var(--color-primary-strong); }
|
|
|
1651
1648
|
.fdy-breadcrumb__link:hover{color:var(--color-primary-strong);text-decoration:underline;}
|
|
1652
1649
|
.fdy-breadcrumb__link:focus-visible{outline:none;box-shadow:0 0 0 3px rgba(var(--color-primary-rgb),.26);}
|
|
1653
1650
|
.fdy-breadcrumb__item[aria-current="page"]{color:var(--color-text);font-weight:var(--weight-medium);}
|
|
1654
|
-
.fdy-breadcrumb__sep{color:var(--color-text-subtle);user-select:none;}
|
|
1651
|
+
.fdy-breadcrumb__sep{color:var(--color-text-subtle);-webkit-user-select:none;user-select:none;}
|
|
1655
1652
|
|
|
1656
1653
|
/* Freeday. Responsive display utilities (pairs with freeday-breakpoint.js).
|
|
1657
1654
|
* Breakpoint scale (min-width, px): sm 600 · md 960 · lg 1280 · xl 1920.
|
|
@@ -1957,7 +1954,13 @@ a { color: var(--color-primary-strong); }
|
|
|
1957
1954
|
* size, which is what made `.fdy-stats--inline` collapse to three zero tracks in 3.1.0. This box
|
|
1958
1955
|
* takes its width from the dialog (`min(46rem, 100vw - …)`, an explicit width) and already scrolls
|
|
1959
1956
|
* its own content, so it never sized to the table to begin with. */
|
|
1960
|
-
.fdy-cfl__results{
|
|
1957
|
+
.fdy-cfl__results{overflow:auto;max-height:min(24rem,50vh);}
|
|
1958
|
+
/* Fenced the way composition.css:62 fences its own, so the declaration states the condition it
|
|
1959
|
+
needs instead of relying on a browser to drop it. Safari 15.4 to 15.8 is inside the floor the
|
|
1960
|
+
README states and has no container queries at all. */
|
|
1961
|
+
@supports (container-type:inline-size){
|
|
1962
|
+
.fdy-cfl__results{container:fdy-cfl / inline-size;}
|
|
1963
|
+
}
|
|
1961
1964
|
.fdy-cfl__results .fdy-table th{position:sticky;top:0;z-index:1;}
|
|
1962
1965
|
|
|
1963
1966
|
.fdy-cfl__row{cursor:pointer;}
|
|
@@ -1999,30 +2002,71 @@ a { color: var(--color-primary-strong); }
|
|
|
1999
2002
|
*
|
|
2000
2003
|
* Column headers ARE a real loss here, and a deliberate one: `<thead>` is hidden, because a header
|
|
2001
2004
|
* row that costs a third of the width buys nothing when each row is labelled by its own title. */
|
|
2002
|
-
@
|
|
2003
|
-
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
|
|
2009
|
-
|
|
2010
|
-
|
|
2011
|
-
|
|
2012
|
-
|
|
2013
|
-
|
|
2014
|
-
|
|
2015
|
-
|
|
2016
|
-
|
|
2017
|
-
|
|
2018
|
-
|
|
2019
|
-
|
|
2020
|
-
|
|
2021
|
-
|
|
2022
|
-
|
|
2023
|
-
|
|
2024
|
-
|
|
2025
|
-
|
|
2005
|
+
@supports (container-type:inline-size){
|
|
2006
|
+
@container fdy-cfl (max-width: 30rem){
|
|
2007
|
+
.fdy-cfl__results .fdy-table,
|
|
2008
|
+
.fdy-cfl__results .fdy-table tbody{display:block;width:100%;}
|
|
2009
|
+
.fdy-cfl__results .fdy-table thead{display:none;}
|
|
2010
|
+
.fdy-cfl__row{display:flex;flex-wrap:wrap;align-items:baseline;column-gap:var(--space-2);padding:var(--space-3) var(--space-4);border-bottom:var(--bw) solid var(--color-border-muted);}
|
|
2011
|
+
.fdy-cfl__results .fdy-table tbody tr:last-child{border-bottom:0;}
|
|
2012
|
+
.fdy-cfl__row > td{display:block;padding:0;border:0;}
|
|
2013
|
+
/* The title takes the whole first line, which is what pushes every remaining cell onto the second
|
|
2014
|
+
one — no selector has to know how many columns there are, or which of them is last. */
|
|
2015
|
+
.fdy-cfl__row > td:first-child:not(.fdy-cfl__check),
|
|
2016
|
+
.fdy-cfl__row > .fdy-cfl__check + td{font-weight:var(--weight-semibold);color:var(--color-text);}
|
|
2017
|
+
.fdy-cfl__row > td:first-child:not(.fdy-cfl__check){flex:0 0 100%;}
|
|
2018
|
+
/* Multi-select: the checkbox shares line one with the title, so the title claims the rest of it. */
|
|
2019
|
+
.fdy-cfl__row > .fdy-cfl__check + td{flex:1 0 calc(100% - var(--space-6));}
|
|
2020
|
+
.fdy-cfl__row > td:first-child:not(.fdy-cfl__check) ~ td,
|
|
2021
|
+
.fdy-cfl__row > .fdy-cfl__check + td ~ td{font-size:var(--text-xs);color:var(--color-text-muted);}
|
|
2022
|
+
.fdy-cfl__row > td:first-child:not(.fdy-cfl__check) ~ td:empty,
|
|
2023
|
+
.fdy-cfl__row > .fdy-cfl__check + td ~ td:empty{display:none;}
|
|
2024
|
+
.fdy-cfl__row > td:first-child:not(.fdy-cfl__check) ~ td::before,
|
|
2025
|
+
.fdy-cfl__row > .fdy-cfl__check + td ~ td::before{content:"·";margin-right:var(--space-2);color:var(--color-text-subtle);}
|
|
2026
|
+
.fdy-cfl__row > td:first-child:not(.fdy-cfl__check) + td::before,
|
|
2027
|
+
.fdy-cfl__row > .fdy-cfl__check + td + td::before{content:none;}
|
|
2028
|
+
/* The checkbox keeps its own line position beside the title rather than above it. */
|
|
2029
|
+
.fdy-cfl__row > .fdy-cfl__check{flex:none;width:auto;align-self:center;}
|
|
2030
|
+
}
|
|
2031
|
+
}
|
|
2032
|
+
|
|
2033
|
+
/* The same block for a browser that has no container queries, which is every Safari from 15.4 to
|
|
2034
|
+
* 15.8 and inside the floor the README states. There the @supports above is false, the stacked
|
|
2035
|
+
* layout never applied, and a 372px dialog kept a three-column master-data table that scrolls on
|
|
2036
|
+
* both axes.
|
|
2037
|
+
*
|
|
2038
|
+
* The condition is a VIEWPORT width, the only width this path can read. 32rem is derived from the
|
|
2039
|
+
* dialog rather than picked: the dialog is min(46rem, 100vw - var(--space-8)) with --space-8 at
|
|
2040
|
+
* 2rem, and the results box takes that width, so it sits at or under 30rem exactly when the
|
|
2041
|
+
* viewport sits at or under 32rem. What a media query cannot answer is the case the container
|
|
2042
|
+
* query exists for, a narrow dialog inside a wide viewport, which is a docked panel on a desktop;
|
|
2043
|
+
* on those browsers that one case keeps the scrolling table it has always had.
|
|
2044
|
+
*
|
|
2045
|
+
* The body is a copy of the body above, because CSS has no way to share one declaration block
|
|
2046
|
+
* between two different conditions. test/baseline.test.mjs compares the two, so an edit that
|
|
2047
|
+
* reaches one of them and misses the other fails there. */
|
|
2048
|
+
@supports not (container-type:inline-size){
|
|
2049
|
+
@media (max-width:32rem){
|
|
2050
|
+
.fdy-cfl__results .fdy-table,
|
|
2051
|
+
.fdy-cfl__results .fdy-table tbody{display:block;width:100%;}
|
|
2052
|
+
.fdy-cfl__results .fdy-table thead{display:none;}
|
|
2053
|
+
.fdy-cfl__row{display:flex;flex-wrap:wrap;align-items:baseline;column-gap:var(--space-2);padding:var(--space-3) var(--space-4);border-bottom:var(--bw) solid var(--color-border-muted);}
|
|
2054
|
+
.fdy-cfl__results .fdy-table tbody tr:last-child{border-bottom:0;}
|
|
2055
|
+
.fdy-cfl__row > td{display:block;padding:0;border:0;}
|
|
2056
|
+
.fdy-cfl__row > td:first-child:not(.fdy-cfl__check),
|
|
2057
|
+
.fdy-cfl__row > .fdy-cfl__check + td{font-weight:var(--weight-semibold);color:var(--color-text);}
|
|
2058
|
+
.fdy-cfl__row > td:first-child:not(.fdy-cfl__check){flex:0 0 100%;}
|
|
2059
|
+
.fdy-cfl__row > .fdy-cfl__check + td{flex:1 0 calc(100% - var(--space-6));}
|
|
2060
|
+
.fdy-cfl__row > td:first-child:not(.fdy-cfl__check) ~ td,
|
|
2061
|
+
.fdy-cfl__row > .fdy-cfl__check + td ~ td{font-size:var(--text-xs);color:var(--color-text-muted);}
|
|
2062
|
+
.fdy-cfl__row > td:first-child:not(.fdy-cfl__check) ~ td:empty,
|
|
2063
|
+
.fdy-cfl__row > .fdy-cfl__check + td ~ td:empty{display:none;}
|
|
2064
|
+
.fdy-cfl__row > td:first-child:not(.fdy-cfl__check) ~ td::before,
|
|
2065
|
+
.fdy-cfl__row > .fdy-cfl__check + td ~ td::before{content:"·";margin-right:var(--space-2);color:var(--color-text-subtle);}
|
|
2066
|
+
.fdy-cfl__row > td:first-child:not(.fdy-cfl__check) + td::before,
|
|
2067
|
+
.fdy-cfl__row > .fdy-cfl__check + td + td::before{content:none;}
|
|
2068
|
+
.fdy-cfl__row > .fdy-cfl__check{flex:none;width:auto;align-self:center;}
|
|
2069
|
+
}
|
|
2026
2070
|
}
|
|
2027
2071
|
|
|
2028
2072
|
/* Freeday. Charts (zero-dependency CSS/SVG, rendered by freeday-chart.js).
|
package/dist/freeday.css
CHANGED
|
@@ -36,9 +36,6 @@ a { color: var(--color-primary-strong); }
|
|
|
36
36
|
* framework with its preflight OFF (the recommended pairing), a semantic <ul>/<ol> keeps native
|
|
37
37
|
* bullets + a 40px indent; add this class (or a Freeday list component) to normalise it. */
|
|
38
38
|
.fdy-list-reset { list-style: none; margin: 0; padding: 0; }
|
|
39
|
-
@media (prefers-reduced-motion: reduce) {
|
|
40
|
-
*, *::before, *::after { animation-duration: .001ms !important; transition-duration: .001ms !important; }
|
|
41
|
-
}
|
|
42
39
|
|
|
43
40
|
/* ===========================================================================
|
|
44
41
|
* Reduce Motion: SETIAP transisi dinetralkan, bukan daftar yang dipelihara tangan.
|
|
@@ -318,7 +315,7 @@ a { color: var(--color-primary-strong); }
|
|
|
318
315
|
@media (prefers-reduced-motion:no-preference){.fdy-autocomplete__listbox:not([hidden]){animation:fdy-combo-in var(--dur-fast) var(--ease-standard);}}
|
|
319
316
|
|
|
320
317
|
/* Freeday. Avatar */
|
|
321
|
-
.fdy-avatar{display:inline-flex;align-items:center;justify-content:center;flex:none;width:2.5rem;height:2.5rem;border-radius:var(--radius-full);background:var(--color-primary-soft);color:var(--color-primary-strong);font-family:var(--font-body);font-weight:var(--weight-semibold);font-size:var(--text-sm);line-height:1;overflow:hidden;user-select:none;}
|
|
318
|
+
.fdy-avatar{display:inline-flex;align-items:center;justify-content:center;flex:none;width:2.5rem;height:2.5rem;border-radius:var(--radius-full);background:var(--color-primary-soft);color:var(--color-primary-strong);font-family:var(--font-body);font-weight:var(--weight-semibold);font-size:var(--text-sm);line-height:1;overflow:hidden;-webkit-user-select:none;user-select:none;}
|
|
322
319
|
.fdy-avatar img{width:100%;height:100%;object-fit:cover;}
|
|
323
320
|
/* --xs exists for an avatar INSIDE a control: `.fdy-btn--sm` is exactly 2rem tall, which is also
|
|
324
321
|
`--sm`'s size, so a small avatar in a small button fills it edge to edge and the ghost border
|
|
@@ -474,7 +471,7 @@ a { color: var(--color-primary-strong); }
|
|
|
474
471
|
.fdy-breadcrumb__link:hover{color:var(--color-primary-strong);text-decoration:underline;}
|
|
475
472
|
.fdy-breadcrumb__link:focus-visible{outline:none;box-shadow:0 0 0 3px rgba(var(--color-primary-rgb),.26);}
|
|
476
473
|
.fdy-breadcrumb__item[aria-current="page"]{color:var(--color-text);font-weight:var(--weight-medium);}
|
|
477
|
-
.fdy-breadcrumb__sep{color:var(--color-text-subtle);user-select:none;}
|
|
474
|
+
.fdy-breadcrumb__sep{color:var(--color-text-subtle);-webkit-user-select:none;user-select:none;}
|
|
478
475
|
|
|
479
476
|
/* Freeday. Responsive display utilities (pairs with freeday-breakpoint.js).
|
|
480
477
|
* Breakpoint scale (min-width, px): sm 600 · md 960 · lg 1280 · xl 1920.
|
|
@@ -780,7 +777,13 @@ a { color: var(--color-primary-strong); }
|
|
|
780
777
|
* size, which is what made `.fdy-stats--inline` collapse to three zero tracks in 3.1.0. This box
|
|
781
778
|
* takes its width from the dialog (`min(46rem, 100vw - …)`, an explicit width) and already scrolls
|
|
782
779
|
* its own content, so it never sized to the table to begin with. */
|
|
783
|
-
.fdy-cfl__results{
|
|
780
|
+
.fdy-cfl__results{overflow:auto;max-height:min(24rem,50vh);}
|
|
781
|
+
/* Fenced the way composition.css:62 fences its own, so the declaration states the condition it
|
|
782
|
+
needs instead of relying on a browser to drop it. Safari 15.4 to 15.8 is inside the floor the
|
|
783
|
+
README states and has no container queries at all. */
|
|
784
|
+
@supports (container-type:inline-size){
|
|
785
|
+
.fdy-cfl__results{container:fdy-cfl / inline-size;}
|
|
786
|
+
}
|
|
784
787
|
.fdy-cfl__results .fdy-table th{position:sticky;top:0;z-index:1;}
|
|
785
788
|
|
|
786
789
|
.fdy-cfl__row{cursor:pointer;}
|
|
@@ -822,30 +825,71 @@ a { color: var(--color-primary-strong); }
|
|
|
822
825
|
*
|
|
823
826
|
* Column headers ARE a real loss here, and a deliberate one: `<thead>` is hidden, because a header
|
|
824
827
|
* row that costs a third of the width buys nothing when each row is labelled by its own title. */
|
|
825
|
-
@
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
828
|
+
@supports (container-type:inline-size){
|
|
829
|
+
@container fdy-cfl (max-width: 30rem){
|
|
830
|
+
.fdy-cfl__results .fdy-table,
|
|
831
|
+
.fdy-cfl__results .fdy-table tbody{display:block;width:100%;}
|
|
832
|
+
.fdy-cfl__results .fdy-table thead{display:none;}
|
|
833
|
+
.fdy-cfl__row{display:flex;flex-wrap:wrap;align-items:baseline;column-gap:var(--space-2);padding:var(--space-3) var(--space-4);border-bottom:var(--bw) solid var(--color-border-muted);}
|
|
834
|
+
.fdy-cfl__results .fdy-table tbody tr:last-child{border-bottom:0;}
|
|
835
|
+
.fdy-cfl__row > td{display:block;padding:0;border:0;}
|
|
836
|
+
/* The title takes the whole first line, which is what pushes every remaining cell onto the second
|
|
837
|
+
one — no selector has to know how many columns there are, or which of them is last. */
|
|
838
|
+
.fdy-cfl__row > td:first-child:not(.fdy-cfl__check),
|
|
839
|
+
.fdy-cfl__row > .fdy-cfl__check + td{font-weight:var(--weight-semibold);color:var(--color-text);}
|
|
840
|
+
.fdy-cfl__row > td:first-child:not(.fdy-cfl__check){flex:0 0 100%;}
|
|
841
|
+
/* Multi-select: the checkbox shares line one with the title, so the title claims the rest of it. */
|
|
842
|
+
.fdy-cfl__row > .fdy-cfl__check + td{flex:1 0 calc(100% - var(--space-6));}
|
|
843
|
+
.fdy-cfl__row > td:first-child:not(.fdy-cfl__check) ~ td,
|
|
844
|
+
.fdy-cfl__row > .fdy-cfl__check + td ~ td{font-size:var(--text-xs);color:var(--color-text-muted);}
|
|
845
|
+
.fdy-cfl__row > td:first-child:not(.fdy-cfl__check) ~ td:empty,
|
|
846
|
+
.fdy-cfl__row > .fdy-cfl__check + td ~ td:empty{display:none;}
|
|
847
|
+
.fdy-cfl__row > td:first-child:not(.fdy-cfl__check) ~ td::before,
|
|
848
|
+
.fdy-cfl__row > .fdy-cfl__check + td ~ td::before{content:"·";margin-right:var(--space-2);color:var(--color-text-subtle);}
|
|
849
|
+
.fdy-cfl__row > td:first-child:not(.fdy-cfl__check) + td::before,
|
|
850
|
+
.fdy-cfl__row > .fdy-cfl__check + td + td::before{content:none;}
|
|
851
|
+
/* The checkbox keeps its own line position beside the title rather than above it. */
|
|
852
|
+
.fdy-cfl__row > .fdy-cfl__check{flex:none;width:auto;align-self:center;}
|
|
853
|
+
}
|
|
854
|
+
}
|
|
855
|
+
|
|
856
|
+
/* The same block for a browser that has no container queries, which is every Safari from 15.4 to
|
|
857
|
+
* 15.8 and inside the floor the README states. There the @supports above is false, the stacked
|
|
858
|
+
* layout never applied, and a 372px dialog kept a three-column master-data table that scrolls on
|
|
859
|
+
* both axes.
|
|
860
|
+
*
|
|
861
|
+
* The condition is a VIEWPORT width, the only width this path can read. 32rem is derived from the
|
|
862
|
+
* dialog rather than picked: the dialog is min(46rem, 100vw - var(--space-8)) with --space-8 at
|
|
863
|
+
* 2rem, and the results box takes that width, so it sits at or under 30rem exactly when the
|
|
864
|
+
* viewport sits at or under 32rem. What a media query cannot answer is the case the container
|
|
865
|
+
* query exists for, a narrow dialog inside a wide viewport, which is a docked panel on a desktop;
|
|
866
|
+
* on those browsers that one case keeps the scrolling table it has always had.
|
|
867
|
+
*
|
|
868
|
+
* The body is a copy of the body above, because CSS has no way to share one declaration block
|
|
869
|
+
* between two different conditions. test/baseline.test.mjs compares the two, so an edit that
|
|
870
|
+
* reaches one of them and misses the other fails there. */
|
|
871
|
+
@supports not (container-type:inline-size){
|
|
872
|
+
@media (max-width:32rem){
|
|
873
|
+
.fdy-cfl__results .fdy-table,
|
|
874
|
+
.fdy-cfl__results .fdy-table tbody{display:block;width:100%;}
|
|
875
|
+
.fdy-cfl__results .fdy-table thead{display:none;}
|
|
876
|
+
.fdy-cfl__row{display:flex;flex-wrap:wrap;align-items:baseline;column-gap:var(--space-2);padding:var(--space-3) var(--space-4);border-bottom:var(--bw) solid var(--color-border-muted);}
|
|
877
|
+
.fdy-cfl__results .fdy-table tbody tr:last-child{border-bottom:0;}
|
|
878
|
+
.fdy-cfl__row > td{display:block;padding:0;border:0;}
|
|
879
|
+
.fdy-cfl__row > td:first-child:not(.fdy-cfl__check),
|
|
880
|
+
.fdy-cfl__row > .fdy-cfl__check + td{font-weight:var(--weight-semibold);color:var(--color-text);}
|
|
881
|
+
.fdy-cfl__row > td:first-child:not(.fdy-cfl__check){flex:0 0 100%;}
|
|
882
|
+
.fdy-cfl__row > .fdy-cfl__check + td{flex:1 0 calc(100% - var(--space-6));}
|
|
883
|
+
.fdy-cfl__row > td:first-child:not(.fdy-cfl__check) ~ td,
|
|
884
|
+
.fdy-cfl__row > .fdy-cfl__check + td ~ td{font-size:var(--text-xs);color:var(--color-text-muted);}
|
|
885
|
+
.fdy-cfl__row > td:first-child:not(.fdy-cfl__check) ~ td:empty,
|
|
886
|
+
.fdy-cfl__row > .fdy-cfl__check + td ~ td:empty{display:none;}
|
|
887
|
+
.fdy-cfl__row > td:first-child:not(.fdy-cfl__check) ~ td::before,
|
|
888
|
+
.fdy-cfl__row > .fdy-cfl__check + td ~ td::before{content:"·";margin-right:var(--space-2);color:var(--color-text-subtle);}
|
|
889
|
+
.fdy-cfl__row > td:first-child:not(.fdy-cfl__check) + td::before,
|
|
890
|
+
.fdy-cfl__row > .fdy-cfl__check + td + td::before{content:none;}
|
|
891
|
+
.fdy-cfl__row > .fdy-cfl__check{flex:none;width:auto;align-self:center;}
|
|
892
|
+
}
|
|
849
893
|
}
|
|
850
894
|
|
|
851
895
|
/* Freeday. Charts (zero-dependency CSS/SVG, rendered by freeday-chart.js).
|
package/dist/freeday.js
CHANGED
|
@@ -4945,6 +4945,14 @@
|
|
|
4945
4945
|
trigger.setAttribute('aria-haspopup', 'listbox');
|
|
4946
4946
|
trigger.setAttribute('aria-expanded', 'false');
|
|
4947
4947
|
trigger.setAttribute('aria-label', label);
|
|
4948
|
+
/* The trigger is a <button>, which is NOT a labelable element, so a form's own `<label for>`
|
|
4949
|
+
can never activate it -- but an id is still what `aria-describedby` targets and what a host
|
|
4950
|
+
needs to point at this control. Both were unreadable from the seed until now, so a Blazor
|
|
4951
|
+
host could not name its own error text. Mirrors the datepicker's seed. */
|
|
4952
|
+
var seedId = wrap.getAttribute('data-id');
|
|
4953
|
+
if (seedId) trigger.id = seedId;
|
|
4954
|
+
var describedby = wrap.getAttribute('data-describedby');
|
|
4955
|
+
if (describedby) trigger.setAttribute('aria-describedby', describedby);
|
|
4948
4956
|
var valueSpan = document.createElement('span');
|
|
4949
4957
|
valueSpan.className = 'fdy-timepicker__value';
|
|
4950
4958
|
trigger.appendChild(valueSpan);
|
|
@@ -4982,6 +4990,30 @@
|
|
|
4982
4990
|
wrap.appendChild(panel);
|
|
4983
4991
|
|
|
4984
4992
|
var active = -1;
|
|
4993
|
+
/* A host that renders its seed ONCE and then never re-renders it (Blazor: ShouldRender is
|
|
4994
|
+
false after hydration) still has to be able to disable, lock or invalidate the field
|
|
4995
|
+
afterwards. Without this the parameter was there and nothing read it. Mirrors
|
|
4996
|
+
FreedayDatepicker.setState so the two controls of one family answer the same call. */
|
|
4997
|
+
var stateDisabled = wrap.hasAttribute('data-disabled');
|
|
4998
|
+
var stateReadonly = wrap.hasAttribute('data-readonly');
|
|
4999
|
+
var stateInvalid = wrap.hasAttribute('data-invalid');
|
|
5000
|
+
|
|
5001
|
+
function applyState() {
|
|
5002
|
+
trigger.disabled = stateDisabled;
|
|
5003
|
+
if (stateReadonly) trigger.setAttribute('aria-readonly', 'true');
|
|
5004
|
+
else trigger.removeAttribute('aria-readonly');
|
|
5005
|
+
if (stateInvalid) trigger.setAttribute('aria-invalid', 'true');
|
|
5006
|
+
else trigger.removeAttribute('aria-invalid');
|
|
5007
|
+
wrap.classList.toggle('fdy-timepicker--error', stateInvalid);
|
|
5008
|
+
if ((stateDisabled || stateReadonly) && !panel.hidden) close(false);
|
|
5009
|
+
}
|
|
5010
|
+
function setState(next) {
|
|
5011
|
+
if (!next) return;
|
|
5012
|
+
if (next.disabled != null) stateDisabled = !!next.disabled;
|
|
5013
|
+
if (next.readonly != null) stateReadonly = !!next.readonly;
|
|
5014
|
+
if (next.invalid != null) stateInvalid = !!next.invalid;
|
|
5015
|
+
applyState();
|
|
5016
|
+
}
|
|
4985
5017
|
|
|
4986
5018
|
function updateDisplay() {
|
|
4987
5019
|
if (value) {
|
|
@@ -5010,6 +5042,7 @@
|
|
|
5010
5042
|
var _pop = null;
|
|
5011
5043
|
function popCtl() { if (_pop === null && window.FreedayPopover) _pop = window.FreedayPopover.attach(panel, trigger); return _pop; }
|
|
5012
5044
|
function open() {
|
|
5045
|
+
if (stateDisabled || stateReadonly) return;
|
|
5013
5046
|
if (!panel.hidden) return;
|
|
5014
5047
|
var p = popCtl(); if (p) p.show(); else panel.hidden = false;
|
|
5015
5048
|
trigger.setAttribute('aria-expanded', 'true');
|
|
@@ -5060,10 +5093,12 @@
|
|
|
5060
5093
|
});
|
|
5061
5094
|
|
|
5062
5095
|
updateDisplay();
|
|
5096
|
+
applyState();
|
|
5063
5097
|
|
|
5064
5098
|
var api = {
|
|
5065
5099
|
wrap: wrap,
|
|
5066
5100
|
getValue: function () { return value; },
|
|
5101
|
+
setState: setState,
|
|
5067
5102
|
clear: function () { value = ''; for (var i = 0; i < opts.length; i++) opts[i].setAttribute('aria-selected', 'false'); updateDisplay(); }
|
|
5068
5103
|
};
|
|
5069
5104
|
wrap._fdyTp = api;
|
|
@@ -5083,7 +5118,15 @@
|
|
|
5083
5118
|
initAll();
|
|
5084
5119
|
}
|
|
5085
5120
|
|
|
5086
|
-
window.FreedayTimepicker = {
|
|
5121
|
+
window.FreedayTimepicker = {
|
|
5122
|
+
init: initTime,
|
|
5123
|
+
initAll: initAll,
|
|
5124
|
+
/* See api.setState above: the one call a render-once host needs. */
|
|
5125
|
+
setState: function (root, state) {
|
|
5126
|
+
var api = root && root._fdyTp ? root._fdyTp : null;
|
|
5127
|
+
if (api && api.setState) api.setState(state);
|
|
5128
|
+
}
|
|
5129
|
+
};
|
|
5087
5130
|
})();
|
|
5088
5131
|
|
|
5089
5132
|
/* Freeday, toast API (optional, zero-dependency).
|
package/docs/agent-onboarding.md
CHANGED
|
@@ -33,9 +33,9 @@ and the code looks correct and fails later.**
|
|
|
33
33
|
| Blazor (net8.0) | `@using Freeday.Blazor` (RCL) | `@bind-Value` |
|
|
34
34
|
| Static HTML, Svelte, server-rendered templates… | no wrapper: raw markup + the enhancer script | `fdy-*` DOM events |
|
|
35
35
|
|
|
36
|
-
The
|
|
37
|
-
FdyCascade · FdyCfl · FdyChart · FdyTable · FdyModal · FdyDrawer · FdyAppShell**. In
|
|
38
|
-
Vue/React/Blazor, **never hand-write the raw markup + enhancer for these
|
|
36
|
+
The thirteen: **FdyCombo · FdyDatepicker · FdyMonthpicker · FdyDateRange · FdyTimepicker ·
|
|
37
|
+
FdyAutocomplete · FdyCascade · FdyCfl · FdyChart · FdyTable · FdyModal · FdyDrawer · FdyAppShell**. In
|
|
38
|
+
Vue/React/Blazor, **never hand-write the raw markup + enhancer for these thirteen.** The raw path *appears* to work: the enhancer auto-initialises
|
|
39
39
|
once on `DOMContentLoaded` and the first render is correct. Then it fails quietly: DOM your framework
|
|
40
40
|
renders later is never hydrated, and the widget's state lives in the DOM instead of in your
|
|
41
41
|
framework's state.
|
package/docs/getting-started.md
CHANGED
|
@@ -21,8 +21,8 @@ Freeday = **CSS** (semantic tokens + `fdy-*` classes) + **zero-dependency JS enh
|
|
|
21
21
|
the enhancer owns the widget's DOM. You **listen for `fdy-*` events** (all bubbling
|
|
22
22
|
`CustomEvent`s, data in `event.detail`) → store them in your framework state. Event/API contract
|
|
23
23
|
table: [`integrations.md` §Event & API contract](integrations.md).
|
|
24
|
-
**On Vue, React or Blazor this is not the path to take for
|
|
25
|
-
`FdyDatepicker`, `FdyMonthpicker`, `FdyDateRange`, `FdyAutocomplete`, `FdyCascade`, `FdyCfl`,
|
|
24
|
+
**On Vue, React or Blazor this is not the path to take for thirteen of the components.** `FdyCombo`,
|
|
25
|
+
`FdyDatepicker`, `FdyMonthpicker`, `FdyDateRange`, `FdyTimepicker`, `FdyAutocomplete`, `FdyCascade`, `FdyCfl`,
|
|
26
26
|
`FdyChart`, `FdyTable`, `FdyModal`, `FdyDrawer`, `FdyAppShell` ship typed wrappers that own the state properly (Vue and
|
|
27
27
|
React re-implement the interaction natively; Blazor wraps the enhancer over interop). Use them;
|
|
28
28
|
the raw path is for the components without a wrapper, and for stacks without an adapter.
|
|
@@ -156,6 +156,13 @@ cp -r node_modules/@cahyo-dimas/freeday/dist ./assets/freeday # copy into your
|
|
|
156
156
|
```
|
|
157
157
|
> Two-file alternative: `freeday.tokens.css` (tokens) + `freeday.css` (components).
|
|
158
158
|
|
|
159
|
+
> **The viewport meta is required, not decoration.** Without it a mobile engine lays the page out at
|
|
160
|
+
> a default width near 980px, so `(max-width: 720px)` never matches and the kit's entire responsive
|
|
161
|
+
> layer is absent: the app shell stands in its desktop form on a phone, sidebar visible and bottom
|
|
162
|
+
> nav gone. That is not a hypothetical. It is what a fixture without the tag did on the first run of
|
|
163
|
+
> the WebKit suite, reporting `window.innerWidth` 981 on an iPhone 7 descriptor, and it is the same
|
|
164
|
+
> shape as the report that started that suite.
|
|
165
|
+
|
|
159
166
|
### 3. Load the enhancers before `</body>`
|
|
160
167
|
```html
|
|
161
168
|
<script src="assets/freeday/freeday.js" defer></script>
|
|
@@ -191,7 +198,7 @@ live docs also have a copy button per component.
|
|
|
191
198
|
```bash
|
|
192
199
|
npm i @cahyo-dimas/freeday
|
|
193
200
|
```
|
|
194
|
-
Lands in `package.json` as `"@cahyo-dimas/freeday": "^3.
|
|
201
|
+
Lands in `package.json` as `"@cahyo-dimas/freeday": "^3.11.0"` (public npm package). `dist/` is
|
|
195
202
|
committed and published → no build step; `npm ci` runs without auth.
|
|
196
203
|
|
|
197
204
|
### 2. Import the CSS + enhancers **once** in your entry (`src/main.ts`)
|
|
@@ -444,9 +451,9 @@ kit's CSS/enhancers), then bind:
|
|
|
444
451
|
<FdyChart Type="donut" Values="_byCity" Labels="_cityLabels" AriaLabel="Revenue by city" />
|
|
445
452
|
<FdyDrawer @bind-Open="_drawerOpen" Title="Detail" Side="right">…</FdyDrawer>
|
|
446
453
|
```
|
|
447
|
-
|
|
454
|
+
Thirteen components at parity with the Vue/React adapters: **`FdyModal`** · **`FdyDrawer`** (`@bind-Open`,
|
|
448
455
|
`Title`, `Size`/`Side`, `Dismissible`) · **`FdyCombo<TValue>`** · **`FdyDatepicker`** ·
|
|
449
|
-
**`FdyMonthpicker`** (`@bind-Value` as `yyyy-MM`) · **`FdyAutocomplete`** · **`FdyCascade`** · **`FdyDateRange`** (`@bind-From`/`@bind-To`) ·
|
|
456
|
+
**`FdyMonthpicker`** (`@bind-Value` as `yyyy-MM`) · **`FdyTimepicker`** (`@bind-Value` as `HH:MM`) · **`FdyAutocomplete`** · **`FdyCascade`** · **`FdyDateRange`** (`@bind-From`/`@bind-To`) ·
|
|
450
457
|
**`FdyCfl<TRow>`** (async `LoadPage`) · **`FdyChart`** · **`FdyTable<TRow>`** (client sort/filter/page,
|
|
451
458
|
or controlled `Sort`/`Filters`/`Page` for a server-paged table; `RowActivatable`, `RowDetail`) ·
|
|
452
459
|
**`FdyAppShell`** (`@bind-NavOpen`). Each
|
package/docs/integrations.md
CHANGED
|
@@ -154,7 +154,7 @@ function Panel(): JSX.Element {
|
|
|
154
154
|
```
|
|
155
155
|
> **Controlled alternative (parity with Vue's `v-model`):** `@cahyo-dimas/freeday/react` also exports
|
|
156
156
|
> the typed components `FdyCombo` / `FdyDatepicker` / `FdyMonthpicker` / `FdyDateRange` /
|
|
157
|
-
> `FdyAutocomplete` / `FdyCascade` / `FdyCfl` / `FdyChart` / `FdyTable` / `FdyModal` / `FdyDrawer` /
|
|
157
|
+
> `FdyTimepicker` / `FdyAutocomplete` / `FdyCascade` / `FdyCfl` / `FdyChart` / `FdyTable` / `FdyModal` / `FdyDrawer` /
|
|
158
158
|
> `FdyAppShell`, with plain
|
|
159
159
|
> `value`/`onChange` (props in, events out), no `data-fdy-*` + manual event listener:
|
|
160
160
|
> ```tsx
|
|
@@ -200,7 +200,7 @@ document.addEventListener('fdy-form-invalid', (e) =>
|
|
|
200
200
|
|
|
201
201
|
> **Native components (parity with Vue's `v-model` / React's `value`/`onChange`):** the
|
|
202
202
|
> **`Freeday.Blazor`** RCL (net8.0, `adapters/blazor/`) ships the typed components `FdyCombo<TValue>` /
|
|
203
|
-
> `FdyDatepicker` / `FdyMonthpicker` / `FdyDateRange` / `FdyAutocomplete` / `FdyCascade` /
|
|
203
|
+
> `FdyDatepicker` / `FdyMonthpicker` / `FdyDateRange` / `FdyTimepicker` / `FdyAutocomplete` / `FdyCascade` /
|
|
204
204
|
> `FdyCfl<TRow>` / `FdyChart` / `FdyTable<TRow>` / `FdyModal` / `FdyDrawer` / `FdyAppShell` with `@bind`, no `@ref` / manual `initAll` / `[JSInvokable]`:
|
|
205
205
|
> ```razor
|
|
206
206
|
> @using Freeday.Blazor
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cahyo-dimas/freeday",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.11.0",
|
|
4
4
|
"description": "Freeday: token-driven, framework-agnostic UI KIT (design source-of-truth).",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -96,14 +96,16 @@
|
|
|
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/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/harness-contract.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",
|
|
103
103
|
"test:blazor": "dotnet test test/blazor -v quiet --nologo",
|
|
104
|
+
"test:webkit": "playwright test",
|
|
104
105
|
"test:blazor-server": "node --test browser/blazor-server.mjs"
|
|
105
106
|
},
|
|
106
107
|
"devDependencies": {
|
|
108
|
+
"@playwright/test": "^1.64.1",
|
|
107
109
|
"@types/react": "^19.2.17",
|
|
108
110
|
"esbuild": "^0.28.1",
|
|
109
111
|
"react": "^19.2.8",
|
package/src/base.css
CHANGED
|
@@ -35,9 +35,6 @@ a { color: var(--color-primary-strong); }
|
|
|
35
35
|
* framework with its preflight OFF (the recommended pairing), a semantic <ul>/<ol> keeps native
|
|
36
36
|
* bullets + a 40px indent; add this class (or a Freeday list component) to normalise it. */
|
|
37
37
|
.fdy-list-reset { list-style: none; margin: 0; padding: 0; }
|
|
38
|
-
@media (prefers-reduced-motion: reduce) {
|
|
39
|
-
*, *::before, *::after { animation-duration: .001ms !important; transition-duration: .001ms !important; }
|
|
40
|
-
}
|
|
41
38
|
|
|
42
39
|
/* ===========================================================================
|
|
43
40
|
* Reduce Motion: SETIAP transisi dinetralkan, bukan daftar yang dipelihara tangan.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/* Freeday. Avatar */
|
|
2
|
-
.fdy-avatar{display:inline-flex;align-items:center;justify-content:center;flex:none;width:2.5rem;height:2.5rem;border-radius:var(--radius-full);background:var(--color-primary-soft);color:var(--color-primary-strong);font-family:var(--font-body);font-weight:var(--weight-semibold);font-size:var(--text-sm);line-height:1;overflow:hidden;user-select:none;}
|
|
2
|
+
.fdy-avatar{display:inline-flex;align-items:center;justify-content:center;flex:none;width:2.5rem;height:2.5rem;border-radius:var(--radius-full);background:var(--color-primary-soft);color:var(--color-primary-strong);font-family:var(--font-body);font-weight:var(--weight-semibold);font-size:var(--text-sm);line-height:1;overflow:hidden;-webkit-user-select:none;user-select:none;}
|
|
3
3
|
.fdy-avatar img{width:100%;height:100%;object-fit:cover;}
|
|
4
4
|
/* --xs exists for an avatar INSIDE a control: `.fdy-btn--sm` is exactly 2rem tall, which is also
|
|
5
5
|
`--sm`'s size, so a small avatar in a small button fills it edge to edge and the ghost border
|
|
@@ -6,4 +6,4 @@
|
|
|
6
6
|
.fdy-breadcrumb__link:hover{color:var(--color-primary-strong);text-decoration:underline;}
|
|
7
7
|
.fdy-breadcrumb__link:focus-visible{outline:none;box-shadow:0 0 0 3px rgba(var(--color-primary-rgb),.26);}
|
|
8
8
|
.fdy-breadcrumb__item[aria-current="page"]{color:var(--color-text);font-weight:var(--weight-medium);}
|
|
9
|
-
.fdy-breadcrumb__sep{color:var(--color-text-subtle);user-select:none;}
|
|
9
|
+
.fdy-breadcrumb__sep{color:var(--color-text-subtle);-webkit-user-select:none;user-select:none;}
|
package/src/components/cfl.css
CHANGED
|
@@ -23,7 +23,13 @@
|
|
|
23
23
|
* size, which is what made `.fdy-stats--inline` collapse to three zero tracks in 3.1.0. This box
|
|
24
24
|
* takes its width from the dialog (`min(46rem, 100vw - …)`, an explicit width) and already scrolls
|
|
25
25
|
* its own content, so it never sized to the table to begin with. */
|
|
26
|
-
.fdy-cfl__results{
|
|
26
|
+
.fdy-cfl__results{overflow:auto;max-height:min(24rem,50vh);}
|
|
27
|
+
/* Fenced the way composition.css:62 fences its own, so the declaration states the condition it
|
|
28
|
+
needs instead of relying on a browser to drop it. Safari 15.4 to 15.8 is inside the floor the
|
|
29
|
+
README states and has no container queries at all. */
|
|
30
|
+
@supports (container-type:inline-size){
|
|
31
|
+
.fdy-cfl__results{container:fdy-cfl / inline-size;}
|
|
32
|
+
}
|
|
27
33
|
.fdy-cfl__results .fdy-table th{position:sticky;top:0;z-index:1;}
|
|
28
34
|
|
|
29
35
|
.fdy-cfl__row{cursor:pointer;}
|
|
@@ -65,28 +71,69 @@
|
|
|
65
71
|
*
|
|
66
72
|
* Column headers ARE a real loss here, and a deliberate one: `<thead>` is hidden, because a header
|
|
67
73
|
* row that costs a third of the width buys nothing when each row is labelled by its own title. */
|
|
68
|
-
@
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
74
|
+
@supports (container-type:inline-size){
|
|
75
|
+
@container fdy-cfl (max-width: 30rem){
|
|
76
|
+
.fdy-cfl__results .fdy-table,
|
|
77
|
+
.fdy-cfl__results .fdy-table tbody{display:block;width:100%;}
|
|
78
|
+
.fdy-cfl__results .fdy-table thead{display:none;}
|
|
79
|
+
.fdy-cfl__row{display:flex;flex-wrap:wrap;align-items:baseline;column-gap:var(--space-2);padding:var(--space-3) var(--space-4);border-bottom:var(--bw) solid var(--color-border-muted);}
|
|
80
|
+
.fdy-cfl__results .fdy-table tbody tr:last-child{border-bottom:0;}
|
|
81
|
+
.fdy-cfl__row > td{display:block;padding:0;border:0;}
|
|
82
|
+
/* The title takes the whole first line, which is what pushes every remaining cell onto the second
|
|
83
|
+
one — no selector has to know how many columns there are, or which of them is last. */
|
|
84
|
+
.fdy-cfl__row > td:first-child:not(.fdy-cfl__check),
|
|
85
|
+
.fdy-cfl__row > .fdy-cfl__check + td{font-weight:var(--weight-semibold);color:var(--color-text);}
|
|
86
|
+
.fdy-cfl__row > td:first-child:not(.fdy-cfl__check){flex:0 0 100%;}
|
|
87
|
+
/* Multi-select: the checkbox shares line one with the title, so the title claims the rest of it. */
|
|
88
|
+
.fdy-cfl__row > .fdy-cfl__check + td{flex:1 0 calc(100% - var(--space-6));}
|
|
89
|
+
.fdy-cfl__row > td:first-child:not(.fdy-cfl__check) ~ td,
|
|
90
|
+
.fdy-cfl__row > .fdy-cfl__check + td ~ td{font-size:var(--text-xs);color:var(--color-text-muted);}
|
|
91
|
+
.fdy-cfl__row > td:first-child:not(.fdy-cfl__check) ~ td:empty,
|
|
92
|
+
.fdy-cfl__row > .fdy-cfl__check + td ~ td:empty{display:none;}
|
|
93
|
+
.fdy-cfl__row > td:first-child:not(.fdy-cfl__check) ~ td::before,
|
|
94
|
+
.fdy-cfl__row > .fdy-cfl__check + td ~ td::before{content:"·";margin-right:var(--space-2);color:var(--color-text-subtle);}
|
|
95
|
+
.fdy-cfl__row > td:first-child:not(.fdy-cfl__check) + td::before,
|
|
96
|
+
.fdy-cfl__row > .fdy-cfl__check + td + td::before{content:none;}
|
|
97
|
+
/* The checkbox keeps its own line position beside the title rather than above it. */
|
|
98
|
+
.fdy-cfl__row > .fdy-cfl__check{flex:none;width:auto;align-self:center;}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/* The same block for a browser that has no container queries, which is every Safari from 15.4 to
|
|
103
|
+
* 15.8 and inside the floor the README states. There the @supports above is false, the stacked
|
|
104
|
+
* layout never applied, and a 372px dialog kept a three-column master-data table that scrolls on
|
|
105
|
+
* both axes.
|
|
106
|
+
*
|
|
107
|
+
* The condition is a VIEWPORT width, the only width this path can read. 32rem is derived from the
|
|
108
|
+
* dialog rather than picked: the dialog is min(46rem, 100vw - var(--space-8)) with --space-8 at
|
|
109
|
+
* 2rem, and the results box takes that width, so it sits at or under 30rem exactly when the
|
|
110
|
+
* viewport sits at or under 32rem. What a media query cannot answer is the case the container
|
|
111
|
+
* query exists for, a narrow dialog inside a wide viewport, which is a docked panel on a desktop;
|
|
112
|
+
* on those browsers that one case keeps the scrolling table it has always had.
|
|
113
|
+
*
|
|
114
|
+
* The body is a copy of the body above, because CSS has no way to share one declaration block
|
|
115
|
+
* between two different conditions. test/baseline.test.mjs compares the two, so an edit that
|
|
116
|
+
* reaches one of them and misses the other fails there. */
|
|
117
|
+
@supports not (container-type:inline-size){
|
|
118
|
+
@media (max-width:32rem){
|
|
119
|
+
.fdy-cfl__results .fdy-table,
|
|
120
|
+
.fdy-cfl__results .fdy-table tbody{display:block;width:100%;}
|
|
121
|
+
.fdy-cfl__results .fdy-table thead{display:none;}
|
|
122
|
+
.fdy-cfl__row{display:flex;flex-wrap:wrap;align-items:baseline;column-gap:var(--space-2);padding:var(--space-3) var(--space-4);border-bottom:var(--bw) solid var(--color-border-muted);}
|
|
123
|
+
.fdy-cfl__results .fdy-table tbody tr:last-child{border-bottom:0;}
|
|
124
|
+
.fdy-cfl__row > td{display:block;padding:0;border:0;}
|
|
125
|
+
.fdy-cfl__row > td:first-child:not(.fdy-cfl__check),
|
|
126
|
+
.fdy-cfl__row > .fdy-cfl__check + td{font-weight:var(--weight-semibold);color:var(--color-text);}
|
|
127
|
+
.fdy-cfl__row > td:first-child:not(.fdy-cfl__check){flex:0 0 100%;}
|
|
128
|
+
.fdy-cfl__row > .fdy-cfl__check + td{flex:1 0 calc(100% - var(--space-6));}
|
|
129
|
+
.fdy-cfl__row > td:first-child:not(.fdy-cfl__check) ~ td,
|
|
130
|
+
.fdy-cfl__row > .fdy-cfl__check + td ~ td{font-size:var(--text-xs);color:var(--color-text-muted);}
|
|
131
|
+
.fdy-cfl__row > td:first-child:not(.fdy-cfl__check) ~ td:empty,
|
|
132
|
+
.fdy-cfl__row > .fdy-cfl__check + td ~ td:empty{display:none;}
|
|
133
|
+
.fdy-cfl__row > td:first-child:not(.fdy-cfl__check) ~ td::before,
|
|
134
|
+
.fdy-cfl__row > .fdy-cfl__check + td ~ td::before{content:"·";margin-right:var(--space-2);color:var(--color-text-subtle);}
|
|
135
|
+
.fdy-cfl__row > td:first-child:not(.fdy-cfl__check) + td::before,
|
|
136
|
+
.fdy-cfl__row > .fdy-cfl__check + td + td::before{content:none;}
|
|
137
|
+
.fdy-cfl__row > .fdy-cfl__check{flex:none;width:auto;align-self:center;}
|
|
138
|
+
}
|
|
92
139
|
}
|