@usableapp/cardds 0.7.72 → 0.7.74

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.
Files changed (62) hide show
  1. package/CHANGELOG.md +37 -0
  2. package/README.md +9 -4
  3. package/bin/cardds.mjs +27 -9
  4. package/css/layover.css +4 -0
  5. package/css/people.css +6 -0
  6. package/css/stamp.css +4 -0
  7. package/dist/actions/Chip.d.ts +7 -0
  8. package/dist/actions/Dropdown.d.ts +1 -0
  9. package/dist/actions/Fab.d.ts +3 -0
  10. package/dist/actions/IconBtnGroup.d.ts +1 -0
  11. package/dist/cardds.css +14 -0
  12. package/dist/cards/Card.d.ts +2 -0
  13. package/dist/cards/CardHead.d.ts +5 -0
  14. package/dist/cards/CardHead.js +5 -5
  15. package/dist/catalog.json +1 -1
  16. package/dist/choice/Calendar.d.ts +4 -2
  17. package/dist/choice/DayStrip.d.ts +1 -0
  18. package/dist/choice/Mood.d.ts +1 -0
  19. package/dist/choice/Slider.d.ts +2 -0
  20. package/dist/forms/Composer.d.ts +2 -0
  21. package/dist/forms/Field.d.ts +2 -0
  22. package/dist/forms/FileBtn.d.ts +1 -0
  23. package/dist/journey/NoteRow.d.ts +1 -0
  24. package/dist/journey/Route.d.ts +2 -0
  25. package/dist/layover/Callout.d.ts +4 -1
  26. package/dist/lists/Kv.d.ts +3 -0
  27. package/dist/lists/Row.d.ts +3 -1
  28. package/dist/media/Mosaic.d.ts +2 -0
  29. package/dist/media/Postcard.d.ts +4 -0
  30. package/dist/media/Tile.d.ts +6 -0
  31. package/dist/numbers/Bars.d.ts +1 -0
  32. package/dist/numbers/DotGrid.d.ts +1 -0
  33. package/dist/numbers/Picker.d.ts +1 -0
  34. package/dist/numbers/Track.d.ts +1 -0
  35. package/dist/people/Avatar.d.ts +7 -2
  36. package/dist/people/Avatar.js +4 -4
  37. package/dist/people/AvatarPick.d.ts +1 -0
  38. package/dist/post/PostLetter.d.ts +5 -4
  39. package/dist/scaffold/LayerHistory.d.ts +1 -0
  40. package/dist/scaffold/Screen.d.ts +1 -0
  41. package/dist/sheets/Drawer.d.ts +1 -1
  42. package/dist/sheets/Drawer.js +1 -1
  43. package/dist/sheets/Sheet.d.ts +2 -1
  44. package/dist/sheets/Sheet.js +1 -0
  45. package/dist/sheets/SheetStack.d.ts +1 -0
  46. package/dist/sheets/SheetStack.js +1 -0
  47. package/dist/sheets/SheetSteps.d.ts +2 -2
  48. package/dist/sheets/SheetSteps.js +1 -1
  49. package/dist/sheets/StackSheet.d.ts +4 -2
  50. package/dist/sheets/StackSheet.js +1 -1
  51. package/dist/stamp/StampBook.d.ts +3 -1
  52. package/dist/stamp/StampBook.js +2 -2
  53. package/dist/templates/CallSheet.d.ts +4 -2
  54. package/dist/templates/Home.d.ts +3 -1
  55. package/dist/templates/Walkthrough.d.ts +5 -1
  56. package/lib/catalog.mjs +105 -23
  57. package/lib/guide.mjs +16 -0
  58. package/lib/mcp.mjs +25 -8
  59. package/lib/role.mjs +30 -0
  60. package/lint/eslint.mjs +2 -2
  61. package/lint/rules.mjs +74 -2
  62. package/package.json +1 -1
@@ -12,11 +12,13 @@ export interface CalendarProps extends Omit<ComponentProps<'div'>, 'title' | 'on
12
12
  defaultSelected?: number;
13
13
  /** a day was tapped */
14
14
  onSelect?: (day: number) => void;
15
- /** the head's two buttons: the app turns the month (it owns `title`, `days`, `start`) */
15
+ /** the previous-month button was tapped: the app turns the month (it owns `title`, `days`, `start`) */
16
16
  onPrev?: () => void;
17
+ /** the next-month button was tapped: the app turns the month, as with `onPrev` */
17
18
  onNext?: () => void;
18
- /** their accessible names */
19
+ /** the previous button's accessible name — cardds names it in the page's language (`<html lang>`); pass it only for different words */
19
20
  prevLabel?: string;
21
+ /** the next button's accessible name — cardds names it in the page's language (`<html lang>`); pass it only for different words */
20
22
  nextLabel?: string;
21
23
  /** softly marked days */
22
24
  marks?: number[];
