@usableapp/cardds 0.7.107 → 0.7.108
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 +24 -0
- package/css/card.css +3 -0
- package/css/choice.css +26 -1
- package/css/journey.css +6 -2
- package/css/lists.css +3 -0
- package/css/palette.css +1 -1
- package/dist/cardds.css +39 -4
- package/dist/cards/CardParts.d.ts +2 -1
- package/dist/cards/CardParts.js +2 -1
- package/dist/catalog.json +1 -1
- package/dist/choice/Calendar.d.ts +12 -3
- package/dist/choice/Calendar.js +17 -5
- package/dist/choice/CalendarWeeks.d.ts +10 -2
- package/dist/choice/CalendarWeeks.js +18 -4
- package/dist/choice/HourGrid.d.ts +36 -0
- package/dist/choice/HourGrid.js +21 -0
- package/dist/choice/calendarDay.d.ts +7 -2
- package/dist/choice/calendarDay.js +6 -3
- package/dist/choice/span.d.ts +34 -0
- package/dist/choice/span.js +80 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1 -0
- package/dist/journey/JourneyBadge.d.ts +2 -1
- package/dist/lists/Kv.d.ts +4 -2
- package/dist/lists/Kv.js +3 -3
- package/docs/reference.md +1 -1
- package/package.json +1 -1
- package/scripts/codemod-parts.mjs +107 -28
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,30 @@
|
|
|
2
2
|
|
|
3
3
|
> For: a project that consumes `@usableapp/cardds` and its AI — what changed between versions, written as before → after, so a screen can be brought up to date without reading the source. Newest first. A consumer never edits cardds; if something here leaves you without a way to do what you did before, report the gap. Each release section after 0.7.97 carries one `Components:` line, written by `node scripts/components-changed.mjs <previous tag>`: the components the release changed, or `all` when a file changed that any component can read (a token, the build), or `none`; check only the screens that import those.
|
|
4
4
|
|
|
5
|
+
## 0.7.108 — 2026-10-22
|
|
6
|
+
|
|
7
|
+
`KvGrid centre` (Lh 2026-10-21, the code on timebank's request card): the one number at the centre of the room it stands in, a turning card's back. A `JourneyBadge corner` on a `CardMedia` is the card's paper, its corner concentric with the media's; a theme's two badge knobs still win. From when to when (timebank, Lh 2026-10-21): the asker says which days and which hours they need, the helper answers within them.
|
|
8
|
+
|
|
9
|
+
Components: all (css/palette.css: orchard's badge rule now leaves the media corner badge out, a file any component can read; what a consumer sees change is KvGrid, KvCell, JourneyBadge, CardMedia, Card, Calendar, CalendarWeeks and HourGrid (new), and `scripts/codemod-parts.mjs`, the migration tool, under Fixed)
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
- **`KvGrid centre`: one cell at the centre of the room it stands in, a turning card's back** (Lh 2026-10-21, timebank's request card: the six-digit code the helper types, big, mono, selectable, centred in the middle band over its muted caption; the place `Stat centre` held, as `Head centre` is named). Before → after: a lone `KvCell` in a `KvGrid` on a `Card back` stood left-aligned at the top of the middle band, and the only way to centre it was a hand-written grid around a `Text level="stat"` (cardds's own story did that) → `<KvGrid centre>` is as tall as its holder (`min-height: 100%`, not `height`: in a plain card, a grid of auto rows, a percent height resolved short and the cell overflowed it) and stands its cells at the middle of it, each value and caption centred (`.kv-grid--centre`, `align-content` · `text-align` · `justify-items`); on a plain card, which has no height of its own, the grid hugs its cell and only centres across. The value is the consumer's: a code is `<Text level="stat" mono selectable as="span">490734</Text>`. No new knob (`--kv-cell-gap` sets the space between the value and the caption); `.card__middle` untouched, no rule in lists.css writes another piece's properties. A consumer writes `<KvGrid centre>` in a `Card back` and nothing else changes. Stories: `Kv/KvGridCentre` (new); `Card/TurnsCode` and `Card/TurnsLongTitle` draw their back with it in place of an inline-style grid (inline `style` left in stories: 37, each a knob, a story-only layout, a `display: contents` remount wrapper, the palette demo's surface or the type-scale table; the QR back `TURN_BACK` keeps its three). Style snapshot: only those two stories moved (two elements more on each back) and the new one; the other 498 identical. Tests: tests/kv-grid-centre.spec.js (2); 537 → 538 classes (`.kv-grid--centre`), 719 knobs unchanged. The catalog answers "one big code number centred in the middle of a card back" with KvGrid, then KvCell.
|
|
13
|
+
|
|
14
|
+
| before | after |
|
|
15
|
+
| --- | --- |
|
|
16
|
+
| `back={<div style={{ display: 'grid', justifyItems: 'center', alignContent: 'center', height: '100%' }}><Text level="stat" mono>490734</Text><Text level="caption">…</Text></div>}` | `back={<KvGrid centre><KvCell value={<Text level="stat" mono selectable as="span">490734</Text>} label="…" /></KvGrid>}` |
|
|
17
|
+
- **A run of days on `Calendar` and `CalendarWeeks`: `span` + `onSpanChange`, or `defaultSpan`.** Before → after: a calendar held ONE day (`selected`), so a request for several days was one calendar per day or a field typed by hand → `span={[first, last]}` covers a run: one drag across the days covers them (the first cell under the finger is one end, the last the other, whichever way it went), or a tap on the first day and a tap on the last; the whole run is ONE highlight, the same colour throughout as a finger dragged over words (Lh 2026-10-21: no picked first or last day), a pill that bridges the grid's gaps; a covered cell carries `aria-pressed`. The app is asked once, when the finger lifts or the second tap closes the run; a third tap starts over. A disabled day is never covered: the run stops before it, so the helper's answer stays inside the asked days (the app marks the asked days `soft` and disables the rest; `Calendar/SpanWithin`). On `Calendar` the span is `[day, day]` (numbers, as `selected`); on `CalendarWeeks` it is `[key, key]` and a drag covers along a row while a finger moving up or down still scrolls the box (`touch-action: pan-y`); two taps cover across the weeks. A key on a cell is a tap. `selected` is not read while `span` is given. Knob `--calendar-span-bg` (the highlight, 25% accent by default: the helper's run must read over the asked days' 12% marks). Gallery `Calendar/Span` · `Calendar/SpanWithin` · `CalendarWeeks/Span`.
|
|
18
|
+
- **`HourGrid`: the hours of a day from when to when.** Before → after: an hour was one `ChipPick` in a `ChipGrid` (one slot, no span) or a `Picker` (one value) → `<HourGrid hours={…} label="น." span={[from, to]} onSpanChange={…} />` lays the hours out in Calendar's own 44px round cells, `--hour-grid-cols` to a row (6), a label over them, and covers a run by the same drag or two taps; `selected` + `onSelect` picks one hour instead. It knows no clock: the app builds `hours: { key, num, disabled?, mark?: 'soft' | 'strong' }[]`, as `CalendarWeeks` builds its days. On a sheet, never in a Card. Gallery `HourGrid/Default` · `Within` · `OneHour` · `DaysThenHours` (the when step of an ask: the weeks, then the hours).
|
|
19
|
+
- **A request card's date and time say the span.** Nothing new to import: the card's date box (`JourneyBadge stretch`) takes the run (`label="พฤ–อา" value="18–21" sub="มิ.ย."`) and the clock chip its hours (`09:00–12:00`), the app's words as before. New knob `--tile-badge-stretch-w` (the stretch badge's width, `calc(var(--fs-lg) * 3.25)` as before): two days need more than one, so the app sets it on that badge; a stretch badge's lines no longer break at a dash. Gallery `Card/DateSpanHead` shows the request card so headed.
|
|
20
|
+
- **One mechanic, three holders.** The span is written once (`src/choice/span.ts`, `useSpan`): `Calendar`, `CalendarWeeks` and `HourGrid` number their cells and spread its handlers; the cell is still `calendarDay` (`.calendar__day`), so every `--calendar-day-*` knob reaches the hours too. The grid's columns are now `--_cols` (7 unless the holder says otherwise). `tests/gallery-span.spec.js` holds the drag, the two taps, the clip at a disabled cell, the unbroken highlight and the keyboard.
|
|
21
|
+
|
|
22
|
+
### Changed
|
|
23
|
+
- **A badge on the corner of a picture is the paper, its corner concentric with the media's** (ruled Lh 2026-10-21, chosen from three screenshots side by side: the distance on a request card is information, and a highlight-filled badge reads as a control). Before → after: a `JourneyBadge corner` on a `CardMedia` took the badge's own look, the dark `--card-3-bg` fill with the badge corner (`--r-badge`, 13 at 375), and under orchard the highlight yellow; the stories that wanted the paper set three properties by hand in `style` (`--tile-badge-bg`, `--dark`, `--tile-badge-radius`), which an app on the package could not → `.card__media > .tile-badge--corner` (journey.css) is `--card-1-bg` with the paper's ink (`--dark: var(--card-1-dark)`) and its corner is `--r-media` less the badge's inset `--sp-3` (8.8 at 375), so the two arcs share a centre; orchard's highlight rule leaves this badge out. A theme's `--tile-badge-bg` and `--tile-badge-radius` still win (read first, as before). Nothing changes for a consumer unless it set those knobs by hand on such a badge, which it may now drop. A badge in a head (`Tile · JourneyBadgeGate`, the date on `Card · Turns`) is unchanged: the head's concentric rule and orchard's highlight hold there. Stories that moved (the style snapshot; only the badge's background, its ink and the ink's border colour, and its radius): `Card · Turns`, `TurnsTwoLineTitle`, `TurnsCode`, `TurnsControlled`, `TurnsRoundFoot` (the radius only, 21.6 → 8.8: they had the paper by hand, with the card's corner less its padding; the inline style is gone), `CardMedia · CardMediaRated`, `Placeholder · Md`, `Mosaic · PhotoCard`, `Tile · JourneyBadgeCorner` (dark fill, white ink, 13 → white paper, onlight ink, 8.8). `Card · PaperBands` and `TurnsLongTitle` have no corner badge and did not move. Inline `style` objects left in the stories: 37 (was 38). Test: `tests/gallery-inline.spec.js` reads the badge's computed background and radius against the resolved tokens, on orchard too, and the head badge's highlight.
|
|
24
|
+
|
|
25
|
+
### Fixed
|
|
26
|
+
- **On a dark tone's two-tone card the middle's secondary words take the full ink** (the ink gate, 2026-10-22, found by the caption under the code on `Card back`). Before → after: a `Card paper="bands"` on tone 3 or 5 lightens its middle to a mid grey (#adadad, #bbbbbb in wireframe) and declared the paper's side for it, so a muted word there (`Text muted`, a `KvCell` label, a `Words meta`) read at 3.2:1 and 3.8:1, under the 4.5:1 words need → the middle of a tone 3 or 5 bands card declares `--card-muted` as `--card-ink`, so its secondary words are the full ink there; tones 1, 2 and 4 are unchanged, and a theme's `--card-middle-bg` is read as before. Components: Card. The ink gate (tests/ink.spec.js) passes on every palette; no story as written moved.
|
|
27
|
+
- **`npx cardds codemod-parts` moves a `Row`'s retired props, imports a part once, and keeps a conditional foot conditional** (timebank #372 ran 0.7.107's version and found the three). Before → after: (1) a `Row` still on the props 0.7.106 retired (`title`, `meta`, `lead`, `leadIcon`, `body`, `end`, `endValue`, `endCaption`) was left as it was, and `--check` said nothing of it → it is written in parts, in the 0.7.106 table's order (`<Row><Lead icon="gift" /><Words title meta>{body}</Words><End value caption />{end}</Row>`; `lead` and `end` stand bare, as the table says; `lg`, `done`, `as`, `htmlFor`, `href`, `more`, `open`, `defaultOpen`, `onOpenChange` stay on the Row), and `--check` names `Row title`, `Row meta`, `Row lead`, `Row leadIcon`, `Row end`, `Row body`, `Row endValue`, `Row endCaption` per line. (2) `Head`, `Words` and `Foot` were added to an `import type { … } from 'cardds'` as well as to the value import, so a file with both failed with TS2300 → a part goes to the value import only; the type import has its retired type names renamed (`CardFootProps` → `FootProps`, and every use in the file), and a file with only a type import gets a value import after it. (3) `foot={cond ? x : undefined}` became an always-drawn `<Foot>{cond ? x : undefined}</Foot>`, an empty foot when `cond` is false → `{cond ? <Foot>{x}</Foot> : null}` (also `: null`, and `cond && x` → `{cond && <Foot>{x}</Foot>}`); a plain `foot={value}` is still `<Foot>{value}</Foot>`, since the script cannot know whether `value` may be undefined. A consumer that migrated its screens with 0.7.107's version runs `npx cardds codemod-parts --check <files…>` again to find the Rows it left, then the rewrite on those files. tests/codemod-parts.spec.js, fixtures `row-`, `type-import-`, `foot-if-`.
|
|
28
|
+
|
|
5
29
|
## 0.7.107 — 2026-10-21
|
|
6
30
|
|
|
7
31
|
Every outer holds the same rows (Lh 2026-10-21): a `Card`, a `Sheet`, a stack sheet and a `Modal` are the paper and its behaviour, and inside each stand a `Head`, a `Body` and a `Foot`; a line is `Lead` · `Words` · `End`, the parts a `Row` and a `Card row` are both made of. Eleven parts and seven `Card` props are gone with no alias; `npx cardds codemod-parts <files>` moves a screen. Also: `Stat`, `StatRow`, `Delta` and `Tile stat` removed (a number is a `NumberBand` or a `KvCell`); the gallery's nav is one grouping by `src/` folder in a derived order; a scoped playwright run takes ports of its own.
|
package/css/card.css
CHANGED
|
@@ -61,6 +61,9 @@
|
|
|
61
61
|
overflow: hidden;
|
|
62
62
|
}
|
|
63
63
|
.card--bands.card--turns { background: none; overflow: visible; } /* the turning box keeps --dark: the faces' ink is computed from it */
|
|
64
|
+
/* on a dark tone (3, 5) the lightened middle is a mid grey (#adadad, #bbbbbb in wireframe) that no muted ink reads on (3.2:1 and 3.8:1;
|
|
65
|
+
the ink gate, 2026-10-22, from the caption under a code on a `Card back`): there the middle's secondary words take the full ink */
|
|
66
|
+
:is(.card--bands, .card--bands > .card__face):is(.card--3, .card--5, .card--3 > *, .card--5 > *) { --card-muted: var(--card-ink); }
|
|
64
67
|
|
|
65
68
|
/* ---- two faces: the WHOLE card turns (`Card back`, Lh 2026-10-19). The article is the turning box (.flip, base.css) and only that;
|
|
66
69
|
each face is the card's paper — head · middle · foot — and both lie in one grid cell. The head and the foot are the same on both
|
package/css/choice.css
CHANGED
|
@@ -119,7 +119,7 @@
|
|
|
119
119
|
<div class="calendar"><div class="calendar__head">…</div><div class="calendar__grid"><span class="calendar__wd">Mo</span>×7 <button class="calendar__day" style="--start: 3">1</button>…</div></div> */
|
|
120
120
|
.calendar { display: grid; gap: var(--calendar-gap, var(--sp-3)); }
|
|
121
121
|
.calendar__head { display: flex; align-items: center; justify-content: space-between; gap: var(--calendar-head-gap, var(--sp-2)); }
|
|
122
|
-
.calendar__grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: var(--calendar-grid-gap, var(--sp-1)); justify-items: center; }
|
|
122
|
+
.calendar__grid { display: grid; grid-template-columns: repeat(var(--_cols, 7), 1fr); gap: var(--calendar-grid-gap, var(--sp-1)); justify-items: center; container-type: inline-size; } /* a container: the span band below is measured in its width */
|
|
123
123
|
.calendar__wd { font: var(--calendar-wd-font, var(--type-caption)); color: var(--calendar-wd-ink, var(--card-muted)); padding-block: var(--calendar-wd-pad-y, var(--sp-2)); }
|
|
124
124
|
.calendar__day {
|
|
125
125
|
width: 100%;
|
|
@@ -140,6 +140,31 @@
|
|
|
140
140
|
.calendar__day:disabled { opacity: var(--fade-dim); }
|
|
141
141
|
.calendar__day[aria-current="date"] { text-decoration: underline; text-underline-offset: 0.2em; }
|
|
142
142
|
|
|
143
|
+
/* ---- span: a run of cells covered by one drag or two taps (Calendar, CalendarWeeks, HourGrid; src/choice/span.ts is the mechanic). The whole
|
|
144
|
+
run is ONE highlight, as a finger drags over words (Lh 2026-10-21: no picked first or last day, the same colour throughout): each covered
|
|
145
|
+
cell's own ::before is a slice of the band, a column and a gap wide between so the slices meet across the grid's gaps, the slice at an end
|
|
146
|
+
stops at its column's edge with the pill's corner; a one-cell run is a pill the column wide. The cells keep their ink. A grid that is a
|
|
147
|
+
span takes the touch (no scroll starts on it); the weeks' box keeps its vertical scroll, so there a drag covers a row and two taps cover across rows */
|
|
148
|
+
.calendar--span .calendar__grid { touch-action: none; -webkit-user-select: none; user-select: none; }
|
|
149
|
+
.calendar--weeks.calendar--span .calendar__grid { touch-action: pan-y; }
|
|
150
|
+
.calendar__grid { --_col: calc((100cqw - (var(--_cols, 7) - 1) * var(--calendar-grid-gap, var(--sp-1))) / var(--_cols, 7)); --_span-w: calc(var(--_col) + var(--calendar-grid-gap, var(--sp-1))); }
|
|
151
|
+
:is(.calendar__day--span-start, .calendar__day--span-in, .calendar__day--span-end, .calendar__day--span-one) { position: relative; isolation: isolate; }
|
|
152
|
+
.calendar__day--span-start::before, .calendar__day--span-in::before, .calendar__day--span-end::before, .calendar__day--span-one::before { /* flat, not :is(): the knob walk reads each alternative's element */
|
|
153
|
+
content: "";
|
|
154
|
+
position: absolute;
|
|
155
|
+
inset-block: 0;
|
|
156
|
+
inset-inline-start: calc(50% - var(--_span-w) / 2);
|
|
157
|
+
width: var(--_span-w);
|
|
158
|
+
z-index: var(--z-under);
|
|
159
|
+
background: var(--calendar-span-bg, color-mix(in srgb, var(--accent) 25%, transparent));
|
|
160
|
+
}
|
|
161
|
+
.calendar__day--span-start::before { inset-inline-start: calc(50% - var(--_col) / 2); width: calc(var(--_span-w) - var(--calendar-grid-gap, var(--sp-1)) / 2); border-start-start-radius: var(--r-chip); border-end-start-radius: var(--r-chip); }
|
|
162
|
+
.calendar__day--span-end::before { width: calc(var(--_span-w) - var(--calendar-grid-gap, var(--sp-1)) / 2); border-start-end-radius: var(--r-chip); border-end-end-radius: var(--r-chip); }
|
|
163
|
+
.calendar__day--span-one::before { inset-inline-start: calc(50% - var(--_col) / 2); width: var(--_col); border-radius: var(--r-chip); }
|
|
164
|
+
/* ---- hour grid: the hours of a day in Calendar's cells, `--hour-grid-cols` to a row, a label over them
|
|
165
|
+
<div class="calendar hour-grid"><span class="calendar__label">น.</span><div class="calendar__grid"><button class="calendar__day">9</button>…</div></div> */
|
|
166
|
+
.hour-grid > .calendar__grid { --_cols: var(--hour-grid-cols, 6); }
|
|
167
|
+
|
|
143
168
|
/* ---- calendar weeks: a run of week rows that scrolls week by week, `show` rows in sight; the head sticks at the top of the box
|
|
144
169
|
<div class="calendar calendar--weeks"><div class="calendar__weeks-head"><span class="calendar__label">June 2026</span><div class="calendar__grid">…wd×7</div></div>
|
|
145
170
|
<div class="calendar__grid calendar__week"><button class="calendar__day">…</button>×7</div>…</div>
|
package/css/journey.css
CHANGED
|
@@ -58,7 +58,7 @@
|
|
|
58
58
|
align-self: stretch;
|
|
59
59
|
max-block-size: calc((2 * var(--fs-caption) + var(--fs-lg)) * var(--tile-badge-line, var(--lh-badge)) + 2 * var(--sp-3));
|
|
60
60
|
container-type: size;
|
|
61
|
-
inline-size: calc(var(--fs-lg) * 3.25);
|
|
61
|
+
inline-size: var(--tile-badge-stretch-w, calc(var(--fs-lg) * 3.25)); /* a run of days ("18–21") needs more: the app sets the knob on that badge */
|
|
62
62
|
grid-template-columns: auto auto;
|
|
63
63
|
align-content: center;
|
|
64
64
|
justify-content: center;
|
|
@@ -67,7 +67,7 @@
|
|
|
67
67
|
row-gap: 0;
|
|
68
68
|
padding-block: var(--sp-3);
|
|
69
69
|
}
|
|
70
|
-
.tile-badge--stretch > * { line-height: inherit; }
|
|
70
|
+
.tile-badge--stretch > * { line-height: inherit; white-space: nowrap; } /* a value never breaks at its dash */
|
|
71
71
|
.tile-badge--stretch > :first-child { grid-column: 1 / -1; }
|
|
72
72
|
@container (min-height: 3.5rem) { /* just under the three lines' own height, the most the badge grows to */
|
|
73
73
|
.tile-badge--stretch > * { grid-column: 1 / -1; }
|
|
@@ -78,6 +78,10 @@
|
|
|
78
78
|
|
|
79
79
|
/* corner badge: pin a tile badge on media (rating, price) — .card__media is relative */
|
|
80
80
|
.tile-badge--corner { position: absolute; right: var(--sp-3); bottom: var(--sp-3); }
|
|
81
|
+
/* on a CardMedia (ruled Lh 2026-10-21, three screenshots side by side): the card's paper, its corner concentric with the media's — the media's
|
|
82
|
+
corner less the inset above. Not the theme's highlight: the distance on a request card is information, and a highlight fill reads as a
|
|
83
|
+
control. Both knobs still win (palette.css leaves this badge out of orchard's highlight rule for the same reason) */
|
|
84
|
+
.card__media > .tile-badge--corner { --_badge-radius: calc(var(--r-media) - var(--sp-3)); background: var(--tile-badge-bg, var(--card-1-bg)); --dark: var(--card-1-dark); }
|
|
81
85
|
|
|
82
86
|
/* ---- note row: icon + caption (transit hints, fine print) ---- */
|
|
83
87
|
.note-row {
|
package/css/lists.css
CHANGED
|
@@ -75,6 +75,9 @@
|
|
|
75
75
|
<div class="kv-grid"><div class="kv-cell"><svg class="icon"/><span class="kv-cell__val">15.6 kg</span><span class="kv-cell__key">Weight</span></div>…</div> */
|
|
76
76
|
.kv-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(var(--tile-min), 100%), 1fr)); gap: var(--kv-grid-gap, var(--sp-4)); }
|
|
77
77
|
.kv-grid > .kv-cell + .kv-cell { border-left: var(--border-w) solid var(--hairline); padding-left: var(--sp-4); }
|
|
78
|
+
/* `centre` (Lh 2026-10-21, the code on timebank's request card, as `Stat centre` and `Head centre` were): the grid is as tall as its holder, its cells stand in the middle of it, each value and caption centred */
|
|
79
|
+
.kv-grid--centre { min-height: 100%; align-content: center; text-align: center; } /* min-height, not height: in a plain card (a grid of auto rows) a percent height resolved 8px short and the cell overflowed it; a percent min-height is nothing there, and the holder's height on a turning card's face */
|
|
80
|
+
.kv-grid--centre > .kv-cell { justify-items: center; }
|
|
78
81
|
.kv-cell { display: grid; gap: var(--kv-cell-gap, var(--sp-0)); align-content: start; min-width: 0; }
|
|
79
82
|
.kv-cell > .icon { --icon-margin: 0 0 var(--sp-1); }
|
|
80
83
|
.kv-cell__val { font: var(--kv-cell-val-font, var(--type-h2)); letter-spacing: var(--track-h2); font-variant-numeric: tabular-nums; }
|
package/css/palette.css
CHANGED
|
@@ -92,7 +92,7 @@
|
|
|
92
92
|
/* where the highlights land — written as the component's own rule, its knob still first, so a project's knob wins (a palette never DECLARES a
|
|
93
93
|
knob). Each fill says its side; the words on it follow */
|
|
94
94
|
[data-palette="orchard"] .badge:not(.badge--soft) { background: var(--badge-bg, var(--highlight-1)); color: var(--badge-ink, var(--ink-ondark)); }
|
|
95
|
-
[data-palette="orchard"] .tile-badge:not(.tile-badge--plain) { background: var(--tile-badge-bg, var(--highlight-2)); --dark: 0; }
|
|
95
|
+
[data-palette="orchard"] .tile-badge:not(.tile-badge--plain, .card__media > .tile-badge--corner) { background: var(--tile-badge-bg, var(--highlight-2)); --dark: 0; } /* a badge on a media stays the paper (journey.css) */
|
|
96
96
|
[data-palette="orchard"] .calendar__day--mark { background: var(--calendar-day-mark-bg, color-mix(in srgb, var(--highlight-2) 15%, transparent)); }
|
|
97
97
|
/* fields are WHITE boxes on every ground (Lh 2026-09-25): a light ground, so the words typed in them are onlight, even on the moss card */
|
|
98
98
|
[data-palette="orchard"] .field { background: var(--field-bg, #ffffff); color: var(--ink-onlight); }
|
package/dist/cardds.css
CHANGED
|
@@ -521,7 +521,7 @@
|
|
|
521
521
|
/* where the highlights land — written as the component's own rule, its knob still first, so a project's knob wins (a palette never DECLARES a
|
|
522
522
|
knob). Each fill says its side; the words on it follow */
|
|
523
523
|
[data-palette="orchard"] .badge:not(.badge--soft) { background: var(--badge-bg, var(--highlight-1)); color: var(--badge-ink, var(--ink-ondark)); }
|
|
524
|
-
[data-palette="orchard"] .tile-badge:not(.tile-badge--plain) { background: var(--tile-badge-bg, var(--highlight-2)); --dark: 0; }
|
|
524
|
+
[data-palette="orchard"] .tile-badge:not(.tile-badge--plain, .card__media > .tile-badge--corner) { background: var(--tile-badge-bg, var(--highlight-2)); --dark: 0; } /* a badge on a media stays the paper (journey.css) */
|
|
525
525
|
[data-palette="orchard"] .calendar__day--mark { background: var(--calendar-day-mark-bg, color-mix(in srgb, var(--highlight-2) 15%, transparent)); }
|
|
526
526
|
/* fields are WHITE boxes on every ground (Lh 2026-09-25): a light ground, so the words typed in them are onlight, even on the moss card */
|
|
527
527
|
[data-palette="orchard"] .field { background: var(--field-bg, #ffffff); color: var(--ink-onlight); }
|
|
@@ -984,6 +984,9 @@ button:enabled { cursor: pointer; } /* a disabled one keeps the arrow */
|
|
|
984
984
|
overflow: hidden;
|
|
985
985
|
}
|
|
986
986
|
.card--bands.card--turns { background: none; overflow: visible; } /* the turning box keeps --dark: the faces' ink is computed from it */
|
|
987
|
+
/* on a dark tone (3, 5) the lightened middle is a mid grey (#adadad, #bbbbbb in wireframe) that no muted ink reads on (3.2:1 and 3.8:1;
|
|
988
|
+
the ink gate, 2026-10-22, from the caption under a code on a `Card back`): there the middle's secondary words take the full ink */
|
|
989
|
+
:is(.card--bands, .card--bands > .card__face):is(.card--3, .card--5, .card--3 > *, .card--5 > *) { --card-muted: var(--card-ink); }
|
|
987
990
|
|
|
988
991
|
/* ---- two faces: the WHOLE card turns (`Card back`, Lh 2026-10-19). The article is the turning box (.flip, base.css) and only that;
|
|
989
992
|
each face is the card's paper — head · middle · foot — and both lie in one grid cell. The head and the foot are the same on both
|
|
@@ -2569,7 +2572,7 @@ button:enabled { cursor: pointer; } /* a disabled one keeps the arrow */
|
|
|
2569
2572
|
align-self: stretch;
|
|
2570
2573
|
max-block-size: calc((2 * var(--fs-caption) + var(--fs-lg)) * var(--tile-badge-line, var(--lh-badge)) + 2 * var(--sp-3));
|
|
2571
2574
|
container-type: size;
|
|
2572
|
-
inline-size: calc(var(--fs-lg) * 3.25);
|
|
2575
|
+
inline-size: var(--tile-badge-stretch-w, calc(var(--fs-lg) * 3.25)); /* a run of days ("18–21") needs more: the app sets the knob on that badge */
|
|
2573
2576
|
grid-template-columns: auto auto;
|
|
2574
2577
|
align-content: center;
|
|
2575
2578
|
justify-content: center;
|
|
@@ -2578,7 +2581,7 @@ button:enabled { cursor: pointer; } /* a disabled one keeps the arrow */
|
|
|
2578
2581
|
row-gap: 0;
|
|
2579
2582
|
padding-block: var(--sp-3);
|
|
2580
2583
|
}
|
|
2581
|
-
.tile-badge--stretch > * { line-height: inherit; }
|
|
2584
|
+
.tile-badge--stretch > * { line-height: inherit; white-space: nowrap; } /* a value never breaks at its dash */
|
|
2582
2585
|
.tile-badge--stretch > :first-child { grid-column: 1 / -1; }
|
|
2583
2586
|
@container (min-height: 3.5rem) { /* just under the three lines' own height, the most the badge grows to */
|
|
2584
2587
|
.tile-badge--stretch > * { grid-column: 1 / -1; }
|
|
@@ -2589,6 +2592,10 @@ button:enabled { cursor: pointer; } /* a disabled one keeps the arrow */
|
|
|
2589
2592
|
|
|
2590
2593
|
/* corner badge: pin a tile badge on media (rating, price) — .card__media is relative */
|
|
2591
2594
|
.tile-badge--corner { position: absolute; right: var(--sp-3); bottom: var(--sp-3); }
|
|
2595
|
+
/* on a CardMedia (ruled Lh 2026-10-21, three screenshots side by side): the card's paper, its corner concentric with the media's — the media's
|
|
2596
|
+
corner less the inset above. Not the theme's highlight: the distance on a request card is information, and a highlight fill reads as a
|
|
2597
|
+
control. Both knobs still win (palette.css leaves this badge out of orchard's highlight rule for the same reason) */
|
|
2598
|
+
.card__media > .tile-badge--corner { --_badge-radius: calc(var(--r-media) - var(--sp-3)); background: var(--tile-badge-bg, var(--card-1-bg)); --dark: var(--card-1-dark); }
|
|
2592
2599
|
|
|
2593
2600
|
/* ---- note row: icon + caption (transit hints, fine print) ---- */
|
|
2594
2601
|
.note-row {
|
|
@@ -3609,7 +3616,7 @@ button:enabled { cursor: pointer; } /* a disabled one keeps the arrow */
|
|
|
3609
3616
|
<div class="calendar"><div class="calendar__head">…</div><div class="calendar__grid"><span class="calendar__wd">Mo</span>×7 <button class="calendar__day" style="--start: 3">1</button>…</div></div> */
|
|
3610
3617
|
.calendar { display: grid; gap: var(--calendar-gap, var(--sp-3)); }
|
|
3611
3618
|
.calendar__head { display: flex; align-items: center; justify-content: space-between; gap: var(--calendar-head-gap, var(--sp-2)); }
|
|
3612
|
-
.calendar__grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: var(--calendar-grid-gap, var(--sp-1)); justify-items: center; }
|
|
3619
|
+
.calendar__grid { display: grid; grid-template-columns: repeat(var(--_cols, 7), 1fr); gap: var(--calendar-grid-gap, var(--sp-1)); justify-items: center; container-type: inline-size; } /* a container: the span band below is measured in its width */
|
|
3613
3620
|
.calendar__wd { font: var(--calendar-wd-font, var(--type-caption)); color: var(--calendar-wd-ink, var(--card-muted)); padding-block: var(--calendar-wd-pad-y, var(--sp-2)); }
|
|
3614
3621
|
.calendar__day {
|
|
3615
3622
|
width: 100%;
|
|
@@ -3630,6 +3637,31 @@ button:enabled { cursor: pointer; } /* a disabled one keeps the arrow */
|
|
|
3630
3637
|
.calendar__day:disabled { opacity: var(--fade-dim); }
|
|
3631
3638
|
.calendar__day[aria-current="date"] { text-decoration: underline; text-underline-offset: 0.2em; }
|
|
3632
3639
|
|
|
3640
|
+
/* ---- span: a run of cells covered by one drag or two taps (Calendar, CalendarWeeks, HourGrid; src/choice/span.ts is the mechanic). The whole
|
|
3641
|
+
run is ONE highlight, as a finger drags over words (Lh 2026-10-21: no picked first or last day, the same colour throughout): each covered
|
|
3642
|
+
cell's own ::before is a slice of the band, a column and a gap wide between so the slices meet across the grid's gaps, the slice at an end
|
|
3643
|
+
stops at its column's edge with the pill's corner; a one-cell run is a pill the column wide. The cells keep their ink. A grid that is a
|
|
3644
|
+
span takes the touch (no scroll starts on it); the weeks' box keeps its vertical scroll, so there a drag covers a row and two taps cover across rows */
|
|
3645
|
+
.calendar--span .calendar__grid { touch-action: none; -webkit-user-select: none; user-select: none; }
|
|
3646
|
+
.calendar--weeks.calendar--span .calendar__grid { touch-action: pan-y; }
|
|
3647
|
+
.calendar__grid { --_col: calc((100cqw - (var(--_cols, 7) - 1) * var(--calendar-grid-gap, var(--sp-1))) / var(--_cols, 7)); --_span-w: calc(var(--_col) + var(--calendar-grid-gap, var(--sp-1))); }
|
|
3648
|
+
:is(.calendar__day--span-start, .calendar__day--span-in, .calendar__day--span-end, .calendar__day--span-one) { position: relative; isolation: isolate; }
|
|
3649
|
+
.calendar__day--span-start::before, .calendar__day--span-in::before, .calendar__day--span-end::before, .calendar__day--span-one::before { /* flat, not :is(): the knob walk reads each alternative's element */
|
|
3650
|
+
content: "";
|
|
3651
|
+
position: absolute;
|
|
3652
|
+
inset-block: 0;
|
|
3653
|
+
inset-inline-start: calc(50% - var(--_span-w) / 2);
|
|
3654
|
+
width: var(--_span-w);
|
|
3655
|
+
z-index: var(--z-under);
|
|
3656
|
+
background: var(--calendar-span-bg, color-mix(in srgb, var(--accent) 25%, transparent));
|
|
3657
|
+
}
|
|
3658
|
+
.calendar__day--span-start::before { inset-inline-start: calc(50% - var(--_col) / 2); width: calc(var(--_span-w) - var(--calendar-grid-gap, var(--sp-1)) / 2); border-start-start-radius: var(--r-chip); border-end-start-radius: var(--r-chip); }
|
|
3659
|
+
.calendar__day--span-end::before { width: calc(var(--_span-w) - var(--calendar-grid-gap, var(--sp-1)) / 2); border-start-end-radius: var(--r-chip); border-end-end-radius: var(--r-chip); }
|
|
3660
|
+
.calendar__day--span-one::before { inset-inline-start: calc(50% - var(--_col) / 2); width: var(--_col); border-radius: var(--r-chip); }
|
|
3661
|
+
/* ---- hour grid: the hours of a day in Calendar's cells, `--hour-grid-cols` to a row, a label over them
|
|
3662
|
+
<div class="calendar hour-grid"><span class="calendar__label">น.</span><div class="calendar__grid"><button class="calendar__day">9</button>…</div></div> */
|
|
3663
|
+
.hour-grid > .calendar__grid { --_cols: var(--hour-grid-cols, 6); }
|
|
3664
|
+
|
|
3633
3665
|
/* ---- calendar weeks: a run of week rows that scrolls week by week, `show` rows in sight; the head sticks at the top of the box
|
|
3634
3666
|
<div class="calendar calendar--weeks"><div class="calendar__weeks-head"><span class="calendar__label">June 2026</span><div class="calendar__grid">…wd×7</div></div>
|
|
3635
3667
|
<div class="calendar__grid calendar__week"><button class="calendar__day">…</button>×7</div>…</div>
|
|
@@ -3924,6 +3956,9 @@ button.calendar__label:focus-visible { outline: var(--focus); outline-offset: va
|
|
|
3924
3956
|
<div class="kv-grid"><div class="kv-cell"><svg class="icon"/><span class="kv-cell__val">15.6 kg</span><span class="kv-cell__key">Weight</span></div>…</div> */
|
|
3925
3957
|
.kv-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(var(--tile-min), 100%), 1fr)); gap: var(--kv-grid-gap, var(--sp-4)); }
|
|
3926
3958
|
.kv-grid > .kv-cell + .kv-cell { border-left: var(--border-w) solid var(--hairline); padding-left: var(--sp-4); }
|
|
3959
|
+
/* `centre` (Lh 2026-10-21, the code on timebank's request card, as `Stat centre` and `Head centre` were): the grid is as tall as its holder, its cells stand in the middle of it, each value and caption centred */
|
|
3960
|
+
.kv-grid--centre { min-height: 100%; align-content: center; text-align: center; } /* min-height, not height: in a plain card (a grid of auto rows) a percent height resolved 8px short and the cell overflowed it; a percent min-height is nothing there, and the holder's height on a turning card's face */
|
|
3961
|
+
.kv-grid--centre > .kv-cell { justify-items: center; }
|
|
3927
3962
|
.kv-cell { display: grid; gap: var(--kv-cell-gap, var(--sp-0)); align-content: start; min-width: 0; }
|
|
3928
3963
|
.kv-cell > .icon { --icon-margin: 0 0 var(--sp-1); }
|
|
3929
3964
|
.kv-cell__val { font: var(--kv-cell-val-font, var(--type-h2)); letter-spacing: var(--track-h2); font-variant-numeric: tabular-nums; }
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { type ComponentProps } from 'react';
|
|
2
2
|
export interface CardMediaProps extends ComponentProps<'div'> {
|
|
3
3
|
}
|
|
4
|
-
/** CardMedia — rounded media inside a card (a Placeholder or img); a corner JourneyBadge pins to it
|
|
4
|
+
/** CardMedia — rounded media inside a card (a Placeholder or img); a corner JourneyBadge pins to it: the badge on the corner of a picture is the paper,
|
|
5
|
+
* its corner concentric with the media's; a theme's `--tile-badge-bg` / `--tile-badge-radius` still win. Ruled (Lh 2026-10-21). */
|
|
5
6
|
export declare function CardMedia({ className, ...rest }: CardMediaProps): import("react").JSX.Element;
|
|
6
7
|
export interface CardListProps extends ComponentProps<'div'> {
|
|
7
8
|
/** how many rows show before the list scrolls IN ITSELF, counted in rows, not a height: `2.5` = two whole rows and half of the third, the cut row
|
package/dist/cards/CardParts.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import { useLayoutEffect, useRef } from 'react';
|
|
3
3
|
import { cx } from '../cx.js';
|
|
4
|
-
/** CardMedia — rounded media inside a card (a Placeholder or img); a corner JourneyBadge pins to it
|
|
4
|
+
/** CardMedia — rounded media inside a card (a Placeholder or img); a corner JourneyBadge pins to it: the badge on the corner of a picture is the paper,
|
|
5
|
+
* its corner concentric with the media's; a theme's `--tile-badge-bg` / `--tile-badge-radius` still win. Ruled (Lh 2026-10-21). */
|
|
5
6
|
export function CardMedia({ className, ...rest }) {
|
|
6
7
|
return _jsx("div", { className: cx('card__media', className), ...rest });
|
|
7
8
|
}
|