@usableapp/cardds 0.7.103 → 0.7.105

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 (66) hide show
  1. package/CHANGELOG.md +43 -0
  2. package/css/actions.css +112 -37
  3. package/css/base.css +139 -15
  4. package/css/card.css +331 -86
  5. package/css/choice.css +25 -33
  6. package/css/finish.css +29 -28
  7. package/css/forms.css +6 -14
  8. package/css/journey.css +8 -6
  9. package/css/layover.css +26 -24
  10. package/css/lists.css +8 -6
  11. package/css/media.css +13 -74
  12. package/css/numbers.css +37 -32
  13. package/css/palette.css +2 -2
  14. package/css/people.css +3 -8
  15. package/css/post.css +23 -19
  16. package/css/sheet.css +84 -56
  17. package/css/stack.css +40 -216
  18. package/css/stamp.css +41 -29
  19. package/css/step.css +1 -107
  20. package/css/sticky.css +43 -41
  21. package/css/theme.template.css +12 -0
  22. package/css/tokens.css +101 -26
  23. package/dist/actions/Chip.d.ts +1 -1
  24. package/dist/actions/Chip.js +3 -2
  25. package/dist/actions/IconBtn.d.ts +12 -3
  26. package/dist/actions/IconBtn.js +9 -3
  27. package/dist/cardds.css +1094 -881
  28. package/dist/cards/Card.d.ts +8 -6
  29. package/dist/cards/Card.js +4 -4
  30. package/dist/cards/CardFeed.js +7 -9
  31. package/dist/cards/CardFoot.d.ts +7 -2
  32. package/dist/cards/CardFoot.js +4 -3
  33. package/dist/catalog.json +1 -1
  34. package/dist/journey/JourneyBadge.d.ts +1 -1
  35. package/dist/journey/JourneyBadge.js +1 -1
  36. package/dist/layover/Snackbar.js +2 -2
  37. package/dist/lists/Bubble.d.ts +1 -1
  38. package/dist/lists/Bubble.js +1 -1
  39. package/dist/lists/Row.js +5 -7
  40. package/dist/numbers/Picker.js +11 -18
  41. package/dist/people/Avatar.d.ts +1 -1
  42. package/dist/people/Avatar.js +3 -2
  43. package/dist/post/PostDesk.js +6 -9
  44. package/dist/post/PostLetter.js +4 -4
  45. package/dist/pressable.d.ts +9 -0
  46. package/dist/pressable.js +6 -0
  47. package/dist/room.d.ts +5 -0
  48. package/dist/room.js +9 -0
  49. package/dist/scaffold/Panes.js +8 -14
  50. package/dist/sheets/Sheet.d.ts +1 -1
  51. package/dist/sheets/Sheet.js +2 -3
  52. package/dist/sheets/SheetSteps.js +3 -3
  53. package/dist/sheets/StackSheet.d.ts +1 -1
  54. package/dist/sheets/sheetStepsPile.js +2 -3
  55. package/dist/sheets/stackCard.js +67 -115
  56. package/dist/state.d.ts +21 -0
  57. package/dist/state.js +28 -1
  58. package/dist/sticky/Sticky.js +3 -7
  59. package/dist/templates/Home.d.ts +1 -1
  60. package/dist/templates/Splash.js +2 -2
  61. package/dist/templates/Walkthrough.js +4 -5
  62. package/docs/reference.md +76 -12
  63. package/lib/catalog.mjs +23 -7
  64. package/lint/rules.mjs +7 -5
  65. package/lint/values.mjs +144 -0
  66. package/package.json +6 -4