@@ -8,6 +8,7 @@ export interface DayProps extends Omit<ComponentProps<'button'>, 'name'> {
8
8
  name: ReactNode;
9
9
  /** the date number */
10
10
  num: ReactNode;
11
+ /** this day is the picked one (aria-selected; the app keeps which) */
11
12
  selected?: boolean;
12
13
  /** a mark under the number (something is on) */
13
14
  dot?: boolean;
@@ -7,6 +7,7 @@ export interface MoodProps extends Omit<ComponentProps<'fieldset'>, 'onChange' |
7
7
  value?: MoodValue;
8
8
  /** UNCONTROLLED: the dot picked on arrival; the Mood then keeps its own */
9
9
  defaultValue?: MoodValue;
10
+ /** the group's accessible name (default "Mood", by `<html lang>`) */
10
11
  label?: string;
11
12
  /** the dot the member tapped */
12
13
  onChange?: (value: MoodValue) => void;
@@ -4,7 +4,9 @@ export interface SliderProps extends Omit<ComponentProps<'input'>, 'className' |
4
4
  label?: ReactNode;
5
5
  /** one sample letter IN the knob, at the type size the slider sets (a text-size slider's ก) */
6
6
  glyph?: ReactNode;
7
+ /** classes for the slider's label wrapper — the range input itself takes none */
7
8
  className?: string;
9
+ /** inline style for the label wrapper, not the range input */
8
10
  style?: React.CSSProperties;
9
11
  }
10
12
  /** Slider — one value along a hairline rail with a 48px knob; the whole range is thumb-tall. */
@@ -6,7 +6,9 @@ export interface ComposerProps extends Omit<ComponentProps<'textarea'>, 'classNa
6
6
  lead?: ReactNode;
7
7
  /** the right button of the bar (an `IconBtn invert` — send) */
8
8
  send?: ReactNode;
9
+ /** classes for the composer's wrapper, not the textarea */
9
10
  className?: string;
11
+ /** inline style for the wrapper, not the textarea */
10
12
  style?: React.CSSProperties;
11
13
  }
12
14
  /** Composer — a big write-in area (display type) with a bottom bar: icon · hint · send. The write-in step's sheet content. */
@@ -24,7 +24,9 @@ export interface FieldProps extends Omit<ComponentProps<'input'>, 'className' |
24
24
  * → 081-234-5678). Only digits are kept; a mark comes only once a digit follows it, so Backspace never sticks on a dash. The
25
25
  * app's `onChange` reads the shaped value (the digits alone: `value.replace(/\D/g, '')`). Lh 2026-09-25 */
26
26
  mask?: string;
27
+ /** classes for the field's label wrapper, not the input */
27
28
  className?: string;
29
+ /** inline style for the label wrapper, not the input */
28
30
  style?: React.CSSProperties;
29
31
  }
30
32
  /** the digits of `v`, written into `mask`; a mark is written only when a digit comes after it */
@@ -8,6 +8,7 @@ export interface FileBtnProps extends Omit<ComponentProps<'input'>, 'type' | 'cl
8
8
  block?: boolean;
9
9
  /** the button's words (and an Icon, if any) */
10
10
  children?: ReactNode;
11
+ /** classes for the button (the label around the hidden file input) */
11
12
  className?: string;
12
13
  }
13
14
  /**
@@ -1,6 +1,7 @@
1
1
  import type { ComponentProps } from 'react';
2
2
  import { type IconName } from '../type/Icon.js';
3
3
  export interface NoteRowProps extends ComponentProps<'div'> {
4
+ /** the icon before the words (default clock) */
4
5
  icon?: IconName;
5
6
  }
6
7
  /** NoteRow — icon + caption: transit hints, fine print. */
@@ -9,7 +9,9 @@ export interface RoutePoint {
9
9
  time: ReactNode;
10
10
  }
