@cahyo-dimas/freeday 3.1.0 → 3.3.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 +151 -0
- package/COMPONENTS.md +68 -7
- package/README.id.md +1 -1
- package/README.md +1 -1
- package/USAGE.md +10 -0
- package/adapters/blazor/FdyCfl.razor +24 -18
- package/adapters/blazor/FdyCfl.razor.cs +13 -2
- package/adapters/blazor/FdyModal.razor.cs +1 -1
- package/adapters/react/components/FdyCfl.tsx +79 -44
- package/adapters/react/components/FdyModal.tsx +2 -1
- package/adapters/react/index.d.ts +1 -1
- package/adapters/vue/components/FdyCfl.vue +56 -40
- package/adapters/vue/components/FdyModal.vue +4 -1
- package/dist/freeday.bundle.css +106 -10
- package/dist/freeday.css +104 -8
- package/dist/freeday.tokens.css +2 -2
- package/docs/agent-onboarding.md +6 -0
- package/docs/getting-started.md +1 -1
- package/package.json +2 -2
- package/src/components/app-shell.css +10 -3
- package/src/components/cfl.css +66 -2
- package/src/components/input.css +10 -0
- package/src/components/tabs.css +18 -3
- package/tokens/tokens.json +1 -1
package/src/components/cfl.css
CHANGED
|
@@ -6,10 +6,26 @@
|
|
|
6
6
|
|
|
7
7
|
/* Search bar, single leading-icon field; Enter/typing filters the results. */
|
|
8
8
|
.fdy-cfl__search{flex:none;padding:var(--space-4) var(--space-5);border-bottom:var(--bw) solid var(--color-border-muted);}
|
|
9
|
+
/* The search group spans the bar. Four files wrote this as `style="max-width:none"` — both typed
|
|
10
|
+
adapters and both docs examples — which is the same missing vocabulary as #055 §1, one class over. */
|
|
11
|
+
.fdy-cfl__search .fdy-input-group{max-width:none;}
|
|
9
12
|
|
|
10
|
-
/*
|
|
11
|
-
|
|
13
|
+
/* Field-less host (#054). With `dialogOnly` the typed wrappers render the dialog and no field, for a
|
|
14
|
+
caller whose trigger is its own — a chip, a table cell, a menu item — which is what the raw path
|
|
15
|
+
has always had in `[data-fdy-cfl-open]`. `display:contents` so the host generates no box at all:
|
|
16
|
+
a zero-size div would still be a flex item or a grid cell in whatever laid the trigger out. */
|
|
17
|
+
.fdy-cfl__host{display:contents;}
|
|
18
|
+
|
|
19
|
+
/* Results, dense rows, sticky header, its own scroll region.
|
|
20
|
+
*
|
|
21
|
+
* `container-type: inline-size` makes this box the query container for the stacked layout below.
|
|
22
|
+
* Safe here and nowhere near free in general: a size container stops contributing intrinsic inline
|
|
23
|
+
* size, which is what made `.fdy-stats--inline` collapse to three zero tracks in 3.1.0. This box
|
|
24
|
+
* takes its width from the dialog (`min(46rem, 100vw - …)`, an explicit width) and already scrolls
|
|
25
|
+
* its own content, so it never sized to the table to begin with. */
|
|
26
|
+
.fdy-cfl__results{container:fdy-cfl / inline-size;overflow:auto;max-height:min(24rem,50vh);}
|
|
12
27
|
.fdy-cfl__results .fdy-table th{position:sticky;top:0;z-index:1;}
|
|
28
|
+
|
|
13
29
|
.fdy-cfl__row{cursor:pointer;}
|
|
14
30
|
.fdy-cfl__row:hover{background:var(--color-surface-2);}
|
|
15
31
|
.fdy-cfl__row:focus-visible{outline:none;background:var(--color-primary-soft);box-shadow:inset 2px 0 0 var(--color-primary);}
|
|
@@ -26,3 +42,51 @@
|
|
|
26
42
|
.fdy-modal--cfl .fdy-modal__footer{justify-content:space-between;}
|
|
27
43
|
.fdy-cfl__count{font-size:var(--text-sm);color:var(--color-text-muted);}
|
|
28
44
|
.fdy-cfl__actions{display:flex;gap:var(--space-2);}
|
|
45
|
+
|
|
46
|
+
/* Narrow: the same rows as list items, not table cells (#053).
|
|
47
|
+
*
|
|
48
|
+
* A 420px add-on panel gives this dialog ~372px. A three- or four-column master-data table in that
|
|
49
|
+
* space either squeezes every column below legibility or scrolls on both axes, in a dialog whose
|
|
50
|
+
* whole job is "search, look, click one". So the first cell becomes the title and the rest become
|
|
51
|
+
* one detail line under it — the shape a picker takes when it is narrow.
|
|
52
|
+
*
|
|
53
|
+
* A CONTAINER query, not a media query: the dialog is not the viewport. The same component is wide
|
|
54
|
+
* on a desktop page and narrow inside a docked panel, and only the container knows which.
|
|
55
|
+
*
|
|
56
|
+
* No ARIA roles come with this, and that is a MEASURED decision rather than an omission. The
|
|
57
|
+
* received wisdom from the responsive-table era is that `display:block` on a table box drops its
|
|
58
|
+
* implicit role; explicit `role="table"/"row"/"cell"` were written into all four stacks here on
|
|
59
|
+
* that belief and then taken out again, because Chrome's own accessibility tree says otherwise:
|
|
60
|
+
* with the rows at `display:flex`, stripping every `role` attribute leaves
|
|
61
|
+
* `table → row → cell` intact (Chromium 133; only `rowgroup`, which associates nothing, is lost).
|
|
62
|
+
* Redundant ARIA is what the kit's own rule calls worse than none, so the guard asserts the
|
|
63
|
+
* OUTCOME — that a stacked row is still a row in the a11y tree — and stays silent about how.
|
|
64
|
+
* `browser/cfl-narrow.mjs` is where a future engine that does dissolve them shows up as red.
|
|
65
|
+
*
|
|
66
|
+
* Column headers ARE a real loss here, and a deliberate one: `<thead>` is hidden, because a header
|
|
67
|
+
* row that costs a third of the width buys nothing when each row is labelled by its own title. */
|
|
68
|
+
@container fdy-cfl (max-width: 30rem){
|
|
69
|
+
.fdy-cfl__results .fdy-table,
|
|
70
|
+
.fdy-cfl__results .fdy-table tbody{display:block;width:100%;}
|
|
71
|
+
.fdy-cfl__results .fdy-table thead{display:none;}
|
|
72
|
+
.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);}
|
|
73
|
+
.fdy-cfl__results .fdy-table tbody tr:last-child{border-bottom:0;}
|
|
74
|
+
.fdy-cfl__row > td{display:block;padding:0;border:0;}
|
|
75
|
+
/* The title takes the whole first line, which is what pushes every remaining cell onto the second
|
|
76
|
+
one — no selector has to know how many columns there are, or which of them is last. */
|
|
77
|
+
.fdy-cfl__row > td:first-child:not(.fdy-cfl__check),
|
|
78
|
+
.fdy-cfl__row > .fdy-cfl__check + td{font-weight:var(--weight-semibold);color:var(--color-text);}
|
|
79
|
+
.fdy-cfl__row > td:first-child:not(.fdy-cfl__check){flex:0 0 100%;}
|
|
80
|
+
/* Multi-select: the checkbox shares line one with the title, so the title claims the rest of it. */
|
|
81
|
+
.fdy-cfl__row > .fdy-cfl__check + td{flex:1 0 calc(100% - var(--space-6));}
|
|
82
|
+
.fdy-cfl__row > td:first-child:not(.fdy-cfl__check) ~ td,
|
|
83
|
+
.fdy-cfl__row > .fdy-cfl__check + td ~ td{font-size:var(--text-xs);color:var(--color-text-muted);}
|
|
84
|
+
.fdy-cfl__row > td:first-child:not(.fdy-cfl__check) ~ td:empty,
|
|
85
|
+
.fdy-cfl__row > .fdy-cfl__check + td ~ td:empty{display:none;}
|
|
86
|
+
.fdy-cfl__row > td:first-child:not(.fdy-cfl__check) ~ td::before,
|
|
87
|
+
.fdy-cfl__row > .fdy-cfl__check + td ~ td::before{content:"·";margin-right:var(--space-2);color:var(--color-text-subtle);}
|
|
88
|
+
.fdy-cfl__row > td:first-child:not(.fdy-cfl__check) + td::before,
|
|
89
|
+
.fdy-cfl__row > .fdy-cfl__check + td + td::before{content:none;}
|
|
90
|
+
/* The checkbox keeps its own line position beside the title rather than above it. */
|
|
91
|
+
.fdy-cfl__row > .fdy-cfl__check{flex:none;width:auto;align-self:center;}
|
|
92
|
+
}
|
package/src/components/input.css
CHANGED
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
/* Freeday. Field & Input */
|
|
2
2
|
.fdy-field{display:flex;flex-direction:column;gap:var(--space-2);max-width:22rem;}
|
|
3
|
+
/* A field marked --full fills whatever contains it (#055 §1). The cap above is for a field standing
|
|
4
|
+
on its own in a row — a filter bar, a toolbar — and it is right there. But every real form is a
|
|
5
|
+
single-column flex stack (a settings pane, a login card, a dialog at 420px), and the only release
|
|
6
|
+
the kit shipped was `.fdy-form-grid > .fdy-field`, which a flex column can never reach:
|
|
7
|
+
.fdy-form-grid is `repeat(auto-fit,minmax(14rem,1fr))`, which pairs fields up the moment there is
|
|
8
|
+
room. So a stack had no vocabulary at all and said it on the container instead — 23 times across
|
|
9
|
+
two consoles, and four times in this kit's OWN reference page as `style="max-width:none"`.
|
|
10
|
+
Inside .fdy-form-grid this changes nothing (that rule already says it); outside one the modifier
|
|
11
|
+
finally means what its name says, and the grid keeps `grid-column` as its own concern. */
|
|
12
|
+
.fdy-field--full{max-width:none;}
|
|
3
13
|
/* Inside a labelled field, a control fills the field (#051). The 22rem cap those controls carry is
|
|
4
14
|
for one standing on its own, with no field to take a width from; #017 already released the date
|
|
5
15
|
and time pickers here for exactly this reason, and its comment claims a picker then fills its
|
package/src/components/tabs.css
CHANGED
|
@@ -1,7 +1,22 @@
|
|
|
1
1
|
/* Freeday. Tabs (WAI-ARIA APG) */
|
|
2
|
-
/* position:relative, containing block for out-of-flow content in the tabs (see base.css).
|
|
3
|
-
|
|
4
|
-
|
|
2
|
+
/* position:relative, containing block for out-of-flow content in the tabs (see base.css).
|
|
3
|
+
*
|
|
4
|
+
* The strip's own line is an INSET SHADOW, not a border, and the tab carries no negative margin
|
|
5
|
+
* (#052). The pair those two replace — `border-bottom` here plus `margin-bottom:-1px` on the tab,
|
|
6
|
+
* to lift the active tab's 2px underline onto the strip's 1px line so the two read as one — was
|
|
7
|
+
* broken by the `overflow-x:auto` beside it, in two ways at once:
|
|
8
|
+
* 1. CSS Overflow §3 gives no way to scroll one axis alone: `overflow-y` computes from `visible`
|
|
9
|
+
* to `auto` because the other axis is not visible, so the 1px the tab hangs below the content
|
|
10
|
+
* box became a real scrollport. Measured 47 client / 48 scroll, `scrollTop` settling at 1 —
|
|
11
|
+
* invisible in a screenshot, and a trackpad gesture over the strip is eaten by it.
|
|
12
|
+
* 2. A scroll container clips its descendants to the padding box, so the pixel the negative
|
|
13
|
+
* margin pushed out was clipped away and the strip's own line painted in its place: the
|
|
14
|
+
* active underline rendered ONE pixel of primary, never the two it asks for.
|
|
15
|
+
* An inset shadow paints on the box, not on the scrolled content, so the line stays put while the
|
|
16
|
+
* tabs scroll sideways, and the tab's own border-bottom paints over it — same look, no overflow.
|
|
17
|
+
* To hide the line, override `box-shadow`, not `border-bottom` (guarded in browser/tabs-strip.mjs). */
|
|
18
|
+
.fdy-tabs__list{position:relative;display:flex;gap:var(--space-1);box-shadow:inset 0 calc(var(--bw) * -1) 0 var(--color-border);overflow-x:auto;}
|
|
19
|
+
.fdy-tabs__tab{appearance:none;border:0;background:transparent;cursor:pointer;white-space:nowrap;font-family:var(--font-body);font-size:var(--text-sm);font-weight:var(--weight-medium);color:var(--color-text-muted);padding:var(--space-3) var(--space-4);border-bottom:2px solid transparent;transition:color var(--dur-fast) var(--ease-standard),border-color var(--dur-fast) var(--ease-standard);}
|
|
5
20
|
.fdy-tabs__tab:hover{color:var(--color-text);}
|
|
6
21
|
.fdy-tabs__tab:disabled,.fdy-tabs__tab[aria-disabled="true"]{opacity:.5;cursor:not-allowed;color:var(--color-text-muted);}
|
|
7
22
|
.fdy-tabs__tab:disabled:hover,.fdy-tabs__tab[aria-disabled="true"]:hover{color:var(--color-text-muted);}
|
package/tokens/tokens.json
CHANGED
|
@@ -122,7 +122,7 @@
|
|
|
122
122
|
|
|
123
123
|
"text": { "$value": "{slate.900}", "$dark": "{slate.100}" },
|
|
124
124
|
"text-muted": { "$value": "{slate.600}", "$dark": "{slate.400}" },
|
|
125
|
-
"text-subtle": { "$value": "{slate.500}", "$dark": "{slate.
|
|
125
|
+
"text-subtle": { "$comment": "The faintest ink, and the ONLY text tier whose dark value is not the light one's mirror (#053). Light slate-500 on white is 4.69:1 and clears AA on its own; the same primitive on the dark surface is 4.02:1, and the tier is exactly what a placeholder uses — the one line telling an operator what an empty field wants. Dark is slate-450 for that reason: 4.88:1 on --color-surface, which is what every .fdy-input paints itself, so the placeholder clears AA where placeholders actually sit. It is still NOT a body-text tier on the darker surfaces (3.66:1 on surface-3); reaching AA there needs slate-400, which is --color-text-muted, and a subtle that equals muted is not a tier. test/contrast.test.mjs asserts both halves of that split.", "$value": "{slate.500}", "$dark": "{slate.450}" },
|
|
126
126
|
"on-brand": { "$value": "{slate.0}", "$dark": "{slate.0}" },
|
|
127
127
|
|
|
128
128
|
"border": { "$value": "{slate.200}", "$dark": "{slate.800}" },
|