@usableapp/cardds 0.7.101 → 0.7.102
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 +22 -0
- package/css/base.css +20 -0
- package/css/card.css +50 -0
- package/css/choice.css +22 -0
- package/css/forms.css +15 -3
- package/css/journey.css +23 -1
- package/css/media.css +1 -10
- package/css/sheet.css +21 -1
- package/css/tokens.css +2 -2
- package/dist/cardds.css +154 -17
- package/dist/cards/Card.d.ts +25 -3
- package/dist/cards/Card.js +26 -6
- package/dist/cards/cardGo.d.ts +2 -0
- package/dist/cards/cardGo.js +5 -0
- package/dist/catalog.json +1 -1
- package/dist/choice/Calendar.js +5 -1
- package/dist/choice/CalendarWeeks.d.ts +41 -0
- package/dist/choice/CalendarWeeks.js +64 -0
- package/dist/choice/calendarDay.d.ts +13 -0
- package/dist/choice/calendarDay.js +6 -0
- package/dist/forms/Composer.d.ts +1 -1
- package/dist/forms/Composer.js +1 -1
- package/dist/forms/Field.d.ts +9 -1
- package/dist/forms/Field.js +35 -24
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/journey/JourneyBadge.d.ts +5 -2
- package/dist/journey/JourneyBadge.js +3 -3
- package/dist/media/MapArea.d.ts +10 -4
- package/dist/media/MapArea.js +8 -3
- package/dist/media/Postcard.d.ts +1 -1
- package/dist/media/Postcard.js +2 -2
- package/dist/type/Icon.d.ts +1 -1
- package/dist/type/Icon.js +1 -1
- package/dist/type/icons.d.ts +1 -1
- package/dist/type/icons.js +2 -2
- package/dist/words.d.ts +1 -1
- package/dist/words.js +2 -2
- package/icons.svg +1 -0
- package/lint/rules.mjs +2 -2
- package/package.json +1 -1
package/dist/cards/Card.d.ts
CHANGED
|
@@ -2,13 +2,17 @@ import { type ComponentProps, type MouseEvent, type ReactNode } from 'react';
|
|
|
2
2
|
import { type CardHeadProps } from './CardHead.js';
|
|
3
3
|
import { type StackPlace } from '../sheets/stackCard.js';
|
|
4
4
|
export type { StackPlace };
|
|
5
|
+
/** which side of a two-faced card shows */
|
|
6
|
+
export type CardFace = 'front' | 'back';
|
|
5
7
|
/** a card's paper: 1 (default, light) · 2 (tinted) · 3 (dark / accent — controls invert) · 4 · 5 (more colours, from the palette) */
|
|
6
8
|
export type Tone = 1 | 2 | 3 | 4 | 5;
|
|
7
9
|
export interface CardProps extends ComponentProps<'article'> {
|
|
8
10
|
/** the tone slot — see `Tone` */
|
|
9
11
|
tone?: Tone;
|
|
10
|
-
/** the content is white paper and the head keeps the card's colour
|
|
11
|
-
|
|
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`).
|
|
14
|
+
* Omit it and the content matches the head */
|
|
15
|
+
paper?: boolean | 'bands';
|
|
12
16
|
/** compact: a small card inside a card or a sheet body (a note, a promo) */
|
|
13
17
|
sm?: boolean;
|
|
14
18
|
/** a list row that is its own card: thumb · body · end, in a CardList. Its corner is the big card's PROPORTION, not its size (`--r-card-row`, 13; knob `--card-row-radius`).
|
|
@@ -53,6 +57,22 @@ export interface CardProps extends ComponentProps<'article'> {
|
|
|
53
57
|
* things; its touch target stays 44). A touch on it calls this and never picks the row. The app takes the row out of its own list. Knobs
|
|
54
58
|
* `--card-remove-size` · `--card-remove-inset` · `--card-remove-ink` · `--card-remove-bg` */
|
|
55
59
|
onRemove?: () => void;
|
|
60
|
+
/** 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
|
+
* 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
|
+
* Not on a `row`, `sm` or `stack` card */
|
|
65
|
+
back?: ReactNode;
|
|
66
|
+
/** CONTROLLED: the face that shows — pair it with `onFaceChange`. The app owns it */
|
|
67
|
+
face?: CardFace;
|
|
68
|
+
/** UNCONTROLLED: the face it starts on (default `'front'`) */
|
|
69
|
+
defaultFace?: CardFace;
|
|
70
|
+
/** a tap asked for the other face */
|
|
71
|
+
onFaceChange?: (face: CardFace) => void;
|
|
72
|
+
/** the spoken name of the front's hidden turn-over button (default: the words' `turnToBack`) */
|
|
73
|
+
toBackLabel?: string;
|
|
74
|
+
/** the spoken name of the back's hidden turn-over button (default: the words' `turnToFront`) */
|
|
75
|
+
toFrontLabel?: string;
|
|
56
76
|
/** the cross's spoken name (default: the words' `remove`) — name what goes: "Remove 'buy medicine'" */
|
|
57
77
|
removeLabel?: string;
|
|
58
78
|
}
|
|
@@ -64,8 +84,10 @@ export interface CardProps extends ComponentProps<'article'> {
|
|
|
64
84
|
* A page with one feature and one CTA may be a single card. Keep everything big.
|
|
65
85
|
* 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
|
|
66
86
|
* 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
|
+
* 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.
|
|
67
89
|
*/
|
|
68
|
-
export declare function Card({ tone, paper, sm, row, cover, fold, centre, band, as, heading, caption, end, level, foot, footLink, stack, leave, onLeft, onRemove, removeLabel, className, style, children, onClick, ref, ...rest }: CardProps): import("react").DetailedReactHTMLElement<{
|
|
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<{
|
|
69
91
|
onClick: (e: MouseEvent<HTMLElement>) => void;
|
|
70
92
|
inert?: boolean | undefined;
|
|
71
93
|
"aria-busy"?: (boolean | "true" | "false") | undefined;
|
package/dist/cards/Card.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { jsx as _jsx,
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
2
|
import { Children, createElement, isValidElement, useEffect, useLayoutEffect, useRef, useState } from 'react';
|
|
3
3
|
import { cx } from '../cx.js';
|
|
4
|
-
import { useLatest, warnOnce } from '../state.js';
|
|
4
|
+
import { useControlled, useLatest, warnOnce } from '../state.js';
|
|
5
5
|
import { CardHead } from './CardHead.js';
|
|
6
6
|
import { CardFoot } from './CardFoot.js';
|
|
7
|
-
import { goControl } from './cardGo.js';
|
|
7
|
+
import { goControl, onControl } from './cardGo.js';
|
|
8
8
|
import { Icon } from '../type/Icon.js';
|
|
9
9
|
import { word } from '../words.js';
|
|
10
10
|
import { StackHeadCtx, StackPullCtx, ownHead, stackPaint, useStackCard } from '../sheets/stackCard.js';
|
|
@@ -16,10 +16,17 @@ import { StackHeadCtx, StackPullCtx, ownHead, stackPaint, useStackCard } from '.
|
|
|
16
16
|
* A page with one feature and one CTA may be a single card. Keep everything big.
|
|
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
|
+
* 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.
|
|
19
21
|
*/
|
|
20
|
-
export function Card({ tone, paper, sm, row, cover, fold, centre, band, as = 'article', heading, caption, end, level, foot, footLink, stack, leave, onLeft, onRemove, removeLabel, 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, stack, leave, onLeft, onRemove, removeLabel, back, face, defaultFace = 'front', onFaceChange, toBackLabel, toFrontLabel, className, style, children, onClick, ref, ...rest }) {
|
|
21
23
|
if (onRemove && !row)
|
|
22
24
|
warnOnce('card-remove-row', 'cardds Card: `onRemove` draws its cross on a `row` card only');
|
|
25
|
+
if (back != null && (row || sm || stack))
|
|
26
|
+
warnOnce('card-back-kind', 'cardds Card: `back` turns a whole card — not a `row`, `sm` or `stack` card; the back is ignored');
|
|
27
|
+
const turns = back != null && !row && !sm && !stack;
|
|
28
|
+
const [shown, ask] = useControlled(face, defaultFace, onFaceChange);
|
|
29
|
+
const flipped = turns && shown === 'back';
|
|
23
30
|
const head = heading != null || caption != null || end != null;
|
|
24
31
|
const tail = foot != null || footLink != null;
|
|
25
32
|
if (head || tail) {
|
|
@@ -55,7 +62,7 @@ export function Card({ tone, paper, sm, row, cover, fold, centre, band, as = 'ar
|
|
|
55
62
|
return () => { live = false; };
|
|
56
63
|
}, [away]);
|
|
57
64
|
const [go, setGo] = useState(false);
|
|
58
|
-
useLayoutEffect(() => { setGo(own.current != null && goControl(own.current) != null); }); // every render: what the card holds is its children's
|
|
65
|
+
useLayoutEffect(() => { setGo(!turns && own.current != null && goControl(own.current) != null); }); // every render: what the card holds is its children's
|
|
59
66
|
const pressing = useRef(false);
|
|
60
67
|
const click = (e) => {
|
|
61
68
|
if (pressing.current)
|
|
@@ -63,6 +70,11 @@ export function Card({ tone, paper, sm, row, cover, fold, centre, band, as = 'ar
|
|
|
63
70
|
onClick?.(e);
|
|
64
71
|
const target = e.target;
|
|
65
72
|
const card = own.current;
|
|
73
|
+
if (turns) {
|
|
74
|
+
if (!e.defaultPrevented && card && !onControl(card, target))
|
|
75
|
+
ask(flipped ? 'front' : 'back');
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
66
78
|
if (!e.defaultPrevented && card?.contains(target)) {
|
|
67
79
|
const control = goControl(card);
|
|
68
80
|
if (control && !control.contains(target)) {
|
|
@@ -94,13 +106,21 @@ export function Card({ tone, paper, sm, row, cover, fold, centre, band, as = 'ar
|
|
|
94
106
|
const props = {
|
|
95
107
|
...rest,
|
|
96
108
|
ref: setRef,
|
|
97
|
-
className: cx('card', tone && tone !== 1 && `card--${tone}`, paper && 'sheet--paper', sm && 'card--sm', row && 'card--row', cover && 'card--cover', fold && 'card--fold', centre && 'card--centre', band && 'card--band', go && 'card--go', leaver && 'card--leaver', away && 'card--away', painted.className, className),
|
|
109
|
+
className: cx('card', tone && tone !== 1 && `card--${tone}`, paper === true && 'sheet--paper', paper === 'bands' && 'card--bands', turns && 'card--turns flip', flipped && 'is-flipped', sm && 'card--sm', row && 'card--row', cover && 'card--cover', fold && 'card--fold', centre && 'card--centre', band && 'card--band', go && 'card--go', leaver && 'card--leaver', away && 'card--away', painted.className, className),
|
|
98
110
|
style: painted.style || style ? { ...painted.style, ...style } : undefined,
|
|
99
111
|
...(stack ? { 'aria-busy': painted.busy } : {}),
|
|
100
112
|
...(away ? { inert: true } : {}),
|
|
101
113
|
onClick: click,
|
|
102
114
|
};
|
|
103
115
|
const cross = row && onRemove ? (_jsx("button", { type: "button", className: "card__remove", "aria-label": removeLabel ?? word('remove'), onClick: (e) => { e.preventDefault(); e.stopPropagation(); onRemove(); }, children: _jsx(Icon, { name: "x" }) }, "remove")) : null;
|
|
116
|
+
if (turns) {
|
|
117
|
+
const kids = Children.toArray(children);
|
|
118
|
+
const ownHeadKid = kids.find((c) => isValidElement(c) && c.type === CardHead);
|
|
119
|
+
const ownFootKid = kids.find((c) => isValidElement(c) && c.type === CardFoot);
|
|
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));
|
|
122
|
+
return createElement(as, props, inner(_jsxs(_Fragment, { children: [side('front', null), side('back', back)] })));
|
|
123
|
+
}
|
|
104
124
|
if (!head && !tail)
|
|
105
125
|
return createElement(as, props, inner(_jsxs(_Fragment, { children: [children, cross] })));
|
|
106
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] })));
|
package/dist/cards/cardGo.d.ts
CHANGED
|
@@ -1,2 +1,4 @@
|
|
|
1
1
|
/** the control this card presses when it is touched off that control, or null: the card is only read */
|
|
2
2
|
export declare function goControl(card: HTMLElement): HTMLElement | null;
|
|
3
|
+
/** the press landed on something the member presses inside this card (a Card with a `back` turns only when it did not) */
|
|
4
|
+
export declare function onControl(card: HTMLElement, target: Element): boolean;
|
package/dist/cards/cardGo.js
CHANGED
|
@@ -27,3 +27,8 @@ export function goControl(card) {
|
|
|
27
27
|
const atRowEnd = card.matches('.card--row') && card.lastElementChild === control && !control.matches('.card__remove'); // a row's cross takes it off its list: never pressed by a touch elsewhere
|
|
28
28
|
return inFoot || atRowEnd ? control : null;
|
|
29
29
|
}
|
|
30
|
+
/** the press landed on something the member presses inside this card (a Card with a `back` turns only when it did not) */
|
|
31
|
+
export function onControl(card, target) {
|
|
32
|
+
const control = target.closest(CONTROLS);
|
|
33
|
+
return control != null && control !== card && card.contains(control);
|
|
34
|
+
}
|