11
11
  export interface RouteProps extends ComponentProps<'div'> {
12
+ /** where it starts: place · code · time */
12
13
  from: RoutePoint;
14
+ /** where it ends: place · code · time */
13
15
  to: RoutePoint;
14
16
  /** the icon on the dotted connector (plane by default) */
15
17
  via?: IconName;
@@ -1,9 +1,12 @@
1
1
  import type { ComponentProps, ReactNode } from 'react';
2
2
  export interface CalloutProps extends Omit<ComponentProps<'div'>, 'title'> {
3
+ /** the callout's first line (a place, a name) */
3
4
  title: ReactNode;
5
+ /** a second, smaller line under the title */
4
6
  sub?: ReactNode;
5
- /** position over the stage background (CSS lengths / percentages) */
7
+ /** the callout's top edge, over the stage background (a CSS length / percentage) */
6
8
  top?: string;
9
+ /** the callout's centre line, from the left of the stage background (a CSS length / percentage) */
7
10
  left?: string;
8
11
  }
9
12
  /** Callout — a small card with a tail, pinned over a map or a media. */
@@ -19,8 +19,11 @@ export interface KvGridProps extends ComponentProps<'div'> {
19
19
  /** KvGrid — value-over-label cells split by a rule (Sex | Weight); children are KVCells. */
20
20
  export declare function KvGrid({ className, ...rest }: KvGridProps): import("react").JSX.Element;
21
21
  export interface KvCellProps extends ComponentProps<'div'> {
22
+ /** an icon before the value */
22
23
  icon?: IconName;
24
+ /** the big value */
23
25
  value: ReactNode;
26
+ /** the caption under the value */
24
27
  label: ReactNode;
25
28
  }
26
29
  /** KvCell — an icon, a big value, a caption label. */
@@ -13,8 +13,9 @@ export interface RowProps extends Omit<ComponentProps<'div'>, 'title'> {
13
13
  body?: ReactNode;
14
14
  /** the trailing control: an IconBtn, a Chip, a Check, a Toggle, a caption */
15
15
  end?: ReactNode;
16
- /** a trailing value + caption, right-aligned */
16
+ /** a trailing value, right-aligned (title type) */
17
17
  endValue?: ReactNode;
18
+ /** the muted caption under `endValue` */
18
19
  endCaption?: ReactNode;
19
20
  /** menu row: more air, a bigger title */
20
21
  lg?: boolean;
@@ -22,6 +23,7 @@ export interface RowProps extends Omit<ComponentProps<'div'>, 'title'> {
22
23
  done?: boolean;
23
24
  /** div (default), a link, a label wrapping a Check/Toggle, li */
24
25
  as?: 'div' | 'a' | 'label' | 'li';
26
+ /** makes the row a link (an `a`); not with `more`, whose row is a summary */
25
27
  href?: string;
26
28
  /** what the row EXPANDS to show under itself (who liked, the rest of a list): the row becomes a `<details>`' summary */
27
29
  more?: ReactNode;
@@ -1,10 +1,12 @@
1
1
  import type { ComponentProps } from 'react';
2
2
  export interface MosaicProps extends ComponentProps<'div'> {
3
+ /** the photos' one accessible name — the mosaic is a single `img` (default "Photos", by `<html lang>`) */
3
4
  label?: string;
4
5
  }
5
6
  /** Mosaic — one big photo + two small in a card (three Placeholders or imgs). */
6
7
  export declare function Mosaic({ label, className, ...rest }: MosaicProps): import("react").JSX.Element;
7
8
  export interface WaveProps extends ComponentProps<'span'> {
9
+ /** the waveform's accessible name (default "Voice note", by `<html lang>`) */
8
10
  label?: string;
9
11
  /** the bars' heights, 0–1, left to right — a real recording's levels; default: a mock-up shape */
10
12
  levels?: number[];
@@ -2,6 +2,7 @@ import { type ComponentProps, type ReactNode } from 'react';
2
2
  export interface PostcardProps extends ComponentProps<'div'> {
3
3
  /** the photo on the front; none = the wireframe box */
4
4
  photo?: string | null;
5
+ /** the photo's alt text; with no photo, the wireframe box's accessible name */
5
6
  alt?: string;
6
7
  /** whose card it is — the big line of the band */
7
8
  name: ReactNode;
@@ -21,8 +22,11 @@ export interface PostcardProps extends ComponentProps<'div'> {
21
22
  liked?: boolean;
22
23
  /** the heart was tapped: the state it asks for. No `liked` and no `onLike` = no heart */
23
24
  onLike?: (liked: boolean) => void;
25
+ /** the heart's accessible name (default "ถูกใจ") */
24
26
  likeLabel?: string;
27
+ /** the accessible name of the front's turn-over button (default "พลิกดูด้านหลัง") */
25
28
  frontLabel?: string;
29
+ /** the accessible name of the back's turn-over button (default "พลิกดูด้านหน้า") */
26
30
  backLabel?: string;
27
31
  }
28
32
  /**
@@ -3,6 +3,7 @@ import { type IconName } from '../type/Icon.js';
3
3
  export interface TileGridProps extends ComponentProps<'div'> {
4
4
  /** three across on a phone (attachments, upload kinds) */
5
5
  cols3?: boolean;
6
+ /** the grid takes the card's side padding back and runs to its edges (`.bleed`, card.css) */
6
7
  bleed?: boolean;
7
8
  }
8
9
  /** TileGrid — big square Tiles in a responsive grid. */
@@ -18,10 +19,15 @@ export interface TileProps extends Omit<ComponentProps<'div'>, 'onChange'> {
18
19
  sub?: ReactNode;
19
20
  /** a pick tile: a checkbox (or radio) inside, filled when checked */
20
21
  pick?: boolean;
22
+ /** what the pick tile's input is: checkbox (default) for pick-many, radio for pick-one */
21
23
  type?: 'checkbox' | 'radio';
24
+ /** the input's name (a pick tile): the radios of one choice share it (that is what makes them one group); a checkbox's is its form field */
22
25
  name?: string;
26
+ /** CONTROLLED: picked (a pick tile). The app owns it — pair it with `onChange` */
23
27
  checked?: boolean;
28
+ /** UNCONTROLLED: picked on arrival; the input then keeps its own */
24
29
  defaultChecked?: boolean;
30
+ /** the native input's change event: the tile was picked, or (checkbox) toggled */
25
31
  onChange?: React.ChangeEventHandler<HTMLInputElement>;
26
32
  /** filled accent (a static "on" tile) */
27
33
  on?: boolean;
@@ -6,6 +6,7 @@ export interface BarsProps extends ComponentProps<'div'> {
6
6
  /** Bars — three or four bars with a count on top, the glance chart; children are Bar. */
7
7
  export declare function Bars({ max, className, style, ...rest }: BarsProps): import("react").JSX.Element;
8
8
  export interface BarProps extends ComponentProps<'div'> {
9
+ /** the bar's height, against `Bars max` (the tallest bar's value) */
9
10
  value: number;
10
11
  /** the highlighted bar (accent, its count in a pill) */
11
12
  on?: boolean;
@@ -6,6 +6,7 @@ export interface DotGridProps extends ComponentProps<'div'> {
6
6
  done: number;
7
7
  /** dots per row (12) */
8
8
  cols?: number;
9
+ /** the grid's accessible name (default "{done} of {total}") */
9
10
  label?: string;
10
11
  }
11
12
  /** DotGrid — progress over time as a grid of dots, one element and three numbers (`--total`, `--done`, `--cols`). */
@@ -8,6 +8,7 @@ export interface PickerProps extends Omit<ComponentProps<'div'>, 'onChange' | 'd
8
8
  onChange?: (value: string) => void;
9
9
  /** the unit under the rail ("hours") */
10
10
  unit?: ReactNode;
11
+ /** the picker's accessible name (aria-label) */
11
12
  label?: string;
12
13
  }
13
14
  /**
@@ -1,5 +1,6 @@
1
1
  import type { ComponentProps } from 'react';
2
2
  export interface TrackProps extends ComponentProps<'ol'> {
3
+ /** the track's accessible name (default "Progress", by `<html lang>`) */
3
4
  label?: string;
4
5
  }
5
6
  /** Track — step progress in a dark pill: done · done · todo; children are TrackSteps holding an Icon each. */
@@ -15,10 +15,13 @@ export interface AvatarProps extends ComponentProps<'span'> {
15
15
  center?: boolean;
16
16
  /** a photo instead of initials */
17
17
  src?: string;
18
+ /** the photo's alt text; empty (the default) = decorative */
18
19
  alt?: string;
19
20
  /** an icon instead of initials */
20
21
  icon?: IconName;
22
+ /** the element: span (default), a when it has an `href`, or button for a tap target */
21
23
  as?: 'span' | 'a' | 'button';
24
+ /** makes the avatar a link (an `a`) */
22
25
  href?: string;
23
26
  /** the initials */
24
27
  children?: ReactNode;
@@ -310,6 +313,8 @@ export declare function Avatar({ size, outline, add, on, halo, center, src, alt,
310
313
  className: string;
311
314
  }, HTMLSpanElement>;
312
315
  export interface AvatarStackProps extends ComponentProps<'span'> {
316
+ /** the count that trails the stack ("+9"): plain text, no round, no fill, in title type — it reads at arm's length. Use it for a stack of Stamps or when the count is the point; a count that should look like one more head is `<Avatar size="sm" on>+7</Avatar>` as the last child */
317
+ more?: ReactNode;
313
318
  }
314
- /** AvatarStack — overlapping small Avatars with an optional `on` "+N" tail. */
315
- export declare function AvatarStack({ className, ...rest }: AvatarStackProps): import("react").JSX.Element;
319
+ /** AvatarStack — overlapping small Avatars, or small Stamps (`bare`), side by side; a trailing count is `more` (or an `on` Avatar as the last child). */
320
+ export declare function AvatarStack({ more, className, children, ...rest }: AvatarStackProps): import("react").JSX.Element;
@@ -1,4 +1,4 @@
1
- import { jsx as _jsx } from "react/jsx-runtime";
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { createElement } from 'react';
3
3
  import { cx } from '../cx.js';
4
4
  import { Icon } from '../type/Icon.js';
@@ -7,7 +7,7 @@ export function Avatar({ size, outline, add, on, halo, center, src, alt = '', ic
7
7
  const el = as ?? (href ? 'a' : 'span');
8
8
  return createElement(el, { href, type: el === 'button' ? 'button' : undefined, className: cx('avatar', size && `avatar--${size}`, outline && 'avatar--outline', add && 'avatar--add', on && 'avatar--on', halo && 'avatar--halo', center && 'avatar--center', className), ...rest }, src ? _jsx("img", { src: src, alt: alt }) : icon ? _jsx(Icon, { name: icon }) : children);
9
9
  }
10
- /** AvatarStack — overlapping small Avatars with an optional `on` "+N" tail. */
11
- export function AvatarStack({ className, ...rest }) {
12
- return _jsx("span", { className: cx('avatar-stack', className), ...rest });
10
+ /** AvatarStack — overlapping small Avatars, or small Stamps (`bare`), side by side; a trailing count is `more` (or an `on` Avatar as the last child). */
11
+ export function AvatarStack({ more, className, children, ...rest }) {
12
+ return (_jsxs("span", { className: cx('avatar-stack', className), ...rest, children: [children, more != null && _jsx("span", { className: "avatar-stack__more", children: more })] }));
13
13
  }
@@ -2,6 +2,7 @@ import type { ComponentProps, ReactNode } from 'react';
2
2
  export interface AvatarPickProps extends ComponentProps<'div'> {
3
3
  /** run the strip to the card's edges */
4
4
  bleed?: boolean;
5
+ /** the strip's accessible name (aria-label) */
5
6
  label?: string;
6
7
  }
7
8
  /** AvatarPick — the chooser row: big heads with name and role under, scrolling sideways; children are AvatarPickItems. */
@@ -32,14 +32,15 @@ export interface PostLetterProps extends ComponentProps<'div'> {
32
32
  sign?: ReactNode;
33
33
  /** one line under the card: the trip it made */
34
34
  journey?: ReactNode;
35
- /** the tab's words while the picture is in front (default: cardds's own, by `<html lang>`) */
35
+ /** the tab's words while the picture is in front — cardds names it in the page's language (`<html lang>`); pass it only for different words */
36
36
  backLabel?: string;
37
- /** the tab's words while the back is in front */
37
+ /** the tab's words while the back is in front — named by cardds like `backLabel`; pass it only for different words */
38
38
  pictureLabel?: string;
39
- /** the play control's names */
39
+ /** the play control's name while the note is paused — named by cardds in the page's language (`<html lang>`); pass it only for different words */
40
40
  playLabel?: string;
41
+ /** the play control's name while the note plays — named by cardds like `playLabel`; pass it only for different words */
41
42
  pauseLabel?: string;
42
- /** the small word before the name (default "To", by `<html lang>`) */
43
+ /** the small word before the name — named by cardds in the page's language (`<html lang>`); pass it only for different words */
43
44
  toLabel?: ReactNode;
44
45
  }
45
46
  /**
@@ -14,6 +14,7 @@ export interface LayerHistoryProps {
14
14
  replace: (state: EntryState, search?: LayerSearch) => void;
15
15
  /** back by this many entries (`navigate(-entries)`) */
16
16
  back: (entries: number) => void;
17
+ /** the app's screens: whatever calls `useLayer` / `useLayers` stands under it */
17
18
  children?: ReactNode;
18
19
  }
19
20
  /**
@@ -5,6 +5,7 @@ export interface ScreenProps extends ComponentProps<'div'> {
5
5
  fill?: boolean;
6
6
  /** a colour preset from palette.css; omit for the black-and-white wireframe */
7
7
  palette?: Palette;
8
+ /** the element: div (default), main for the page's landmark, or section */
8
9
  as?: 'div' | 'main' | 'section';
9
10
  /** TOP: a `TopBar` / `AppBar`, or `"lead"` — no bar, the content starts `--screen-lead` (15% of the screen) down */
10
11
  top?: ReactNode | 'lead';
@@ -15,7 +15,7 @@ export interface ModalProps extends ComponentProps<'article'> {
15
15
  * out below while the lift moves up.
16
16
  * A COMPONENT, not a wiring: it does not know its buttons. They are plain `IconBtn`s / `Btn`s with the app's `onClick` — the app
17
17
  * records the answer and sets `open={false}`; the modal's one behaviour is how it leaves. `onDismiss` asks to leave unanswered (a tap on
18
- * the scrim, Esc).
18
+ * the scrim, Esc). When it has arrived, cardds puts the cursor in the field marked `data-autofocus`, else the first field, else the question — write no focus code.
19
19
  */
20
20
  export declare function Modal({ open, onClosed, onDismiss, className, ...rest }: ModalProps): import("react").JSX.Element;
21
21
  export interface LiftProps extends ComponentProps<'div'> {
@@ -8,7 +8,7 @@ import { cx } from '../cx.js';
8
8
  * out below while the lift moves up.
9
9
  * A COMPONENT, not a wiring: it does not know its buttons. They are plain `IconBtn`s / `Btn`s with the app's `onClick` — the app
10
10
  * records the answer and sets `open={false}`; the modal's one behaviour is how it leaves. `onDismiss` asks to leave unanswered (a tap on
11
- * the scrim, Esc).
11
+ * the scrim, Esc). When it has arrived, cardds puts the cursor in the field marked `data-autofocus`, else the first field, else the question — write no focus code.
12
12
  */
13
13
  export function Modal({ open = true, onClosed, onDismiss, className, ...rest }) {
14
14
  const ref = useRef(null);
@@ -19,7 +19,7 @@ export interface SheetProps extends Omit<ComponentProps<'article'>, 'onChange'>
19
19
  onSettled?: (state: SheetState) => void;
20
20
  /** the states a drag snaps to and a reveal may climb through — "peek half full", or an array (default all four) */
21
21
  states?: string | readonly Resting[];
22
- /** the grab handle; `false` for a sheet with no handle, a string sets its accessible name */
22
+ /** the grab handle; `false` for a sheet with no handle. cardds names it in the page's language (`<html lang>`) — a string is for different words only */
23
23
  handle?: boolean | string;
24
24
  /** the grab mark. `line` (default) or `dots`: both sit in the card's top padding, the same distance from the edge, so the title does not move */
25
25
  mark?: 'line' | 'dots';
@@ -50,5 +50,6 @@ export interface SheetProps extends Omit<ComponentProps<'article'>, 'onChange'>
50
50
  * fixed habit of every sheet. A sheet asked up in the same box meanwhile waits for it: "one left, another came", never two sheets
51
51
  * crossing and never one continuous move, whatever the app's wiring (both states set in one render, or the next raised from the
52
52
  * first's `onSettled`) — the app adds no timer.
53
+ * The CURSOR is cardds's too: once it has come up it waits in the field marked `data-autofocus`, else the first field, else the heading — write no `autoFocus` or `.focus()` for it.
53
54
  */
54
55
  export declare function Sheet({ state, defaultState, onStateChange, onSettled, states, handle, mark, refreshing, tone, paper, className, children, onFocus, ...rest }: SheetProps): import("react").JSX.Element;
@@ -37,6 +37,7 @@ function markLong(node, long) {
37
37
  * fixed habit of every sheet. A sheet asked up in the same box meanwhile waits for it: "one left, another came", never two sheets
38
38
  * crossing and never one continuous move, whatever the app's wiring (both states set in one render, or the next raised from the
39
39
  * first's `onSettled`) — the app adds no timer.
40
+ * The CURSOR is cardds's too: once it has come up it waits in the field marked `data-autofocus`, else the first field, else the heading — write no `autoFocus` or `.focus()` for it.
40
41
  */
41
42
  export function Sheet({ state, defaultState = 'half', onStateChange, onSettled, states, handle = true, mark = 'line', refreshing, tone, paper, className, children, onFocus, ...rest }) {
42
43
  const [current, request] = useControlled(state, defaultState, onStateChange);
@@ -38,5 +38,6 @@ export interface SheetStackProps extends ComponentProps<'div'> {
38
38
  * the phone's back button can open and close a section. WHAT the sheet does with that, and with `refreshing`, lives on the card (`stack`):
39
39
  * the place classes, the grip, the pull. The stack only says which index. Sheets are rigid — the open one slides up, the ones after it leave
40
40
  * below, the ones before tuck under nearest-first; closing reverses in two beats. Only `translate` (stack.css); never a size.
41
+ * The CURSOR is cardds's: a sheet that opens takes it in the field marked `data-autofocus`, else the first field, else the heading — write no `autoFocus` or `.focus()` for it.
41
42
  */
42
43
  export declare function SheetStack({ mode, open, defaultOpen, onOpenChange, onRefresh, refreshing, mark, fanned, closed, rise, base, className, children, onClickCapture, onPointerDownCapture, ref: passed, ...rest }: SheetStackProps): import("react").JSX.Element;
@@ -55,6 +55,7 @@ function stamp(child, place) {
55
55
  * the phone's back button can open and close a section. WHAT the sheet does with that, and with `refreshing`, lives on the card (`stack`):
56
56
  * the place classes, the grip, the pull. The stack only says which index. Sheets are rigid — the open one slides up, the ones after it leave
57
57
  * below, the ones before tuck under nearest-first; closing reverses in two beats. Only `translate` (stack.css); never a size.
58
+ * The CURSOR is cardds's: a sheet that opens takes it in the field marked `data-autofocus`, else the first field, else the heading — write no `autoFocus` or `.focus()` for it.
58
59
  */
59
60
  export function SheetStack({ mode = 'tap', open, defaultOpen = null, onOpenChange, onRefresh, refreshing = null, mark = 'dots', fanned, closed, rise = 'under', base, className, children, onClickCapture, onPointerDownCapture, ref: passed, ...rest }) {
60
61
  const [current, request] = useControlled(open, defaultOpen, onOpenChange);
@@ -40,7 +40,7 @@ export interface SheetStepProps extends Omit<ComponentProps<'li'>, 'title'> {
40
40
  summary?: ReactNode;
41
41
  /** the member may pass this step without doing it: a small link at its end moves on (reason `skip`) */
42
42
  skippable?: boolean;
43
- /** the skip link's words (default "Skip") */
43
+ /** the skip link's words — cardds names it in the page's language (`<html lang>`); pass it only for different words */
44
44
  skipLabel?: ReactNode;
45
45
  /** what went wrong, in words — one line UNDER the step's button (an alert icon, `--signal-error`, read out at once): the number
46
46
  * is not a phone number, no signal, the code could not be sent, the two PINs differ. The step stays where it is; to send the
@@ -50,5 +50,5 @@ export interface SheetStepProps extends Omit<ComponentProps<'li'>, 'title'> {
50
50
  * step's buttons take no taps meanwhile. The app moves `at` when the answer is good, or sets `error`. */
51
51
  busy?: ReactNode;
52
52
  }
53
- /** SheetStep — one step of a SheetSteps: its title, then what the member does (a Field, a Pin, a Toggle, the step's own Btn). */
53
+ /** SheetStep — one step of a SheetSteps: its title, then what the member does (a Field, a Pin, a Toggle, the step's own Btn). When it opens, cardds puts the cursor in the field marked `data-autofocus`, else the first field, else the title — write no focus code. */
54
54
  export declare function SheetStep({ title, summary, skippable, skipLabel, error, busy, className, children, ...rest }: SheetStepProps): import("react").JSX.Element;
@@ -201,7 +201,7 @@ function useStepChecks(off, park) {
201
201
  };
202
202
  return { note, group, press };
203
203
  }
204
- /** SheetStep — one step of a SheetSteps: its title, then what the member does (a Field, a Pin, a Toggle, the step's own Btn). */
204
+ /** SheetStep — one step of a SheetSteps: its title, then what the member does (a Field, a Pin, a Toggle, the step's own Btn). When it opens, cardds puts the cursor in the field marked `data-autofocus`, else the first field, else the title — write no focus code. */
205
205
  export function SheetStep({ title, summary, skippable, skipLabel = word('skip'), error, busy, className, children, ...rest }) {
206
206
  const ctx = useContext(StepCtx);
207
207
  if (!ctx)
@@ -23,11 +23,13 @@ export interface StackSheetProps extends Omit<ComponentProps<'article'>, 'title'
23
23
  tabs?: StackSheetTab[];
24
24
  /** CONTROLLED: the tab shown (its id) — with `onTabChange`; or `defaultTab` (default: the first) */
25
25
  tab?: string;
26
+ /** UNCONTROLLED: the tab shown first (its id, default the first); the sheet then keeps its own. Pair of `tab` */
26
27
  defaultTab?: string;
28
+ /** a tab was tapped: its id */
27
29
  onTabChange?: (tab: string) => void;
28
30
  /** the SHEET FOOT: the CTA at the sheet's bottom (one row) */
29
31
  foot?: ReactNode;
30
- /** the back button's label (shown once the sheet is open) */
32
+ /** the back button's label (shown once the sheet is open) — cardds names it in the page's language (`<html lang>`); pass it only for different words */
31
33
  backLabel?: string;
32
34
  /** where the back button stands: `none` (default — hidden for now, Lh 2026-09-29: not used in real work yet; a tap on the open sheet's title folds it) ·
33
35
  * `end` (after the tabs, chevron DOWN: the sheet folds down) · `start` (before the title, chevron left) */
@@ -40,6 +42,6 @@ export interface StackSheetProps extends Omit<ComponentProps<'article'>, 'title'
40
42
  * SHEET BODY (the children; scrolls) · SHEET FOOT (`foot`, the CTA) at the bottom. Its tabs are icon buttons. The chosen one is filled
41
43
  * only while this sheet is open — a closed home shows every icon plain; the disc fades in with the rise and out with the fold.
42
44
  * A count shows as a small circle over its icon. The body is the app's: render the page of the chosen tab (and nothing while the sheet
43
- * is closed — see `Home`). A direct child of `SheetStack`.
45
+ * is closed — see `Home`). A direct child of `SheetStack`. Once open, cardds puts the cursor in the field marked `data-autofocus`, else the first field, else the heading — write no focus code.
44
46
  */
45
47
  export declare function StackSheet({ title, tone, paper, icon, tabs, tab: tabProp, defaultTab, onTabChange, foot, backLabel, backAt, stack, className, children, ...rest }: StackSheetProps): import("react").JSX.Element;
@@ -17,7 +17,7 @@ import { word } from '../words.js';
17
17
  * SHEET BODY (the children; scrolls) · SHEET FOOT (`foot`, the CTA) at the bottom. Its tabs are icon buttons. The chosen one is filled
18
18
  * only while this sheet is open — a closed home shows every icon plain; the disc fades in with the rise and out with the fold.
19
19
  * A count shows as a small circle over its icon. The body is the app's: render the page of the chosen tab (and nothing while the sheet
20
- * is closed — see `Home`). A direct child of `SheetStack`.
20
+ * is closed — see `Home`). A direct child of `SheetStack`. Once open, cardds puts the cursor in the field marked `data-autofocus`, else the first field, else the heading — write no focus code.
21
21
  */
22
22
  export function StackSheet({ title, tone, paper, icon, tabs, tab: tabProp, defaultTab, onTabChange, foot, backLabel = word('back'), backAt = 'none', stack, className, children, ...rest }) {
23
23
  const [tab, pick] = useControlled(tabProp, defaultTab ?? tabs?.[0]?.id, onTabChange);
@@ -4,9 +4,11 @@ export interface StampBookProps extends ComponentProps<'div'> {
4
4
  places?: number;
5
5
  /** ONE line of small stamps that scrolls sideways, no ground — the tray a member picks from */
6
6
  strip?: boolean;
7
+ /** the page with NO ground — no fill, no padding, no round: three stamps across fill the whole width of what holds the book, each the full width of its third (the Stamp's width cap is lifted) with the least gap that keeps them apart. Put the name INSIDE the stamp (`Stamp name`), not under it */
8
+ bare?: boolean;
7
9
  }
8
10
  /** StampBook — the album page: StampCells three across on an album ground, the free places drawn empty up to `places`. */
9
- export declare function StampBook({ places, strip, className, children, ...rest }: StampBookProps): import("react").JSX.Element;
11
+ export declare function StampBook({ places, strip, bare, className, children, ...rest }: StampBookProps): import("react").JSX.Element;
10
12
  export interface StampCellProps extends Omit<ComponentProps<'span'>, 'onClick'> {
11
13
  /** a short line under the stamp — who it is from */
12
14
  label?: ReactNode;
@@ -4,9 +4,9 @@ import { cx } from '../cx.js';
4
4
  import { Icon } from '../type/Icon.js';
5
5
  import { StampPlace } from './Stamp.js';
6
6
  /** StampBook — the album page: StampCells three across on an album ground, the free places drawn empty up to `places`. */
7
- export function StampBook({ places = 0, strip, className, children, ...rest }) {
7
+ export function StampBook({ places = 0, strip, bare, className, children, ...rest }) {
8
8
  const free = Math.max(0, places - Children.count(children));
9
- return (_jsxs("div", { className: cx('stamp-book', strip && 'stamp-book--strip', className), ...rest, children: [children, Array.from({ length: free }, (_, i) => _jsx(StampPlace, { faint: true, "aria-hidden": "true" }, i))] }));
9
+ return (_jsxs("div", { className: cx('stamp-book', strip && 'stamp-book--strip', bare && 'stamp-book--bare', className), ...rest, children: [children, Array.from({ length: free }, (_, i) => _jsx(StampPlace, { faint: true, "aria-hidden": "true" }, i))] }));
10
10
  }
11
11
  /** StampCell — one place of a StampBook: a Stamp (the child) and a short label under it. */
12
12
  export function StampCell({ label, onClick, on, className, children, ...rest }) {
@@ -10,7 +10,7 @@ export interface CallSheetSheet {
10
10
  foot?: ReactNode;
11
11
  /** a small link UNDER that button (a `Link sm`, e.g. details for developers) */
12
12
  footLink?: ReactNode;
13
- /** this sheet's handle — its accessible name (a string), or `false` for none; overrides the CallSheet's `handle` */
13
+ /** this sheet's handle: `false` for none, a string only for words different from cardds's own (named in the page's language, `<html lang>`); overrides the CallSheet's `handle` */
14
14
  handle?: SheetProps['handle'];
15
15
  }
16
16
  /** one way in: its button and the sheet it calls */
@@ -39,11 +39,13 @@ export interface CallSheetProps extends Omit<ComponentProps<typeof Screen>, 'chi
39
39
  ways?: CallSheetWay[];
40
40
  /** CONTROLLED: which way's sheet is up — an index, or null for none (`true` = the first); with `onOpenChange`; or `defaultOpen` */
41
41
  open?: number | boolean | null;
42
+ /** UNCONTROLLED: the way whose sheet is up on arrival (an index, `true` = the first, null = none); the template then keeps its own. Pair of `open` */
42
43
  defaultOpen?: number | boolean | null;
44
+ /** a sheet came up or went away: whether one is up, and which way's (its index, or null) */
43
45
  onOpenChange?: (open: boolean, way: number | null) => void;
44
46
  /** the sheets' resting states once up (default "peek full") */
45
47
  states?: string;
46
- /** every sheet's handle: its accessible name in the app's language (a string — default "Resize"), or `false` for none. A sheet's own `handle` wins */
48
+ /** every sheet's handle: `false` for none; cardds names it in the page's language (`<html lang>`), so pass a string only for different words. A sheet's own `handle` wins */
47
49
  handle?: SheetProps['handle'];
48
50
  /** layers over the screen */
49
51
  children?: ReactNode;
@@ -29,7 +29,9 @@ export interface HomeProps extends Omit<ComponentProps<typeof Screen>, 'children
29
29
  sheets: HomeSheet[];
30
30
  /** CONTROLLED: the open sheet's index, or null — with `onOpenChange`; or `defaultOpen` */
31
31
  open?: number | null;
32
+ /** UNCONTROLLED: the sheet open on arrival (its index), or null for none; the Home then keeps its own. Pair of `open` */
32
33
  defaultOpen?: number | null;
34
+ /** a sheet asks to come up or fold: the index it asks for, or null for none */
33
35
  onOpenChange?: (open: number | null) => void;
34
36
  /** the open sheet's scroller was already at the top and the finger pulled down past the commit. The stack asks with that index. It does not fetch. Omit it and a pull in the body only scrolls */
35
37
  onRefresh?: (index: number) => void;
@@ -44,7 +46,7 @@ export interface HomeProps extends Omit<ComponentProps<typeof Screen>, 'children
44
46
  base?: ReactNode;
45
47
  /** keep a sheet's body mounted after it closes (it opens again at once, scrolled where it was); default: dropped */
46
48
  keep?: boolean;
47
- /** the open sheet's back button label */
49
+ /** the open sheet's back button label — cardds names it in the page's language (`<html lang>`); pass it only for different words */
48
50
  backLabel?: string;
49
51
  /** the open sheet's back button — see `StackSheet backAt` (default `none`: hidden for now) */
50
52
  backAt?: StackSheetProps['backAt'];
@@ -15,10 +15,13 @@ export interface WalkthroughCta {
15
15
  go: (to: number) => void;
16
16
  }
17
17
  export interface WalkthroughProps extends Omit<ComponentProps<typeof Screen>, 'children' | 'fill' | 'top' | 'bottom'> {
18
+ /** the pages in order — a picture, a heading and the words each */
18
19
  pages: WalkthroughPage[];
19
20
  /** the page shown (0-based), controlled — with `onAtChange`; or `defaultAt` */
20
21
  at?: number;
22
+ /** UNCONTROLLED: the page shown on arrival (0-based, default 0); the walk then keeps its own. Pair of `at` */
21
23
  defaultAt?: number;
24
+ /** a page was turned to: its index */
22
25
  onAtChange?: (at: number) => void;
23
26
  /** the ONE row of the bottom panel. Omitted: the round pager (back · next). A function gets `{ at, count, go }`,
24
27
  * e.g. the pager until the last page, then one wide Btn. */
@@ -29,8 +32,9 @@ export interface WalkthroughProps extends Omit<ComponentProps<typeof Screen>, 'c
29
32
  ctaLink?: ReactNode;
30
33
  /** layers over the screen: the app's `SheetStage dim` + `Modal` that a link or button opens (the app wires it) */
31
34
  children?: ReactNode;
32
- /** the pager's labels */
35
+ /** the pager's back button name — cardds names it in the page's language (`<html lang>`); pass it only for different words */
33
36
  backLabel?: string;
37
+ /** the pager's next button name — cardds names it in the page's language (`<html lang>`); pass it only for different words */
34
38
  nextLabel?: string;
35
39
  }
36
40
  /**