@usableapp/cardds 0.7.11 → 0.7.13

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 CHANGED
@@ -2,6 +2,26 @@
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.
4
4
 
5
+ ## 0.7.13 — 2026-09-25
6
+
7
+ ### Added
8
+ - `SheetStep`: Enter in a field of the step presses the step's button, through the step's checks like a tap (a wrong
9
+ number stays on the step). It is the phone keyboard's next/go key. Give the field `enterKeyHint="next"` (or `"go"`) so
10
+ the key says so. iPhone's number/tel pads have no Enter key: there the member taps the step's button. No auto-advance on a
11
+ full number, on purpose (the member checks the number before the code is sent).
12
+
13
+ ## 0.7.12 — 2026-09-25
14
+
15
+ ### Changed
16
+ - `SheetSteps`: each step's title line is a THIN quiet bar — 32px (`--tap-base` × 2/3), an ink tint, rounded, 4px apart;
17
+ the tap stays 44px. Opening a step never makes its bar taller: the step's content shows on the ground under it. Replaces
18
+ the rule on top (0.7.11's `--sheet-step-border-w` default is now 0). With `numbered`, the number sits in a white disc on the bar
19
+ (was the brand colour). Knobs `--sheet-steps-row-h` · `--sheet-steps-gap` · `--sheet-step-bar-bg` · `-bar-ink` ·
20
+ `-bar-radius` · `-bar-pad-x` · `--sheet-step-num-bg` · `-num-ink`.
21
+ - The old ruled look is knobs only (story `SheetSteps · Ruled`): `--sheet-step-bar-bg: transparent; --sheet-step-bar-radius: 0;
22
+ --sheet-step-bar-pad-x: 0; --sheet-steps-row-h: var(--tap-sm); --sheet-step-border-w: 1.5px; --sheet-steps-gap: 0;
23
+ --sheet-step-num-bg: var(--ink-tint)`.
24
+
5
25
  ## 0.7.11 — 2026-09-25
6
26
 
7
27
  ### Added
package/css/sheet.css CHANGED
@@ -388,7 +388,6 @@
388
388
  .sheet-step {
389
389
  position: relative; min-width: 0;
390
390
  display: grid; grid-template-rows: auto 0fr; align-content: start; /* mid-fold the rows sum to less than the box: the spare room stays BELOW, never spread into the title row (Lh: it looked like a spring) */
391
- border-top: var(--sheet-step-border-w, 1px) solid var(--sheet-step-border, var(--hairline)); /* a hair, not a rule: 2px read heavy between short rows (Lh 2026-09-25) */
392
391
  flex: 0 0 auto;
393
392
  transition: grid-template-rows var(--motion-sheet) ease, flex-grow var(--motion-sheet) ease;
394
393
  }
@@ -396,21 +395,28 @@
396
395
  in one beat the step that was open folds while the new one unfolds (flex-grow and the 1fr row both ease), the piles slide
397
396
  with them, nothing jumps (Lh 2026-09-24) */
398
397
  .sheet-step--now { grid-template-rows: auto 1fr; flex-grow: 1; }
399
- .sheet-step__head { display: flex; align-items: center; gap: var(--sp-2); min-height: var(--sheet-steps-row-h, var(--tap-sm)); }
398
+ .sheet-step + .sheet-step { margin-top: var(--sheet-steps-gap, var(--sp-1)); } /* the folded bars read as a pile, a little ground between them (Lh 2026-09-25) */
399
+ .sheet-step__head { /* every step's title line is a quiet BAR (a tint of the ink, not the brand — a brand bar read as a button, Lh 2026-09-25), the same height open or folded — opening shows the white room under it, never a taller bar (Lh 2026-09-25; was a thin rule on top) */
400
+ display: flex; align-items: center; gap: var(--sp-3); min-height: var(--sheet-steps-row-h, calc(var(--tap-base) * 2 / 3)); /* THIN: 32px, a summary line, not a button (Lh 2026-09-25) — the tap stays 44, see __go */
401
+ padding-inline: var(--sheet-step-bar-pad-x, var(--sp-3)); border-radius: var(--sheet-step-bar-radius, var(--r-chip));
402
+ background: var(--sheet-step-bar-bg, var(--ink-tint)); color: var(--sheet-step-bar-ink, inherit);
403
+ border-top: var(--sheet-step-border-w, 0px) solid var(--sheet-step-border, currentColor); /* a rule instead of the bar: set this, the bar's bg transparent, radius 0 */
404
+ }
405
+ .sheet-step__summary { color: inherit; opacity: 0.8; }
400
406
  .sheet-step__title { font: var(--sheet-step-title-font, var(--type-label)); margin: 0; flex: 0 1 auto; min-width: 0; outline: none; /* the label size, not a body title: a pile of rows must stay small (Lh 2026-09-24) */ overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
401
- .sheet-step__num { /* `numbered`: the step's number in a disc BEFORE its title (Lh 2026-09-25) — every disc the same brand colour, none faded */
407
+ .sheet-step__num { /* `numbered`: the step's number in a disc BEFORE its title (Lh 2026-09-25) — a white disc on the bar, the number in the ink */
402
408
  flex: none; display: grid; place-items: center; inline-size: var(--sheet-step-num-size, calc(var(--tap-base) / 2)); block-size: var(--sheet-step-num-size, calc(var(--tap-base) / 2));
403
409
  border-radius: 50%; font: var(--sheet-step-num-font, var(--type-caption)); font-variant-numeric: tabular-nums;
404
- background: var(--sheet-step-num-bg, var(--accent)); color: var(--sheet-step-num-ink, var(--on-accent));
410
+ background: var(--sheet-step-num-bg, var(--card-bg)); color: var(--sheet-step-num-ink, inherit);
405
411
  }
406
412
  .sheet-step__summary { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
407
413
  .sheet-step__check { margin-inline-start: auto; }
408
414
  .sheet-step__body { min-height: 0; overflow: clip; overflow-clip-margin: var(--sp-1); }
409
- .sheet-step__inner { display: grid; gap: var(--card-gap); padding-bottom: var(--card-gap); }
415
+ .sheet-step__inner { display: grid; gap: var(--card-gap); padding-block: var(--card-gap); }
410
416
  .sheet-step__inner > * { min-width: 0; }
411
417
  .sheet-step__inner > .link { justify-self: center; } /* a link of its own row in a step (skip, "change number", "set PIN again"): centred under the step, as the skip (Lh 2026-09-25) */
412
418
  .sheet-step:not(.sheet-step--now) > .sheet-step__body { visibility: hidden; transition: visibility 0s linear var(--motion-sheet); }
413
- .sheet-step__go { position: absolute; inset: 0; margin: 0; padding: 0; border: 0; background: none; cursor: pointer; -webkit-tap-highlight-color: transparent; }
419
+ .sheet-step__go { position: absolute; inset: min(0px, (var(--sheet-steps-row-h, calc(var(--tap-base) * 2 / 3)) - var(--tap-sm)) / 2) 0 auto; min-height: max(100%, var(--tap-sm)); /* a thin bar still takes a 44px tap */ margin: 0; padding: 0; border: 0; background: none; cursor: pointer; -webkit-tap-highlight-color: transparent; }
414
420
  /* the last step's finish, when the app gives one: under the steps */
415
421
  .sheet-steps__finish { display: grid; padding-top: var(--card-gap); }
416
422
  @media (prefers-reduced-motion: reduce) { .sheet-step { transition: none; } }
package/dist/cardds.css CHANGED
@@ -1576,7 +1576,6 @@ button { font: inherit; cursor: pointer; }
1576
1576
  .sheet-step {
1577
1577
  position: relative; min-width: 0;
1578
1578
  display: grid; grid-template-rows: auto 0fr; align-content: start; /* mid-fold the rows sum to less than the box: the spare room stays BELOW, never spread into the title row (Lh: it looked like a spring) */
1579
- border-top: var(--sheet-step-border-w, 1px) solid var(--sheet-step-border, var(--hairline)); /* a hair, not a rule: 2px read heavy between short rows (Lh 2026-09-25) */
1580
1579
  flex: 0 0 auto;
1581
1580
  transition: grid-template-rows var(--motion-sheet) ease, flex-grow var(--motion-sheet) ease;
1582
1581
  }
@@ -1584,21 +1583,28 @@ button { font: inherit; cursor: pointer; }
1584
1583
  in one beat the step that was open folds while the new one unfolds (flex-grow and the 1fr row both ease), the piles slide
1585
1584
  with them, nothing jumps (Lh 2026-09-24) */
1586
1585
  .sheet-step--now { grid-template-rows: auto 1fr; flex-grow: 1; }
1587
- .sheet-step__head { display: flex; align-items: center; gap: var(--sp-2); min-height: var(--sheet-steps-row-h, var(--tap-sm)); }
1586
+ .sheet-step + .sheet-step { margin-top: var(--sheet-steps-gap, var(--sp-1)); } /* the folded bars read as a pile, a little ground between them (Lh 2026-09-25) */
1587
+ .sheet-step__head { /* every step's title line is a quiet BAR (a tint of the ink, not the brand — a brand bar read as a button, Lh 2026-09-25), the same height open or folded — opening shows the white room under it, never a taller bar (Lh 2026-09-25; was a thin rule on top) */
1588
+ display: flex; align-items: center; gap: var(--sp-3); min-height: var(--sheet-steps-row-h, calc(var(--tap-base) * 2 / 3)); /* THIN: 32px, a summary line, not a button (Lh 2026-09-25) — the tap stays 44, see __go */
1589
+ padding-inline: var(--sheet-step-bar-pad-x, var(--sp-3)); border-radius: var(--sheet-step-bar-radius, var(--r-chip));
1590
+ background: var(--sheet-step-bar-bg, var(--ink-tint)); color: var(--sheet-step-bar-ink, inherit);
1591
+ border-top: var(--sheet-step-border-w, 0px) solid var(--sheet-step-border, currentColor); /* a rule instead of the bar: set this, the bar's bg transparent, radius 0 */
1592
+ }
1593
+ .sheet-step__summary { color: inherit; opacity: 0.8; }
1588
1594
  .sheet-step__title { font: var(--sheet-step-title-font, var(--type-label)); margin: 0; flex: 0 1 auto; min-width: 0; outline: none; /* the label size, not a body title: a pile of rows must stay small (Lh 2026-09-24) */ overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
1589
- .sheet-step__num { /* `numbered`: the step's number in a disc BEFORE its title (Lh 2026-09-25) — every disc the same brand colour, none faded */
1595
+ .sheet-step__num { /* `numbered`: the step's number in a disc BEFORE its title (Lh 2026-09-25) — a white disc on the bar, the number in the ink */
1590
1596
  flex: none; display: grid; place-items: center; inline-size: var(--sheet-step-num-size, calc(var(--tap-base) / 2)); block-size: var(--sheet-step-num-size, calc(var(--tap-base) / 2));
1591
1597
  border-radius: 50%; font: var(--sheet-step-num-font, var(--type-caption)); font-variant-numeric: tabular-nums;
1592
- background: var(--sheet-step-num-bg, var(--accent)); color: var(--sheet-step-num-ink, var(--on-accent));
1598
+ background: var(--sheet-step-num-bg, var(--card-bg)); color: var(--sheet-step-num-ink, inherit);
1593
1599
  }
1594
1600
  .sheet-step__summary { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
1595
1601
  .sheet-step__check { margin-inline-start: auto; }
1596
1602
  .sheet-step__body { min-height: 0; overflow: clip; overflow-clip-margin: var(--sp-1); }
1597
- .sheet-step__inner { display: grid; gap: var(--card-gap); padding-bottom: var(--card-gap); }
1603
+ .sheet-step__inner { display: grid; gap: var(--card-gap); padding-block: var(--card-gap); }
1598
1604
  .sheet-step__inner > * { min-width: 0; }
1599
1605
  .sheet-step__inner > .link { justify-self: center; } /* a link of its own row in a step (skip, "change number", "set PIN again"): centred under the step, as the skip (Lh 2026-09-25) */
1600
1606
  .sheet-step:not(.sheet-step--now) > .sheet-step__body { visibility: hidden; transition: visibility 0s linear var(--motion-sheet); }
1601
- .sheet-step__go { position: absolute; inset: 0; margin: 0; padding: 0; border: 0; background: none; cursor: pointer; -webkit-tap-highlight-color: transparent; }
1607
+ .sheet-step__go { position: absolute; inset: min(0px, (var(--sheet-steps-row-h, calc(var(--tap-base) * 2 / 3)) - var(--tap-sm)) / 2) 0 auto; min-height: max(100%, var(--tap-sm)); /* a thin bar still takes a 44px tap */ margin: 0; padding: 0; border: 0; background: none; cursor: pointer; -webkit-tap-highlight-color: transparent; }
1602
1608
  /* the last step's finish, when the app gives one: under the steps */
1603
1609
  .sheet-steps__finish { display: grid; padding-top: var(--card-gap); }
1604
1610
  @media (prefers-reduced-motion: reduce) { .sheet-step { transition: none; } }
@@ -22,7 +22,7 @@ export interface SheetStepsProps extends ComponentProps<'div'> {
22
22
  /** true: the member may go back and forth — a tap on a done or next step opens it, an up/down swipe moves one step.
23
23
  * false (default): only forward — the done steps stay in the pile, never opened again (a swipe up passes only a `skippable` step). */
24
24
  reversible?: boolean;
25
- /** true: each step's number in a disc before its title — all the same brand colour (Lh 2026-09-25). Default: titles only. */
25
+ /** true: each step's number in a disc before its title — a white disc on the step's bar (Lh 2026-09-25). Default: titles only. */
26
26
  numbered?: boolean;
27
27
  }
28
28
  /**
@@ -238,5 +238,16 @@ export function SheetStep({ title, summary, skippable, skipLabel = 'Skip', error
238
238
  bad.focus();
239
239
  }
240
240
  };
241
- return (_jsxs("li", { className: cx('sheet-step', `sheet-step--${phase}`, busy != null && busy !== false && 'sheet-step--busy', className), "aria-current": phase === 'now' ? 'step' : undefined, "aria-busy": busy != null && busy !== false ? true : undefined, "data-skippable": skippable || undefined, ...rest, children: [_jsxs("div", { className: "sheet-step__head", inert: off || undefined, children: [numbered && _jsx("span", { className: "sheet-step__num", "aria-hidden": true, children: i + 1 }), _jsx("h3", { className: "sheet-step__title", tabIndex: -1, children: title }), phase === 'done' && summary != null && _jsx("span", { className: "sheet-step__summary t-caption t-muted", children: summary }), phase === 'done' && _jsx(Icon, { name: "check", size: "xs", className: "sheet-step__check" })] }), _jsx("div", { className: "sheet-step__body", children: _jsxs("div", { className: "sheet-step__inner", inert: off || undefined, onClickCapture: press, onPointerDown: keepCursor, children: [_jsx(CheckContext.Provider, { value: group, children: children }), _jsx(FormNote, { error: error ?? note, busy: busy }), skippable && _jsx(Link, { sm: true, muted: true, className: "sheet-step__skip", onClick: () => go(i + 1, 'skip'), children: skipLabel })] }) }), reversible && off && (_jsx("button", { type: "button", className: "sheet-step__go", "aria-label": typeof title === 'string' ? title : `${i + 1} / ${count}`, onClick: () => go(i, 'tap') }))] }));
241
+ /* Enter on the keyboard in a field of the step = a press on the step's button (the phone's "go"/"next" key, a desktop's Enter);
242
+ the press goes through the step's checks like a tap (Lh 2026-09-25) */
243
+ const enter = (e) => {
244
+ if (e.key !== 'Enter' || e.nativeEvent.isComposing || !(e.target instanceof HTMLInputElement))
245
+ return;
246
+ const btn = e.currentTarget.querySelector('.btn:not(:disabled)');
247
+ if (btn) {
248
+ e.preventDefault();
249
+ btn.click();
250
+ }
251
+ };
252
+ return (_jsxs("li", { className: cx('sheet-step', `sheet-step--${phase}`, busy != null && busy !== false && 'sheet-step--busy', className), "aria-current": phase === 'now' ? 'step' : undefined, "aria-busy": busy != null && busy !== false ? true : undefined, "data-skippable": skippable || undefined, ...rest, children: [_jsxs("div", { className: "sheet-step__head", inert: off || undefined, children: [numbered && _jsx("span", { className: "sheet-step__num", "aria-hidden": true, children: i + 1 }), _jsx("h3", { className: "sheet-step__title", tabIndex: -1, children: title }), phase === 'done' && summary != null && _jsx("span", { className: "sheet-step__summary t-caption", children: summary }), phase === 'done' && _jsx(Icon, { name: "check", size: "xs", className: "sheet-step__check" })] }), _jsx("div", { className: "sheet-step__body", children: _jsxs("div", { className: "sheet-step__inner", inert: off || undefined, onClickCapture: press, onPointerDown: keepCursor, onKeyDown: enter, children: [_jsx(CheckContext.Provider, { value: group, children: children }), _jsx(FormNote, { error: error ?? note, busy: busy }), skippable && _jsx(Link, { sm: true, muted: true, className: "sheet-step__skip", onClick: () => go(i + 1, 'skip'), children: skipLabel })] }) }), reversible && off && (_jsx("button", { type: "button", className: "sheet-step__go", "aria-label": typeof title === 'string' ? title : `${i + 1} / ${count}`, onClick: () => go(i, 'tap') }))] }));
242
253
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@usableapp/cardds",
3
- "version": "0.7.11",
3
+ "version": "0.7.13",
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); gallery/ shows every story live (npm run dev), tests/ measures the geometry.",