@usableapp/cardds 0.6.13 → 0.6.15

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,31 @@
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.6.15 — 2026-09-24
6
+
7
+ - **`ActionNote` icon colour:** new knob `--action-note-icon-ink` (default: the words' muted ink). A project can colour the
8
+ icon apart from the words, e.g. the system blue of the control it points at:
9
+ `:root { --action-note-icon-ink: #007AFF }` (and `#0A84FF` in dark mode) in its theme.css. cardds carries no platform colour.
10
+
11
+ ## 0.6.14 — 2026-09-24
12
+
13
+ ### ActionNote (new, the bottom)
14
+ - The main button's place and size, but lying on the ground: no fill, no border, no rounding. It holds one line of muted
15
+ words, and an inline `Icon` is allowed. Nothing to press.
16
+ - For when there is nothing to press here. Example (iPhone install):
17
+ `<ActionNote>กดที่ <Icon name="share" /> ด้านล่างนี้</ActionNote>`, pointing at Safari's own share button.
18
+ - Put it in a `CardFoot` (so a `CallSheet`'s `sheet.foot`) or an `ActionBar`, in place of the button, never beside one.
19
+ A `link` / `ctaLink` still goes under it.
20
+ - One fixed shape, never styled per use.
21
+
22
+ ### Modal in Safari (iOS 18) — fixed
23
+ - Before: in Safari/WebKit the Modal stretched to the whole stage and its dark drawer (the question + buttons) was pushed out of
24
+ sight; Chrome was right. After: the same in both — the card its own height at the centre, the drawer shown.
25
+ - CSS only, nothing to change in a project: `.modal` is a flex column (was a grid of `minmax(0, 1fr) auto`, which WebKit sized
26
+ to 0) and takes its own height by `align-self: center` (was `height: fit-content`).
27
+
28
+ - Tests can run in WebKit: `CARDDS_BROWSER=webkit npm test` (the 131% text-size cases are Chrome-only — they use CDP).
29
+
5
30
  ## 0.6.13 — 2026-09-24
6
31
 
7
32
  ### `CallSheet ways`: several ways in, each calling its own sheet (new)
package/css/actions.css CHANGED
@@ -310,3 +310,24 @@
310
310
  fixed to the viewport wherever it sits. (.screen--fill reserves nothing:
311
311
  its .step carries the bar's room itself, step.css.) */
312
312
  :has(> .action-bar) .screen:not(.screen--fill) { padding-bottom: var(--bar-reserve); }
313
+
314
+ /* ---- action note (Lh 2026-09-24): the main button's place, the main button's size, but ON the ground — no fill, no border, no
315
+ rounding — one line of muted words, an inline icon allowed; nothing to press. In a CardFoot or an ActionBar row it takes the
316
+ button's share (the whole width), so a foot or a bar keeps its height whether it holds a button or the note. ---- */
317
+ .action-note {
318
+ flex: 1 1 0;
319
+ min-width: 0;
320
+ min-height: var(--btn-h);
321
+ display: flex;
322
+ align-items: center;
323
+ justify-content: center;
324
+ gap: var(--action-note-gap, var(--sp-1));
325
+ padding-inline: var(--sp-2);
326
+ font: var(--action-note-font, var(--type-body));
327
+ color: var(--action-note-ink, var(--on-surface-muted));
328
+ text-align: center;
329
+ cursor: default;
330
+ }
331
+ .card .action-note { color: var(--action-note-ink, var(--card-muted)); }
332
+ .action-note__words { display: block; } /* ONE run of words: an icon inside sits in the line, the spaces around it kept */
333
+ .action-note__words > .icon { display: inline-block; vertical-align: -0.2em; width: 1.25em; height: 1.25em; margin-inline: 0.15em; color: var(--action-note-icon-ink, inherit); } /* a project may colour the icon apart from the words — e.g. the system blue of the control it points at (Lh 2026-09-24) */
package/css/layover.css CHANGED
@@ -34,14 +34,16 @@
34
34
  position: absolute; /* at the stage's centre, and kept there as it grows: absolute + margin auto re-centres on every height */
35
35
  inset: 0;
36
36
  margin: auto;
37
- height: fit-content; /* inset 0 alone would stretch it to the stage: its own height, then the margins share the rest */
37
+ height: auto;
38
+ align-self: center; /* inset 0 alone would stretch it to the stage: centre self-alignment gives it its own height, the margins
39
+ share the rest. NOT `height: fit-content` — WebKit/Safari sizes it wrong (Lh 2026-09-24, iOS 18.6) */
38
40
  width: calc(100% - 2 * var(--screen-pad));
39
41
  z-index: 2; /* over the dim stage's scrim (z 1) */
40
42
  max-height: calc(100cqh - 2 * var(--sp-5)); /* cqh: the stage (a size container) */
41
43
  padding: 0; /* the parts pad themselves */
42
44
  border: 0; /* no frame on the modal (Lh 2026-09-16) — its edge is the shadow */
43
- display: grid;
44
- grid-template-rows: minmax(0, 1fr) auto;
45
+ display: flex; /* a column: the lift shrinks (and scrolls) under max-height, the drawer keeps its height. NOT a grid */
46
+ flex-direction: column; /* of minmax(0, 1fr) + auto — WebKit/Safari sizes that 1fr row to 0 (Lh 2026-09-24, iOS 18.6) */
45
47
  overflow: clip;
46
48
  box-shadow: var(--modal-shadow, var(--shadow-sheet));
47
49
  }
@@ -50,11 +52,13 @@
50
52
  display: grid;
51
53
  gap: var(--card-gap);
52
54
  align-content: start;
55
+ flex: 0 1 auto;
53
56
  min-height: 0;
54
57
  overflow-y: auto; /* tall content scrolls inside; the drawer stays */
55
58
  overscroll-behavior: contain;
56
59
  }
57
60
  .modal__drawer {
61
+ flex-shrink: 0;
58
62
  height: var(--drawer-h);
59
63
  box-sizing: border-box;
60
64
  padding: var(--modal-drawer-pad, var(--sp-5));
@@ -0,0 +1,11 @@
1
+ import type { ComponentProps } from 'react';
2
+ export interface ActionNoteProps extends ComponentProps<'div'> {
3
+ }
4
+ /**
5
+ * ActionNote — the words that stand WHERE THE MAIN BUTTON WOULD BE when there is nothing to press: a block exactly the main button's
6
+ * size (full width, `--btn-h` tall), lying on the ground — no fill, no border, no rounding — holding one line of muted words, an
7
+ * inline `Icon` allowed ("กดที่ <Icon name="share" /> ด้านล่างนี้" — the member does the thing elsewhere). It does nothing on a tap.
8
+ * A member of the BOTTOM: a `CardFoot`'s row or an `ActionBar`'s, in place of the button, never beside one; a `link` still goes under
9
+ * it (CardFoot `link`, ActionBar `ctaLink`). One fixed shape — never styled per use (Lh 2026-09-24).
10
+ */
11
+ export declare function ActionNote({ className, children, ...rest }: ActionNoteProps): import("react").JSX.Element;
@@ -0,0 +1,12 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { cx } from '../cx.js';
3
+ /**
4
+ * ActionNote — the words that stand WHERE THE MAIN BUTTON WOULD BE when there is nothing to press: a block exactly the main button's
5
+ * size (full width, `--btn-h` tall), lying on the ground — no fill, no border, no rounding — holding one line of muted words, an
6
+ * inline `Icon` allowed ("กดที่ <Icon name="share" /> ด้านล่างนี้" — the member does the thing elsewhere). It does nothing on a tap.
7
+ * A member of the BOTTOM: a `CardFoot`'s row or an `ActionBar`'s, in place of the button, never beside one; a `link` still goes under
8
+ * it (CardFoot `link`, ActionBar `ctaLink`). One fixed shape — never styled per use (Lh 2026-09-24).
9
+ */
10
+ export function ActionNote({ className, children, ...rest }) {
11
+ return _jsx("div", { role: "note", className: cx('action-note', className), ...rest, children: _jsx("span", { className: "action-note__words", children: children }) });
12
+ }
package/dist/cardds.css CHANGED
@@ -2143,6 +2143,27 @@ button { font: inherit; cursor: pointer; }
2143
2143
  its .step carries the bar's room itself, step.css.) */
2144
2144
  :has(> .action-bar) .screen:not(.screen--fill) { padding-bottom: var(--bar-reserve); }
2145
2145
 
2146
+ /* ---- action note (Lh 2026-09-24): the main button's place, the main button's size, but ON the ground — no fill, no border, no
2147
+ rounding — one line of muted words, an inline icon allowed; nothing to press. In a CardFoot or an ActionBar row it takes the
2148
+ button's share (the whole width), so a foot or a bar keeps its height whether it holds a button or the note. ---- */
2149
+ .action-note {
2150
+ flex: 1 1 0;
2151
+ min-width: 0;
2152
+ min-height: var(--btn-h);
2153
+ display: flex;
2154
+ align-items: center;
2155
+ justify-content: center;
2156
+ gap: var(--action-note-gap, var(--sp-1));
2157
+ padding-inline: var(--sp-2);
2158
+ font: var(--action-note-font, var(--type-body));
2159
+ color: var(--action-note-ink, var(--on-surface-muted));
2160
+ text-align: center;
2161
+ cursor: default;
2162
+ }
2163
+ .card .action-note { color: var(--action-note-ink, var(--card-muted)); }
2164
+ .action-note__words { display: block; } /* ONE run of words: an icon inside sits in the line, the spaces around it kept */
2165
+ .action-note__words > .icon { display: inline-block; vertical-align: -0.2em; width: 1.25em; height: 1.25em; margin-inline: 0.15em; color: var(--action-note-icon-ink, inherit); } /* a project may colour the icon apart from the words — e.g. the system blue of the control it points at (Lh 2026-09-24) */
2166
+
2146
2167
  /* ---- css/numbers.css — ring, track, band, dot grid, picker, badge, bars ---- */
2147
2168
  /* ============================================================
2148
2169
  cardds/numbers.css — big numbers inside cards:
@@ -3357,14 +3378,16 @@ button { font: inherit; cursor: pointer; }
3357
3378
  position: absolute; /* at the stage's centre, and kept there as it grows: absolute + margin auto re-centres on every height */
3358
3379
  inset: 0;
3359
3380
  margin: auto;
3360
- height: fit-content; /* inset 0 alone would stretch it to the stage: its own height, then the margins share the rest */
3381
+ height: auto;
3382
+ align-self: center; /* inset 0 alone would stretch it to the stage: centre self-alignment gives it its own height, the margins
3383
+ share the rest. NOT `height: fit-content` — WebKit/Safari sizes it wrong (Lh 2026-09-24, iOS 18.6) */
3361
3384
  width: calc(100% - 2 * var(--screen-pad));
3362
3385
  z-index: 2; /* over the dim stage's scrim (z 1) */
3363
3386
  max-height: calc(100cqh - 2 * var(--sp-5)); /* cqh: the stage (a size container) */
3364
3387
  padding: 0; /* the parts pad themselves */
3365
3388
  border: 0; /* no frame on the modal (Lh 2026-09-16) — its edge is the shadow */
3366
- display: grid;
3367
- grid-template-rows: minmax(0, 1fr) auto;
3389
+ display: flex; /* a column: the lift shrinks (and scrolls) under max-height, the drawer keeps its height. NOT a grid */
3390
+ flex-direction: column; /* of minmax(0, 1fr) + auto — WebKit/Safari sizes that 1fr row to 0 (Lh 2026-09-24, iOS 18.6) */
3368
3391
  overflow: clip;
3369
3392
  box-shadow: var(--modal-shadow, var(--shadow-sheet));
3370
3393
  }
@@ -3373,11 +3396,13 @@ button { font: inherit; cursor: pointer; }
3373
3396
  display: grid;
3374
3397
  gap: var(--card-gap);
3375
3398
  align-content: start;
3399
+ flex: 0 1 auto;
3376
3400
  min-height: 0;
3377
3401
  overflow-y: auto; /* tall content scrolls inside; the drawer stays */
3378
3402
  overscroll-behavior: contain;
3379
3403
  }
3380
3404
  .modal__drawer {
3405
+ flex-shrink: 0;
3381
3406
  height: var(--drawer-h);
3382
3407
  box-sizing: border-box;
3383
3408
  padding: var(--modal-drawer-pad, var(--sp-5));
package/dist/index.d.ts CHANGED
@@ -76,3 +76,4 @@ export * from './templates/Walkthrough.js';
76
76
  export * from './templates/Home.js';
77
77
  export * from './sheets/StackSheet.js';
78
78
  export * from './templates/CallSheet.js';
79
+ export * from './actions/ActionNote.js';
package/dist/index.js CHANGED
@@ -79,3 +79,4 @@ export * from './templates/Walkthrough.js';
79
79
  export * from './templates/Home.js';
80
80
  export * from './sheets/StackSheet.js';
81
81
  export * from './templates/CallSheet.js';
82
+ export * from './actions/ActionNote.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@usableapp/cardds",
3
- "version": "0.6.13",
3
+ "version": "0.6.15",
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.",