@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/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, so a consumer that scales a
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
- Two lines are the budget: cardds.js measures and steps --squeeze down so the
530
- type shrinks to fit; the clamp holds a heading that still overflows to three
531
- lines, never more. The level's own size comes through --fs-self (base.css),
532
- so the multiplier is level-agnostic and a heading without --squeeze renders
533
- exactly as before.
534
- A STACK head is not a skeleton head — it is a one-line peek at its own size,
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. So it opts out of
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, the two-line budget and the squeeze
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: flex; align-items: center; gap: var(--sp-3); }
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
- .chip--toggle:has(:checked)::after {
2236
- mask-image: 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="M18 6 6 18"/><path d="m6 6 12 12"/></svg>');
2237
- -webkit-mask-image: 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="M18 6 6 18"/><path d="m6 6 12 12"/></svg>');
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: hidden; text-overflow: ellipsis; white-space: nowrap; padding-block: 0.12em; margin-block: -0.12em; } /* the clip keeps Thai marks — see card.css */
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); padding-block: var(--sp-3); } /* menu rows: more air, round arrow at the end */
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 > .row + .row { border-top: var(--border-w) solid var(--hairline); }
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
- padding: var(--sp-2);
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
- border-radius: var(--r-control);
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] {
@@ -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`) — two lines is its budget, it squeezes to fit and clamps at three */
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;
@@ -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: [heading != null && (_jsxs("div", { children: [overline != null && _jsx("span", { className: "t-overline t-muted", children: overline }), _jsx(H, { className: level === 'display' ? 't-display' : `t-${level}`, children: heading }), caption != null && _jsx("p", { className: "t-caption t-muted", children: caption })] })), children, end] }));
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
  }
@@ -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, flush, done, as, href, className, children, ...rest }: RowProps): import("react").DetailedReactHTMLElement<{
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, flush, done, as, href, className, children, ...rest }) {
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', flush && 'row--flush', 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" }) }));
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.0",
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:everysundays/cardds.git"
9
+ "url": "git+ssh://git@github.com/everysundays/cardds.git"
10
10
  },
11
11
  "scripts": {
12
12
  "dev": "vite --config app/vite.config.ts",