@@ -9,8 +9,8 @@ export type Tone = 1 | 2 | 3 | 4 | 5;
9
9
  export interface CardProps extends ComponentProps<'article'> {
10
10
  /** the tone slot — see `Tone` */
11
11
  tone?: Tone;
12
- /** `true`: the content is white paper and the head keeps the card's colour (the look of `Sheet paper`). `'bands'`: the opposite, two-tone —
13
- * the head and the foot are white paper bands edge to edge, the middle between them keeps the card's tone, lightened (knob `--card-middle-bg`).
12
+ /** `true`: the content is the theme's paper (`--action-bg`, the ground of its fields) and the head keeps the card's colour (the look of `Sheet paper`). `'bands'`: the opposite, two-tone —
13
+ * the head and the foot are paper bands edge to edge, the middle between them keeps the card's tone, lightened (knob `--card-middle-bg`).
14
14
  * Omit it and the content matches the head */
15
15
  paper?: boolean | 'bands';
16
16
  /** compact: a small card inside a card or a sheet body (a note, a promo) */
@@ -43,6 +43,8 @@ export interface CardProps extends ComponentProps<'article'> {
43
43
  foot?: ReactNode;
44
44
  /** the small Link under the foot's buttons (CardFoot `link`) */
45
45
  footLink?: ReactNode;
46
+ /** the foot is a few big ROUND buttons (CardFoot `round`): `foot` holds `IconBtn`s, stood as one centred group a fixed gap apart */
47
+ footRound?: boolean;
46
48
  /** set by `SheetStack` from the app's `open` and `refreshing`. The card renders its place, its grip and its pull. Leave it unset on any other card */
47
49
  stack?: StackPlace;
48
50
  /** THE CARD LEAVES — the card floats away: up and out with a small turn, as one piece with all it holds (a stamp that has just landed on it goes with it).
@@ -59,8 +61,8 @@ export interface CardProps extends ComponentProps<'article'> {
59
61
  onRemove?: () => void;
60
62
  /** THE BACK — the card has two faces and the member turns the WHOLE card over: a tap anywhere on it that is not on a control asks for the other
61
63
  * face. The head and the foot (`heading`/`caption`/`end` or a CardHead child, `foot`) are given once and drawn on BOTH faces, so they read the same
62
- * either way; the children are the front's middle, `back` the back's. The middle is one fixed height on both faces (knob `--card-middle-h`), so the
63
- * card never changes height when it turns. The hidden face is `inert`; an `id` in the head or the foot would be drawn twice, so give it none.
64
+ * either way; the children are the front's middle, `back` the back's. The card is as tall as its taller face and each face fills it, the middle taking
65
+ * what is left, so the card never changes height when it turns (knob `--card-middle-h` fixes the middle's height instead). The hidden face is `inert`; an `id` in the head or the foot would be drawn twice, so give it none.
64
66
  * Not on a `row`, `sm` or `stack` card */
65
67
  back?: ReactNode;
66
68
  /** CONTROLLED: the face that shows — pair it with `onFaceChange`. The app owns it */
@@ -85,9 +87,9 @@ export interface CardProps extends ComponentProps<'article'> {
85
87
  * PRESSED WHOLE: a card whose ONLY control is its foot's button, or a row card's end button, is pressed anywhere — a touch off the
86
88
  * button runs that button's own action once, and the card dims under the finger. The app writes nothing; any other card is only read.
87
89
  * TWO FACES (`back`): the whole card turns over on a tap off a control (the flip mechanic it shares with Postcard); the head and the foot
88
- * read the same on both faces, the middle is one fixed height. `paper="bands"`: white head and foot bands edge to edge, the tint between.
90
+ * read the same on both faces, the middle is one fixed height. `paper="bands"`: paper head and foot bands edge to edge, the tint between.
89
91
  */
90
- export declare function Card({ tone, paper, sm, row, cover, fold, centre, band, as, heading, caption, end, level, foot, footLink, stack, leave, onLeft, onRemove, removeLabel, back, face, defaultFace, onFaceChange, toBackLabel, toFrontLabel, className, style, children, onClick, ref, ...rest }: CardProps): import("react").DetailedReactHTMLElement<{
92
+ export declare function Card({ tone, paper, sm, row, cover, fold, centre, band, as, heading, caption, end, level, foot, footLink, footRound, stack, leave, onLeft, onRemove, removeLabel, back, face, defaultFace, onFaceChange, toBackLabel, toFrontLabel, className, style, children, onClick, ref, ...rest }: CardProps): import("react").DetailedReactHTMLElement<{
91
93
  onClick: (e: MouseEvent<HTMLElement>) => void;
92
94
  inert?: boolean | undefined;
93
95
  "aria-busy"?: (boolean | "true" | "false") | undefined;
@@ -17,9 +17,9 @@ import { StackHeadCtx, StackPullCtx, ownHead, stackPaint, useStackCard } from '.
17
17
  * PRESSED WHOLE: a card whose ONLY control is its foot's button, or a row card's end button, is pressed anywhere — a touch off the
18
18
  * button runs that button's own action once, and the card dims under the finger. The app writes nothing; any other card is only read.
19
19
  * TWO FACES (`back`): the whole card turns over on a tap off a control (the flip mechanic it shares with Postcard); the head and the foot
20
- * read the same on both faces, the middle is one fixed height. `paper="bands"`: white head and foot bands edge to edge, the tint between.
20
+ * read the same on both faces, the middle is one fixed height. `paper="bands"`: paper head and foot bands edge to edge, the tint between.
21
21
  */
22
- export function Card({ tone, paper, sm, row, cover, fold, centre, band, as = 'article', heading, caption, end, level, foot, footLink, stack, leave, onLeft, onRemove, removeLabel, back, face, defaultFace = 'front', onFaceChange, toBackLabel, toFrontLabel, className, style, children, onClick, ref, ...rest }) {
22
+ export function Card({ tone, paper, sm, row, cover, fold, centre, band, as = 'article', heading, caption, end, level, foot, footLink, footRound, stack, leave, onLeft, onRemove, removeLabel, back, face, defaultFace = 'front', onFaceChange, toBackLabel, toFrontLabel, className, style, children, onClick, ref, ...rest }) {
23
23
  if (onRemove && !row)
24
24
  warnOnce('card-remove-row', 'cardds Card: `onRemove` draws its cross on a `row` card only');
25
25
  if (back != null && (row || sm || stack))
@@ -118,10 +118,10 @@ export function Card({ tone, paper, sm, row, cover, fold, centre, band, as = 'ar
118
118
  const ownHeadKid = kids.find((c) => isValidElement(c) && c.type === CardHead);
119
119
  const ownFootKid = kids.find((c) => isValidElement(c) && c.type === CardFoot);
120
120
  const front = kids.filter((c) => c !== ownHeadKid && c !== ownFootKid);
121
- const side = (which, middle) => (_jsxs("div", { className: cx('card__face flip__face', `flip__face--${which}`), ...((which === 'back') !== flipped ? { inert: true } : {}), children: [_jsx("button", { type: "button", className: "card__turn", "aria-label": which === 'front' ? toBackLabel ?? word('turnToBack') : toFrontLabel ?? word('turnToFront'), onClick: () => ask(which === 'front' ? 'back' : 'front') }), head ? _jsx(CardHead, { heading: heading, caption: caption, end: end, level: level }) : ownHeadKid, _jsx("div", { className: "card__middle", children: which === 'front' ? front : middle }), tail ? _jsx(CardFoot, { link: footLink, children: foot }) : ownFootKid] }, which));
121
+ const side = (which, middle) => (_jsxs("div", { className: cx('card__face flip__face', `flip__face--${which}`), ...((which === 'back') !== flipped ? { inert: true } : {}), children: [_jsx("button", { type: "button", className: "card__turn", "aria-label": which === 'front' ? toBackLabel ?? word('turnToBack') : toFrontLabel ?? word('turnToFront'), onClick: () => ask(which === 'front' ? 'back' : 'front') }), head ? _jsx(CardHead, { heading: heading, caption: caption, end: end, level: level }) : ownHeadKid, _jsx("div", { className: "card__middle", children: which === 'front' ? front : middle }), tail ? _jsx(CardFoot, { link: footLink, round: footRound, children: foot }) : ownFootKid] }, which));
122
122
  return createElement(as, props, inner(_jsxs(_Fragment, { children: [side('front', null), side('back', back)] })));
123
123
  }
124
124
  if (!head && !tail)
125
125
  return createElement(as, props, inner(_jsxs(_Fragment, { children: [children, cross] })));
126
- return createElement(as, props, inner(_jsxs(_Fragment, { children: [head && _jsx(CardHead, { heading: heading, caption: caption, end: end, level: level }, "head"), Children.toArray(children), tail && _jsx(CardFoot, { link: footLink, children: foot }, "foot"), cross] })));
126
+ return createElement(as, props, inner(_jsxs(_Fragment, { children: [head && _jsx(CardHead, { heading: heading, caption: caption, end: end, level: level }, "head"), Children.toArray(children), tail && _jsx(CardFoot, { link: footLink, round: footRound, children: foot }, "foot"), cross] })));
127
127
  }
@@ -1,7 +1,7 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { Children, createContext, isValidElement, useContext, useEffect, useId, useLayoutEffect, useRef } from 'react';
3
3
  import { cx } from '../cx.js';
4
- import { reducedMotion, setRefs, useControlled, warnOnce } from '../state.js';
4
+ import { glide, reducedMotion, setRefs, sheetMs, stopMoves, useControlled, warnOnce } from '../state.js';
5
5
  import { Card } from './Card.js';
6
6
  import { CardHead } from './CardHead.js';
7
7
  import { CardFoot } from './CardFoot.js';
@@ -45,19 +45,17 @@ export function CardFeed({ big: bigProp, defaultBig, onBigChange, onMore, ahead
45
45
  if (changed) {
46
46
  if (!kept && ids.length)
47
47
  request(ids[0], 'queue');
48
- els.forEach((el) => el.getAnimations().forEach((a) => { if (a.id === 'feed-move')
49
- a.cancel(); })); // read the resting places
48
+ stopMoves(els, 'feed-move'); // read the resting places
50
49
  }
51
50
  const at = new Map(els.map((el) => [el, el.offsetTop]));
52
51
  if (changed && box && !reducedMotion()) {
53
- const ms = (parseFloat(getComputedStyle(box).getPropertyValue('--motion-sheet')) || 0.35) * 1000;
52
+ const cs = getComputedStyle(box), arrive = cs.getPropertyValue('--ease-out').trim() || 'ease-out';
54
53
  for (const el of els) {
55
54
  const from = tops.current.get(el);
56
- const move = from === undefined
57
- ? el.animate([{ opacity: 0 }, { opacity: 1 }], { duration: ms, easing: 'ease-out' }) // it came in: no place to come from
58
- : from !== at.get(el) ? el.animate([{ translate: `0 ${from - (at.get(el) ?? 0)}px` }, { translate: '0 0' }], { duration: ms, easing: 'cubic-bezier(0.2, 0.8, 0.2, 1)' }) : null;
59
- if (move)
60
- move.id = 'feed-move';
55
+ if (from === undefined)
56
+ el.animate([{ opacity: 0 }, { opacity: 1 }], { duration: sheetMs(cs), easing: arrive }).id = 'feed-move'; // it came in: no place to come from
57
+ else if (from !== at.get(el))
58
+ glide(el, from - (at.get(el) ?? 0), cs, 'feed-move');
61
59
  }
62
60
  }
63
61
  tops.current = at;
@@ -3,8 +3,13 @@ export interface CardFootProps extends ComponentProps<'div'> {
3
3
  /** a SMALL LINK under the buttons, centred on its own short row (a `Link sm` — "details for developers") — the same as an
4
4
  * ActionBar's ctaLink (Lh 2026-09-23). It never takes a share of the buttons' line */
5
5
  link?: ReactNode;
6
+ /** a foot of a few ROUND buttons (`IconBtn`, a size `lg` / `xl` for the big ones): they keep their own size instead of sharing the line, and
7
+ * stand as ONE group in the middle of the foot, a fixed gap apart (wider than the Btns' — `--card-foot-gap` sets it). The Btn foot is
8
+ * unchanged: this is the other foot, for a few big round answers */
9
+ round?: boolean;
6
10
  }
7
11
  /** CardFoot — the card's action buttons on one line: one takes the width, up to four share it evenly. Btns only in the row; a small
8
12
  * link goes in `link`, under it. A `Btn form` keeps its own size here: as wide as its words, centred — for a foot whose one button
9
- * should not fill the card. */
10
- export declare function CardFoot({ link, className, children, ...rest }: CardFootProps): import("react").JSX.Element;
13
+ * should not fill the card. With `round` it is the foot of a few round `IconBtn`s (`size="xl"`, one `primary` with a word, the others
14
+ * with icons): one centred group, a fixed gap between them. */
15
+ export declare function CardFoot({ link, round, className, children, ...rest }: CardFootProps): import("react").JSX.Element;
@@ -2,7 +2,8 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { cx } from '../cx.js';
3
3
  /** CardFoot — the card's action buttons on one line: one takes the width, up to four share it evenly. Btns only in the row; a small
4
4
  * link goes in `link`, under it. A `Btn form` keeps its own size here: as wide as its words, centred — for a foot whose one button
5
- * should not fill the card. */
6
- export function CardFoot({ link, className, children, ...rest }) {
7
- return (_jsxs("div", { className: cx('card__foot', link != null && 'card__foot--link', className), ...rest, children: [children, link != null && _jsx("div", { className: "card__foot-link", children: link })] }));
5
+ * should not fill the card. With `round` it is the foot of a few round `IconBtn`s (`size="xl"`, one `primary` with a word, the others
6
+ * with icons): one centred group, a fixed gap between them. */
7
+ export function CardFoot({ link, round, className, children, ...rest }) {
8
+ return (_jsxs("div", { className: cx('card__foot', link != null && 'card__foot--link', round && 'card__foot--round', className), ...rest, children: [children, link != null && _jsx("div", { className: "card__foot-link", children: link })] }));
8
9
  }