@usableapp/cardds 0.7.64 → 0.7.66

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,20 @@
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.66 — 2026-10-06
6
+
7
+ ### Added
8
+ - **`Sticky onClick`: the whole note is the button** (Lh 2026-10-06) — pass `onClick` and the note renders a `<button>`: a tap anywhere on it, a focus ring, and it KEEPS its folded corner. Before: only an `IconBtn` in `corner` could be pressed, and a note with `corner` has no fold. `<Sticky onClick={open}>…</Sticky>`. With `corner` the note stays a plain box (a button cannot hold a button).
9
+ - **A `Centre` as a closed stack's `base` stands in the middle** (Lh 2026-10-06) — `Home base={<Centre>…</Centre>}` / `SheetStack base`: the block sits in the middle of the room above the sheet heads. Before it sat against the heads, as loose things in a base do. A base that is one `Page` still reads from the top.
10
+
11
+ ### Changed
12
+ - **A tilted `square` note is sized by the screen** (Lh 2026-10-06) — `<Sticky square tilt>` is three quarters of the screen's width inside its inset (255px on a 375 phone), on any phone. Before: `--sticky-square-max-w` (336px at the defaults), which a screen had to cut down with `style`. Remove that `style`; to tune it, set `--sticky-tilt-max-w` in your `theme.css`. A straight `square` note is unchanged.
13
+
14
+ ## 0.7.65 — 2026-10-06
15
+
16
+ ### Changed
17
+ - **A `paper` stack sheet's head band is 4px taller** (Lh 2026-10-06) — the white starts 12px (`--sp-3`) under the head, it was 8px (`--sp-2`): the coloured band of an open sheet is 81.5px tall at the defaults, it was 77.5. `SheetStack` / `Home` sheets with `paper` only; a single paper `Sheet`, a stack sheet without `paper`, and the peeked heads are unchanged. Nothing to change in a screen; a test that measured the gap under the head reads 12.
18
+
5
19
  ## 0.7.64 — 2026-10-06
6
20
 
7
21
  ### Added
package/css/stack.css CHANGED
@@ -289,6 +289,10 @@
289
289
  /* a base that is ONE Page is a page's words (a title, a welcome, the news): it reads from the TOP, like any page —
290
290
  loose things (a picture, a line) still sit against the peeks (Lh 2026-09-23, the home) */
291
291
  .sheet-stack__base:has(> .page:only-child) { align-content: start; }
292
+ /* a base that is ONE Centre is one thing handed over (a note, an empty state): it stands in the MIDDLE of the room above the peeks
293
+ (Lh 2026-10-06). The base already keeps the screen's inset, so the centre block gives its own back. */
294
+ .sheet-stack__base:has(> .screen__centre:only-child) { align-content: center; }
295
+ .sheet-stack__base > .screen__centre { padding-inline: 0; }
292
296
 
293
297
  /* back button: lives in a slot the header reserves once open, and DISSOLVES
294
298
  into it — an opacity fade in place, never a slide in from the left (the
@@ -336,10 +340,10 @@
336
340
  sheet's own slide (--motion-sheet, plus the same stagger), so the corner is the head colour
337
341
  at the moment the sheet stops. Rising, the body is white at once. */
338
342
  /* the head's band is as slim as it can be (Lh 2026-10-06: 20 over · 48 head · 20 under read as a heavy bar): the white starts
339
- --sp-2 under the head, not a whole --card-gap. The body is pulled up by the difference — the card's gap is left alone, the
343
+ --sp-3 under the head, not a whole --card-gap (--sp-2 at first; Lh added 4 the same day). The body is pulled up by the difference — the card's gap is left alone, the
340
344
  stack's step and the body's own rows read it. */
341
345
  .sheet-stack > .card.sheet--paper > .sheet__body {
342
- margin-top: calc(var(--sp-2) - var(--card-gap));
346
+ margin-top: calc(var(--sp-3) - var(--card-gap));
343
347
  padding-top: calc(var(--sp-6) + var(--_refresh, 0px));
344
348
  transition: padding-top var(--motion-sheet) ease, background-color 0s linear;
345
349
  }
package/css/sticky.css CHANGED
@@ -113,6 +113,16 @@
113
113
  mask: radial-gradient(circle at 100% 100%, transparent calc(var(--_notch) - var(--border-w)), #000 var(--_notch));
114
114
  }
115
115
 
