@usableapp/cardds 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +10 -7
- package/cardds.js +15 -109
- package/css/actions.css +2 -1
- package/css/base.css +1 -2
- package/css/card.css +36 -25
- package/css/choice.css +3 -5
- package/css/journey.css +10 -16
- package/css/layover.css +14 -3
- package/css/lists.css +17 -7
- package/css/sheet.css +1 -1
- package/css/stack.css +1 -5
- package/css/tokens.css +1 -0
- package/dist/actions/Chip.d.ts +1 -1
- package/dist/actions/Dropdown.d.ts +6 -2
- package/dist/actions/Dropdown.js +3 -3
- package/dist/actions/IconBtn.d.ts +10 -295
- package/dist/actions/IconBtn.js +9 -4
- package/dist/cardds.css +87 -66
- package/dist/cards/CardHead.d.ts +2 -2
- package/dist/cards/CardHead.js +2 -2
- package/dist/lists/Row.d.ts +1 -3
- package/dist/lists/Row.js +2 -2
- package/package.json +2 -2
package/dist/cardds.css
CHANGED
|
@@ -110,6 +110,7 @@
|
|
|
110
110
|
/* ---- borders / rules / elevation (px on purpose: crisp at any scale) ---- */
|
|
111
111
|
--border-w: 1.5px;
|
|
112
112
|
--rule-w: 2px; /* dotted connectors, picker rules */
|
|
113
|
+
--scroll-w: 1px; /* the scrollbar of a .bleed track: a hairline of ink */
|
|
113
114
|
--focus: 2px solid currentColor; /* :focus-visible ring */
|
|
114
115
|
--shadow-card: 0 1px 2px rgb(0 0 0 / 0.06), 0 0.5rem 1.5rem rgb(0 0 0 / 0.08);
|
|
115
116
|
--shadow-float: 0 0.25rem 0.75rem rgb(0 0 0 / 0.14);
|
|
@@ -410,8 +411,7 @@ button { font: inherit; cursor: pointer; }
|
|
|
410
411
|
.screen--fill > .sheet-stack { flex: 1; min-height: 0; }
|
|
411
412
|
|
|
412
413
|
/* ---- typography levels ---- */
|
|
413
|
-
/* --fs-self: each level publishes its own size,
|
|
414
|
-
heading (card.css --squeeze) can multiply it without knowing the level */
|
|
414
|
+
/* --fs-self: each level publishes its own size, for a consumer that scales a level without knowing which */
|
|
415
415
|
.t-display { font: var(--type-display); letter-spacing: var(--track-display); margin: 0; text-wrap: balance; --fs-self: var(--fs-display); }
|
|
416
416
|
.t-h1 { font: var(--type-h1); letter-spacing: var(--track-h1); margin: 0; --fs-self: var(--fs-h1); }
|
|
417
417
|
.t-h2 { font: var(--type-h2); letter-spacing: var(--track-h2); margin: 0; --fs-self: var(--fs-h2); }
|
|
@@ -503,10 +503,19 @@ button { font: inherit; cursor: pointer; }
|
|
|
503
503
|
multi-line title can opt back out with .card__head--top. */
|
|
504
504
|
.card__head {
|
|
505
505
|
display: flex;
|
|
506
|
+
flex-wrap: wrap; /* the caption / overline take a line of their own — no wrapper div */
|
|
506
507
|
align-items: center;
|
|
507
508
|
justify-content: space-between;
|
|
508
|
-
gap: var(--sp-3);
|
|
509
|
-
|
|
509
|
+
column-gap: var(--sp-3);
|
|
510
|
+
row-gap: var(--sp-0);
|
|
511
|
+
}
|
|
512
|
+
/* flat head markup (Lh 2026-09-16 — no <p>, no wrapper, only padding and gap tokens):
|
|
513
|
+
<div class="card__head"><span class="t-overline t-muted">…</span><h2 class="t-h2">…</h2><span class="t-caption t-muted">…</span><button class="icon-btn icon-btn--sm">…</button></div>
|
|
514
|
+
The heading and the far-right thing share the first row; an overline sits
|
|
515
|
+
on a row above (order −1), a caption on a row below (order 1), whatever the
|
|
516
|
+
DOM order — so an author writes the words in reading order. */
|
|
517
|
+
.card__head > :is(.t-overline, .t-caption, .t-body) { flex: 1 1 100%; order: 1; margin: 0; }
|
|
518
|
+
.card__head > .t-overline { order: -1; }
|
|
510
519
|
.card__head--top { align-items: flex-start; }
|
|
511
520
|
|
|
512
521
|
.card__media { border-radius: var(--r-media); overflow: hidden; position: relative; } /* relative: corner badges */
|
|
@@ -526,29 +535,12 @@ button { font: inherit; cursor: pointer; }
|
|
|
526
535
|
.card__head > :is(h1, h2, h3, div, p):first-child { flex: 1; min-width: 0; }
|
|
527
536
|
|
|
528
537
|
/* Skeleton head — the heading in a card's OWN head, and only there.
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
and "stack headers" below opts it out of the budget, the squeeze and the
|
|
536
|
-
clamp. cardds.js skips those same cards, so CSS and JS agree on what counts
|
|
537
|
-
as a skeleton head. Change one, change the other. */
|
|
538
|
-
.card__head :is(h1, h2, h3) {
|
|
539
|
-
font-size: calc(var(--fs-self, var(--fs-h2)) * var(--squeeze, 1));
|
|
540
|
-
overflow-wrap: anywhere;
|
|
541
|
-
display: -webkit-box;
|
|
542
|
-
-webkit-box-orient: vertical;
|
|
543
|
-
-webkit-line-clamp: 3;
|
|
544
|
-
overflow: hidden;
|
|
545
|
-
/* the clip would take the hair the tight leading leaves outside the line
|
|
546
|
-
box — a stacked tone mark on top, สระอู below (fonts.css). Padding is
|
|
547
|
-
inside the clip, the negative margin gives the room back, so the head
|
|
548
|
-
measures exactly as before. */
|
|
549
|
-
padding-block: 0.15em;
|
|
550
|
-
margin-block: -0.15em;
|
|
551
|
-
}
|
|
538
|
+
The heading wraps freely: no line budget, no squeeze, no clamp (Lh
|
|
539
|
+
2026-09-16 — a height rule on words only distorts them; content that needs
|
|
540
|
+
more rows takes more rows). The group that holds overline · heading ·
|
|
541
|
+
caption is the head's own wrapping row (above) — no wrapper element, no
|
|
542
|
+
height, only the row gap. */
|
|
543
|
+
.card__head :is(h1, h2, h3) { overflow-wrap: anywhere; }
|
|
552
544
|
|
|
553
545
|
/* ---- bleed: a scrolling track that runs to the container's edges ----
|
|
554
546
|
For a horizontal strip inside a padded container — .avatar-pick, .chip-row,
|
|
@@ -559,11 +551,30 @@ button { font: inherit; cursor: pointer; }
|
|
|
559
551
|
<div class="avatar-pick bleed">…</div>
|
|
560
552
|
Padding, not item margins: padding is inside the scrollable area, so the
|
|
561
553
|
last item scrolls fully clear of the edge instead of stopping against it.
|
|
562
|
-
scroll-padding keeps snap points on the content line, not the border edge.
|
|
554
|
+
scroll-padding keeps snap points on the content line, not the border edge.
|
|
555
|
+
The track IS the scroller (nowrap, overflow-x), so no one writes that inline.
|
|
556
|
+
Its scrollbar is designed, not hidden (Lh 2026-09-16): a --scroll-w line of
|
|
557
|
+
the track's own ink, and --sp-2 of room under the items so the line sits
|
|
558
|
+
clear of them and reads as a slider. It shows only while the track is
|
|
559
|
+
hovered or scrolling (cardds.js sets .is-scrolling for a beat after each
|
|
560
|
+
scroll event), otherwise the line is transparent — the room stays, so
|
|
561
|
+
nothing jumps. Chromium/Safari paint it through the ::-webkit-scrollbar
|
|
562
|
+
parts; Firefox gets its thin bar in the same ink. */
|
|
563
563
|
.bleed {
|
|
564
564
|
margin-inline: calc(-1 * var(--card-pad, 0px));
|
|
565
565
|
padding-inline: var(--card-pad, 0px);
|
|
566
|
+
padding-block-end: var(--sp-2);
|
|
566
567
|
scroll-padding-inline: var(--card-pad, 0px);
|
|
568
|
+
flex-wrap: nowrap;
|
|
569
|
+
overflow-x: auto;
|
|
570
|
+
}
|
|
571
|
+
.bleed::-webkit-scrollbar { height: var(--scroll-w); }
|
|
572
|
+
.bleed::-webkit-scrollbar-track { background: transparent; margin-inline: var(--card-pad, 0px); }
|
|
573
|
+
.bleed::-webkit-scrollbar-thumb { background: transparent; }
|
|
574
|
+
.bleed:is(:hover, .is-scrolling)::-webkit-scrollbar-thumb { background: currentColor; }
|
|
575
|
+
@supports not selector(::-webkit-scrollbar) {
|
|
576
|
+
.bleed { scrollbar-width: thin; scrollbar-color: transparent transparent; }
|
|
577
|
+
.bleed:is(:hover, .is-scrolling) { scrollbar-color: currentColor transparent; }
|
|
567
578
|
}
|
|
568
579
|
/* a bleeding child sits over the container's rounded corner, so a strip that
|
|
569
580
|
is genuinely first or last needs the corner clipped for it */
|
|
@@ -843,17 +854,13 @@ button { font: inherit; cursor: pointer; }
|
|
|
843
854
|
min-height: var(--tap);
|
|
844
855
|
}
|
|
845
856
|
/* NOT a skeleton head: a peek is one line at its own size, and the display
|
|
846
|
-
stack deliberately runs a second line under the next card.
|
|
847
|
-
the whole skeleton-head treatment — budget, squeeze and clamp. cardds.js
|
|
848
|
-
skips the same cards. */
|
|
857
|
+
stack deliberately runs a second line under the next card. */
|
|
849
858
|
.sheet-stack > .card > .card__head :is(h1, h2, h3) {
|
|
850
859
|
font-size: var(--fs-h1);
|
|
851
860
|
line-height: 1;
|
|
852
861
|
letter-spacing: -0.01em;
|
|
853
862
|
margin-right: auto; /* pins the icon cluster right */
|
|
854
863
|
display: block;
|
|
855
|
-
-webkit-line-clamp: none;
|
|
856
|
-
overflow: visible;
|
|
857
864
|
overflow-wrap: normal;
|
|
858
865
|
}
|
|
859
866
|
|
|
@@ -1153,7 +1160,7 @@ button { font: inherit; cursor: pointer; }
|
|
|
1153
1160
|
/* the head — a title row at least --tap tall, either kind, so the peek strip
|
|
1154
1161
|
(--sheet-peek) is the same for every sheet:
|
|
1155
1162
|
- in a step it is a plain card head (card.css): the heading left, the
|
|
1156
|
-
contextual thing at the far right
|
|
1163
|
+
contextual thing at the far right
|
|
1157
1164
|
- .sheet__head is the stage sheet's three-column head: a round button,
|
|
1158
1165
|
the centred title and sub, a round button
|
|
1159
1166
|
- a label .row with its .check / .toggle may be the head when the sheet's
|
|
@@ -1454,30 +1461,24 @@ button { font: inherit; cursor: pointer; }
|
|
|
1454
1461
|
============================================================ */
|
|
1455
1462
|
|
|
1456
1463
|
/* ---- route: endpoint · dotted connector (icon in middle) · endpoint ---- */
|
|
1457
|
-
.route { display:
|
|
1464
|
+
.route { display: grid; grid-template-columns: 1fr auto 1fr; align-items: center; column-gap: var(--sp-1); } /* line → icon: --sp-1, as the via always had; code → line is the code row's own --sp-3 */
|
|
1465
|
+
/* the two endpoints get EQUAL columns whatever their words measure, so the via
|
|
1466
|
+
(the icon alone) sits at the card's centre; each dotted run lives on ITS
|
|
1467
|
+
endpoint's code row and fills that side's leftover — with short names the
|
|
1468
|
+
runs are long and equal, a long place name wraps in its half instead of
|
|
1469
|
+
pushing the plane (Lh 2026-09-16) */
|
|
1458
1470
|
|
|
1459
1471
|
.route__point { display: grid; gap: var(--sp-0); min-width: 0; }
|
|
1460
1472
|
.route__point--end { text-align: right; }
|
|
1461
1473
|
|
|
1462
|
-
.route__code { font: var(--type-h2); letter-spacing: var(--track-h2); }
|
|
1474
|
+
.route__code { font: var(--type-h2); letter-spacing: var(--track-h2); display: flex; align-items: center; gap: var(--sp-3); }
|
|
1475
|
+
.route__code::after, .route__point--end .route__code::before { content: ""; flex: 1; border-top: var(--rule-w) dotted currentColor; opacity: 0.65; }
|
|
1476
|
+
.route__point--end .route__code::after { content: none; }
|
|
1463
1477
|
.route__time { font: var(--type-body); font-variant-numeric: tabular-nums; }
|
|
1464
1478
|
.route__place { font: var(--type-caption); color: var(--card-muted); }
|
|
1465
1479
|
.card--3 .route__place { color: inherit; opacity: 0.7; }
|
|
1466
1480
|
|
|
1467
|
-
.route__via {
|
|
1468
|
-
flex: 1;
|
|
1469
|
-
display: flex;
|
|
1470
|
-
align-items: center;
|
|
1471
|
-
gap: var(--sp-1);
|
|
1472
|
-
opacity: 0.65;
|
|
1473
|
-
font-size: var(--fs-body);
|
|
1474
|
-
}
|
|
1475
|
-
.route__via::before,
|
|
1476
|
-
.route__via::after {
|
|
1477
|
-
content: "";
|
|
1478
|
-
flex: 1;
|
|
1479
|
-
border-top: var(--rule-w) dotted currentColor;
|
|
1480
|
-
}
|
|
1481
|
+
.route__via { display: flex; align-items: center; opacity: 0.65; font-size: var(--fs-body); }
|
|
1481
1482
|
|
|
1482
1483
|
/* ---- tile badge: tiny label over a big value (gate, seat, zone) ---- */
|
|
1483
1484
|
.tile-badge {
|
|
@@ -1651,6 +1652,7 @@ button { font: inherit; cursor: pointer; }
|
|
|
1651
1652
|
/* dark-slot inversion lives in card.css (.card--3 :is(...)) */
|
|
1652
1653
|
|
|
1653
1654
|
.chip-row { display: flex; gap: var(--sp-2); flex-wrap: wrap; }
|
|
1655
|
+
.chip-row.bleed { flex-wrap: nowrap; } /* actions.css loads after card.css — the strip stays one line */
|
|
1654
1656
|
|
|
1655
1657
|
/* ---- dropdown: the standard for every select — a pill trigger + .menu popover ----
|
|
1656
1658
|
<div class="dropdown"><button class="dropdown__btn" popovertarget="f1"><span class="dropdown__label">this week</span><svg class="icon icon--xs"><use href="icons.svg#chevron-down"/></svg></button>
|
|
@@ -1679,7 +1681,7 @@ button { font: inherit; cursor: pointer; }
|
|
|
1679
1681
|
.dropdown__label { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
1680
1682
|
.dropdown__btn > .icon { transition: rotate 0.2s ease; }
|
|
1681
1683
|
.dropdown:has(.menu:popover-open) .dropdown__btn > .icon { rotate: 180deg; }
|
|
1682
|
-
.dropdown--end .menu[popover] { position-area: block-end span-inline-start; } /* right-aligned trigger: panel grows leftwards */
|
|
1684
|
+
.dropdown--end .menu[popover] { position-area: block-end span-inline-start; } /* right-aligned trigger: panel grows leftwards (= .menu--end, layover.css) */
|
|
1683
1685
|
.filter-row { display: flex; gap: var(--sp-2); }
|
|
1684
1686
|
.filter-row > .dropdown { flex: 1; min-width: 0; }
|
|
1685
1687
|
|
|
@@ -2232,12 +2234,10 @@ button { font: inherit; cursor: pointer; }
|
|
|
2232
2234
|
-webkit-mask: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="black" stroke-width="2.5" stroke-linecap="round"><path d="M5 12h14"/><path d="M12 5v14"/></svg>') center / contain no-repeat;
|
|
2233
2235
|
}
|
|
2234
2236
|
.chip--toggle:has(:checked) { background: var(--accent); color: var(--on-accent); border-color: transparent; }
|
|
2235
|
-
|
|
2236
|
-
|
|
2237
|
-
|
|
2238
|
-
}
|
|
2237
|
+
/* checked: the same plus turns 45° into an x — one mask, one rotate, no swap (Lh 2026-09-16) */
|
|
2238
|
+
.chip--toggle:has(:checked)::after { rotate: 45deg; }
|
|
2239
|
+
@media (prefers-reduced-motion: no-preference) { .chip--toggle::after { transition: rotate var(--motion-slide); } }
|
|
2239
2240
|
.chip--toggle:has(:focus-visible) { outline: var(--focus); outline-offset: var(--sp-1); }
|
|
2240
|
-
.chip--toggle:has(:checked) { font-style: italic; } /* the interest-picker flourish; drop if unwanted */
|
|
2241
2241
|
|
|
2242
2242
|
/* ---- chip grid: pick one slot / many options in a grid ----
|
|
2243
2243
|
<div class="chip-grid"><label class="chip chip--pick"><input type="radio" name="t">9:00</label>…</div> */
|
|
@@ -2458,12 +2458,14 @@ button { font: inherit; cursor: pointer; }
|
|
|
2458
2458
|
display: flex;
|
|
2459
2459
|
align-items: center;
|
|
2460
2460
|
gap: var(--sp-3);
|
|
2461
|
-
min-height: var(--tap);
|
|
2462
|
-
padding-block: var(--sp-2);
|
|
2461
|
+
min-height: var(--tap); /* the tap target's room — the row's only vertical size */
|
|
2463
2462
|
min-width: 0;
|
|
2464
2463
|
color: inherit;
|
|
2465
2464
|
text-decoration: none; /* .row works as <a> too — it is a tap target */
|
|
2466
2465
|
}
|
|
2466
|
+
/* no padding on a row (Lh 2026-09-16): padding is for room, not for spreading.
|
|
2467
|
+
Space BETWEEN rows is .rows' gap; a lone row as card content takes the card's
|
|
2468
|
+
gap. (.row--flush, which zeroed the old padding, is gone — every row is flush.) */
|
|
2467
2469
|
.row__lead {
|
|
2468
2470
|
width: var(--tap);
|
|
2469
2471
|
height: var(--tap);
|
|
@@ -2474,13 +2476,12 @@ button { font: inherit; cursor: pointer; }
|
|
|
2474
2476
|
place-items: center;
|
|
2475
2477
|
}
|
|
2476
2478
|
.row__body { flex: 1; min-width: 0; display: grid; gap: var(--sp-0); }
|
|
2477
|
-
.row__title { font: var(--type-title); overflow:
|
|
2479
|
+
.row__title { font: var(--type-title); overflow-wrap: anywhere; } /* wraps freely — no clip, so no padding trick for Thai marks (Lh 2026-09-16, same call as the card heading) */
|
|
2478
2480
|
.row__meta { font: var(--type-caption); color: var(--card-muted); display: flex; align-items: center; gap: var(--sp-1); }
|
|
2479
2481
|
.card--3 .row__meta { color: inherit; opacity: 0.7; }
|
|
2480
2482
|
.row__end { margin-left: auto; text-align: right; display: grid; gap: var(--sp-0); justify-items: end; flex: none; }
|
|
2481
|
-
.row--lg { min-height: var(--fab);
|
|
2483
|
+
.row--lg { min-height: var(--fab); } /* menu rows: a taller target, round arrow at the end; .rows gives them more air */
|
|
2482
2484
|
.row--lg .row__title { font: 700 var(--fs-lg)/1.2 var(--font-display); }
|
|
2483
|
-
.row--flush { padding-block: 0; } /* a single row as card content: the card's gap is the spacing */
|
|
2484
2485
|
/* a finished item in a checklist (a to-do list, an onboarding "complete your introduction" list):
|
|
2485
2486
|
the words go muted, a filled tick sits at the end, and the row is no longer a tap target —
|
|
2486
2487
|
pointer-events off here, aria-disabled from the markup. The tick is the .check's checked look
|
|
@@ -2501,8 +2502,17 @@ button { font: inherit; cursor: pointer; }
|
|
|
2501
2502
|
}
|
|
2502
2503
|
|
|
2503
2504
|
/* rows: a list of rows separated by hairlines */
|
|
2504
|
-
.rows { display: grid; }
|
|
2505
|
-
.rows
|
|
2505
|
+
.rows { display: grid; --rows-gap: var(--sp-4); row-gap: var(--rows-gap); }
|
|
2506
|
+
.rows:has(> .row--lg) { --rows-gap: var(--sp-6); }
|
|
2507
|
+
/* the hairline between rows sits in the middle of the gap — drawn, not spaced:
|
|
2508
|
+
no padding, no spacer element */
|
|
2509
|
+
.rows > .row + .row { position: relative; }
|
|
2510
|
+
.rows > .row + .row::before {
|
|
2511
|
+
content: "";
|
|
2512
|
+
position: absolute;
|
|
2513
|
+
inset: calc(-1 * var(--rows-gap) / 2) 0 auto;
|
|
2514
|
+
border-top: var(--border-w) solid var(--hairline);
|
|
2515
|
+
}
|
|
2506
2516
|
|
|
2507
2517
|
/* ---- kv: label left, value right ----
|
|
2508
2518
|
<dl class="kv"><div class="kv__row"><dt class="kv__key">Pay with</dt><dd class="kv__val">GHO</dd></div>…</dl> */
|
|
@@ -2879,14 +2889,22 @@ button { font: inherit; cursor: pointer; }
|
|
|
2879
2889
|
<button class="chip" popovertarget="when">Now ▾</button>
|
|
2880
2890
|
<div class="menu" id="when" popover><button class="menu__item"><svg class="icon"/>Now</button>…</div>
|
|
2881
2891
|
Native popover: light dismiss, Esc, top layer. Anchored to the invoker where
|
|
2882
|
-
anchor positioning exists; the fallback is the browser's centred placement.
|
|
2892
|
+
anchor positioning exists; the fallback is the browser's centred placement.
|
|
2893
|
+
Two kinds (Lh 2026-09-16): a VALUE menu (the dropdown's — the picked item
|
|
2894
|
+
stays current) and an ACTIONS menu, .menu--actions — things to do to the
|
|
2895
|
+
element the button belongs to (a card, a sheet), opened by an .icon-btn:
|
|
2896
|
+
<button class="icon-btn icon-btn--sm" popovertarget="m1" aria-label="More">…</button>
|
|
2897
|
+
<div class="menu menu--actions menu--end" id="m1" popover><button class="menu__item"><svg class="icon"/>Edit</button>…</div>
|
|
2898
|
+
No item stays current there (cardds.js skips the mark). .menu--end = the
|
|
2899
|
+
trigger sits at the far right, so the panel grows leftwards. */
|
|
2883
2900
|
.menu {
|
|
2884
2901
|
display: none; /* explicit closed state — never display on the base rule */
|
|
2885
2902
|
margin: 0;
|
|
2886
2903
|
inset: auto;
|
|
2887
2904
|
border: var(--border-w) solid var(--action-border);
|
|
2888
2905
|
border-radius: var(--r-card);
|
|
2889
|
-
|
|
2906
|
+
--menu-pad: var(--sp-2); /* published: a row's radius is concentric with the panel's */
|
|
2907
|
+
padding: var(--menu-pad);
|
|
2890
2908
|
min-width: 12rem;
|
|
2891
2909
|
background: var(--action-bg);
|
|
2892
2910
|
color: var(--action-ink);
|
|
@@ -2902,7 +2920,9 @@ button { font: inherit; cursor: pointer; }
|
|
|
2902
2920
|
width: 100%;
|
|
2903
2921
|
padding: 0 var(--sp-3);
|
|
2904
2922
|
border: 0;
|
|
2905
|
-
|
|
2923
|
+
/* concentric with the panel: the card radius minus the panel's padding, so the
|
|
2924
|
+
highlight's curve follows the outer corner (Lh 2026-09-16) */
|
|
2925
|
+
border-radius: calc(var(--r-card) - var(--menu-pad, var(--sp-2)));
|
|
2906
2926
|
background: transparent;
|
|
2907
2927
|
color: inherit;
|
|
2908
2928
|
font: var(--type-title);
|
|
@@ -2918,6 +2938,7 @@ button { font: inherit; cursor: pointer; }
|
|
|
2918
2938
|
min-width: max(12rem, anchor-size(width)); /* at least as wide as its trigger */
|
|
2919
2939
|
position-try-fallbacks: flip-block, flip-inline;
|
|
2920
2940
|
}
|
|
2941
|
+
.menu--end[popover] { position-area: block-end span-inline-start; }
|
|
2921
2942
|
}
|
|
2922
2943
|
@media (prefers-reduced-motion: no-preference) {
|
|
2923
2944
|
.menu[popover] {
|
package/dist/cards/CardHead.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { ComponentPropsWithoutRef, ReactNode } from 'react';
|
|
2
2
|
export interface CardHeadProps extends ComponentPropsWithoutRef<'div'> {
|
|
3
|
-
/** the heading (a string becomes an h2 at level `t-h2`) —
|
|
3
|
+
/** the heading (a string becomes an h2 at level `t-h2`) — wraps freely, as many lines as the words need */
|
|
4
4
|
heading?: ReactNode;
|
|
5
5
|
/** small caps above the heading ("Step 1 of 4", "Time bank") */
|
|
6
6
|
overline?: ReactNode;
|
|
@@ -16,6 +16,6 @@ export interface CardHeadProps extends ComponentPropsWithoutRef<'div'> {
|
|
|
16
16
|
/**
|
|
17
17
|
* CardHead — the card's head: the heading on the left takes the room, the contextual info hugs the far right.
|
|
18
18
|
* Use `heading` (+ `overline`/`caption`) and `end` for the standard head, or pass children for a custom one
|
|
19
|
-
* (the FIRST child takes the room). Never put buttons here — they go in the CardFoot.
|
|
19
|
+
* (the FIRST child takes the room). Flat markup: no wrapper element, no <p> — the overline and caption are spans on rows of their own (card.css). Never put buttons here — they go in the CardFoot.
|
|
20
20
|
*/
|
|
21
21
|
export declare function CardHead({ heading, overline, caption, end, top, level, className, children, ...rest }: CardHeadProps): import("react").JSX.Element;
|
package/dist/cards/CardHead.js
CHANGED
|
@@ -3,9 +3,9 @@ import { cx } from '../cx';
|
|
|
3
3
|
/**
|
|
4
4
|
* CardHead — the card's head: the heading on the left takes the room, the contextual info hugs the far right.
|
|
5
5
|
* Use `heading` (+ `overline`/`caption`) and `end` for the standard head, or pass children for a custom one
|
|
6
|
-
* (the FIRST child takes the room). Never put buttons here — they go in the CardFoot.
|
|
6
|
+
* (the FIRST child takes the room). Flat markup: no wrapper element, no <p> — the overline and caption are spans on rows of their own (card.css). Never put buttons here — they go in the CardFoot.
|
|
7
7
|
*/
|
|
8
8
|
export function CardHead({ heading, overline, caption, end, top, level = 'h2', className, children, ...rest }) {
|
|
9
9
|
const H = level === 'h1' ? 'h1' : 'h2';
|
|
10
|
-
return (_jsxs("div", { className: cx('card__head', top && 'card__head--top', className), ...rest, children: [
|
|
10
|
+
return (_jsxs("div", { className: cx('card__head', top && 'card__head--top', className), ...rest, children: [overline != null && _jsx("span", { className: "t-overline t-muted", children: overline }), heading != null && _jsx(H, { className: level === 'display' ? 't-display' : `t-${level}`, children: heading }), caption != null && _jsx("span", { className: "t-caption t-muted", children: caption }), children, end] }));
|
|
11
11
|
}
|
package/dist/lists/Row.d.ts
CHANGED
|
@@ -18,8 +18,6 @@ export interface RowProps extends Omit<ComponentPropsWithoutRef<'div'>, 'title'>
|
|
|
18
18
|
endCaption?: ReactNode;
|
|
19
19
|
/** menu row: more air, a bigger title */
|
|
20
20
|
lg?: boolean;
|
|
21
|
-
/** no vertical padding — a single row as card content */
|
|
22
|
-
flush?: boolean;
|
|
23
21
|
/** a finished checklist item: muted words, a filled tick at the end, no longer a tap target (aria-disabled) — pass no `end` */
|
|
24
22
|
done?: boolean;
|
|
25
23
|
/** div (default), a link, a label wrapping a Check/Toggle, li */
|
|
@@ -31,7 +29,7 @@ export interface RowProps extends Omit<ComponentPropsWithoutRef<'div'>, 'title'>
|
|
|
31
29
|
* Several go in Rows (hairlines between). A row that IS a card is `Card row`.
|
|
32
30
|
* `done` is the checklist's finished line: ticked, muted, not tappable any more.
|
|
33
31
|
*/
|
|
34
|
-
export declare function Row({ lead, leadIcon, title, meta, body, end, endValue, endCaption, lg,
|
|
32
|
+
export declare function Row({ lead, leadIcon, title, meta, body, end, endValue, endCaption, lg, done, as, href, className, children, ...rest }: RowProps): import("react").DetailedReactHTMLElement<{
|
|
35
33
|
slot?: string | undefined | undefined;
|
|
36
34
|
style?: import("react").CSSProperties | undefined;
|
|
37
35
|
suppressHydrationWarning?: boolean | undefined | undefined;
|
package/dist/lists/Row.js
CHANGED
|
@@ -7,9 +7,9 @@ import { Icon } from '../type/Icon';
|
|
|
7
7
|
* Several go in Rows (hairlines between). A row that IS a card is `Card row`.
|
|
8
8
|
* `done` is the checklist's finished line: ticked, muted, not tappable any more.
|
|
9
9
|
*/
|
|
10
|
-
export function Row({ lead, leadIcon, title, meta, body, end, endValue, endCaption, lg,
|
|
10
|
+
export function Row({ lead, leadIcon, title, meta, body, end, endValue, endCaption, lg, done, as, href, className, children, ...rest }) {
|
|
11
11
|
const el = as ?? (href ? 'a' : 'div');
|
|
12
|
-
return createElement(el, { href, className: cx('row', lg && 'row--lg',
|
|
12
|
+
return createElement(el, { href, className: cx('row', lg && 'row--lg', done && 'row--done', className), 'aria-disabled': done || undefined, ...rest }, leadIcon ? _jsx("span", { className: "row__lead", children: _jsx(Icon, { name: leadIcon }) }) : lead, (title != null || meta != null || body != null) && (_jsxs("div", { className: "row__body", children: [title != null && _jsx("span", { className: "row__title", children: title }), meta != null && _jsx("span", { className: "row__meta", children: meta }), body] })), children, (endValue != null || endCaption != null) && (_jsxs("span", { className: "row__end", children: [endValue != null && _jsx("span", { className: "t-title", children: endValue }), endCaption != null && _jsx("span", { className: "t-caption t-muted", children: endCaption })] })), end, done && _jsx("span", { className: "row__done", children: _jsx(Icon, { name: "check", size: "sm" }) }));
|
|
13
13
|
}
|
|
14
14
|
/** Rows — a list of Rows separated by hairlines. */
|
|
15
15
|
export function Rows({ className, ...rest }) {
|
package/package.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@usableapp/cardds",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"license": "UNLICENSED",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"description": "card-first mobile design system, React-first: the components in src/ are thin wrappers over the CSS contract (css/*.css stays the only truth), app/ is the Commons Time Bank PWA built from them, demo/ the CSS spec pages the acceptance tests (tests/) drive.",
|
|
7
7
|
"repository": {
|
|
8
8
|
"type": "git",
|
|
9
|
-
"url": "git@github.com
|
|
9
|
+
"url": "git+ssh://git@github.com/everysundays/cardds.git"
|
|
10
10
|
},
|
|
11
11
|
"scripts": {
|
|
12
12
|
"dev": "vite --config app/vite.config.ts",
|