116
+ /* a tilted square is sized by the SCREEN, not by a length: three quarters of its width inside the inset, about two thirds of the glass (Lh 2026-10-06) — the turned corners
117
+ keep clear of the edges on any phone. cqw reads the fill screen (the size container). After --square, so it wins. */
118
+ .sticky--square.sticky--tilt-left, .sticky--square.sticky--tilt-right { max-width: var(--sticky-tilt-max-w, 75cqw); }
119
+
120
+ /* --tap: the whole note is the button (`onClick`). The fold stays; the ring follows the note's turn. */
121
+ .sticky--tap { appearance: none; border: 0; font: inherit; text-align: start; cursor: pointer; -webkit-tap-highlight-color: transparent; }
122
+ .sticky--tap .sticky__body, .sticky--tap .sticky__foot { display: block; }
123
+ .sticky--tap:focus-visible { outline: var(--focus); outline-offset: var(--sp-1); }
124
+ .sticky--tap:active > .sticky__paper { translate: 0 var(--sp-0); }
125
+
116
126
  /* ---- sticky field: the words written ON a note — a bare textarea in the note's type and ink, filling it ----
117
127
  <div class="sticky__body"><textarea class="sticky-field" aria-label="Note" placeholder="Add text to this note"></textarea></div> */
118
128
  .sticky__body:has(> .sticky-field) { display: grid; }
package/dist/cardds.css CHANGED
@@ -1291,6 +1291,10 @@ button:enabled { cursor: pointer; } /* a disabled one keeps the arrow */
1291
1291
  /* a base that is ONE Page is a page's words (a title, a welcome, the news): it reads from the TOP, like any page —
1292
1292
  loose things (a picture, a line) still sit against the peeks (Lh 2026-09-23, the home) */
1293
1293
  .sheet-stack__base:has(> .page:only-child) { align-content: start; }
1294
+ /* a base that is ONE Centre is one thing handed over (a note, an empty state): it stands in the MIDDLE of the room above the peeks
1295
+ (Lh 2026-10-06). The base already keeps the screen's inset, so the centre block gives its own back. */
1296
+ .sheet-stack__base:has(> .screen__centre:only-child) { align-content: center; }
1297
+ .sheet-stack__base > .screen__centre { padding-inline: 0; }
1294
1298
 
1295
1299
  /* back button: lives in a slot the header reserves once open, and DISSOLVES
1296
1300
  into it — an opacity fade in place, never a slide in from the left (the
@@ -1338,10 +1342,10 @@ button:enabled { cursor: pointer; } /* a disabled one keeps the arrow */
1338
1342
  sheet's own slide (--motion-sheet, plus the same stagger), so the corner is the head colour
1339
1343
  at the moment the sheet stops. Rising, the body is white at once. */
1340
1344
  /* the head's band is as slim as it can be (Lh 2026-10-06: 20 over · 48 head · 20 under read as a heavy bar): the white starts
1341
- --sp-2 under the head, not a whole --card-gap. The body is pulled up by the difference — the card's gap is left alone, the
1345
+ --sp-3 under the head, not a whole --card-gap (--sp-2 at first; Lh added 4 the same day). The body is pulled up by the difference — the card's gap is left alone, the
1342
1346
  stack's step and the body's own rows read it. */
1343
1347
  .sheet-stack > .card.sheet--paper > .sheet__body {
1344
- margin-top: calc(var(--sp-2) - var(--card-gap));
1348
+ margin-top: calc(var(--sp-3) - var(--card-gap));
1345
1349
  padding-top: calc(var(--sp-6) + var(--_refresh, 0px));
1346
1350
  transition: padding-top var(--motion-sheet) ease, background-color 0s linear;
1347
1351
  }
@@ -3713,6 +3717,16 @@ button:enabled { cursor: pointer; } /* a disabled one keeps the arrow */
3713
3717
  mask: radial-gradient(circle at 100% 100%, transparent calc(var(--_notch) - var(--border-w)), #000 var(--_notch));
3714
3718
  }
3715
3719
 
3720
+ /* a tilted square is sized by the SCREEN, not by a length: three quarters of its width inside the inset, about two thirds of the glass (Lh 2026-10-06) — the turned corners
3721
+ keep clear of the edges on any phone. cqw reads the fill screen (the size container). After --square, so it wins. */
3722
+ .sticky--square.sticky--tilt-left, .sticky--square.sticky--tilt-right { max-width: var(--sticky-tilt-max-w, 75cqw); }
3723
+
3724
+ /* --tap: the whole note is the button (`onClick`). The fold stays; the ring follows the note's turn. */
3725
+ .sticky--tap { appearance: none; border: 0; font: inherit; text-align: start; cursor: pointer; -webkit-tap-highlight-color: transparent; }
3726
+ .sticky--tap .sticky__body, .sticky--tap .sticky__foot { display: block; }
3727
+ .sticky--tap:focus-visible { outline: var(--focus); outline-offset: var(--sp-1); }
3728
+ .sticky--tap:active > .sticky__paper { translate: 0 var(--sp-0); }
3729
+
3716
3730
  /* ---- sticky field: the words written ON a note — a bare textarea in the note's type and ink, filling it ----
3717
3731
  <div class="sticky__body"><textarea class="sticky-field" aria-label="Note" placeholder="Add text to this note"></textarea></div> */
3718
3732
  .sticky__body:has(> .sticky-field) { display: grid; }
@@ -1,6 +1,8 @@
1
1
  import type { ComponentProps, ReactNode } from 'react';
2
2
  import type { StickyTone } from './tones.js';
3
- export interface StickyProps extends ComponentProps<'div'> {
3
+ export interface StickyProps extends Omit<ComponentProps<'div'>, 'onClick'> {
4
+ /** the whole note is a button: it renders a `<button>` and keeps its fold. Not with `corner` (a button cannot hold a button) */
5
+ onClick?: () => void;
4
6
  /** the paper's colour — one of STICKY_TONES (default custard) */
5
7
  tone?: StickyTone;
6
8
  /** no folded corner */
@@ -22,4 +24,4 @@ export interface StickyProps extends ComponentProps<'div'> {
22
24
  * Sticky — a paper note: a flat pastel block, straight, its bottom-right corner folded over, a soft shadow under it.
23
25
  * The outer box holds the tone and the shadow; the paper inside is the part that is cut (a clip would cut the shadow too).
24
26
  */
25
- export declare function Sticky({ tone, flat, square, head, date, tilt, foot, corner, className, children, ...rest }: StickyProps): import("react").JSX.Element;
27
+ export declare function Sticky({ tone, flat, square, head, date, tilt, foot, corner, onClick, className, children, ...rest }: StickyProps): import("react").JSX.Element;
@@ -4,7 +4,11 @@ import { cx } from '../cx.js';
4
4
  * Sticky — a paper note: a flat pastel block, straight, its bottom-right corner folded over, a soft shadow under it.
5
5
  * The outer box holds the tone and the shadow; the paper inside is the part that is cut (a clip would cut the shadow too).
6
6
  */
7
- export function Sticky({ tone = 'custard', flat, square, head, date, tilt, foot, corner, className, children, ...rest }) {
7
+ export function Sticky({ tone = 'custard', flat, square, head, date, tilt, foot, corner, onClick, className, children, ...rest }) {
8
8
  const notched = corner != null;
9
- return (_jsxs("div", { className: cx('sticky', `sticky--${tone}`, flat && 'sticky--flat', square && 'sticky--square', notched && 'sticky--corner', tilt && `sticky--tilt-${tilt}`, className), ...rest, children: [_jsxs("div", { className: "sticky__paper", children: [(head != null || date != null) && _jsxs("div", { className: "sticky__head", children: [head, date] }), _jsx("div", { className: "sticky__body", children: children }), foot != null && _jsx("div", { className: "sticky__foot", children: foot }), !flat && !notched && _jsx("span", { className: "sticky__fold", "aria-hidden": "true" })] }), notched && _jsx("div", { className: "sticky__corner", children: corner })] }));
9
+ const tap = onClick != null && !notched;
10
+ const Box = (tap ? 'button' : 'div');
11
+ const Part = tap ? 'span' : 'div';
12
+ const boxProps = (tap ? { type: 'button', onClick, ...rest } : rest);
13
+ return (_jsxs(Box, { className: cx('sticky', `sticky--${tone}`, flat && 'sticky--flat', square && 'sticky--square', notched && 'sticky--corner', tilt && `sticky--tilt-${tilt}`, tap && 'sticky--tap', className), ...boxProps, children: [_jsxs(Part, { className: "sticky__paper", children: [(head != null || date != null) && _jsxs(Part, { className: "sticky__head", children: [head, date] }), _jsx(Part, { className: "sticky__body", children: children }), foot != null && _jsx(Part, { className: "sticky__foot", children: foot }), !flat && !notched && _jsx("span", { className: "sticky__fold", "aria-hidden": "true" })] }), notched && _jsx("div", { className: "sticky__corner", children: corner })] }));
10
14
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@usableapp/cardds",
3
- "version": "0.7.64",
3
+ "version": "0.7.66",
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.",