@usableapp/cardds 0.7.15 → 0.7.17
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 +53 -0
- package/README.md +29 -28
- package/cardds.css +3 -3
- package/css/actions.css +67 -22
- package/css/base.css +44 -18
- package/css/card.css +25 -26
- package/css/choice.css +21 -33
- package/css/forms.css +0 -3
- package/css/journey.css +1 -3
- package/css/layover.css +19 -41
- package/css/lists.css +1 -6
- package/css/media.css +9 -18
- package/css/numbers.css +6 -21
- package/css/people.css +3 -9
- package/css/sheet.css +15 -19
- package/css/stack.css +21 -29
- package/css/step.css +7 -12
- package/css/theme.template.css +2 -1
- package/css/tokens.css +22 -4
- package/dist/actions/Btn.d.ts +1 -1
- package/dist/actions/Dropdown.js +3 -9
- package/dist/actions/Fab.d.ts +1 -1
- package/dist/actions/Fab.js +3 -2
- package/dist/cardds.css +264 -267
- package/dist/cards/Card.d.ts +24 -8
- package/dist/cards/Card.js +23 -8
- package/dist/cards/CardHead.d.ts +0 -1
- package/dist/cards/CardHead.js +1 -1
- package/dist/choice/Calendar.js +2 -5
- package/dist/choice/Mood.d.ts +10 -5
- package/dist/choice/Mood.js +4 -2
- package/dist/forms/Field.js +2 -3
- package/dist/forms/FileBtn.js +1 -1
- package/dist/forms/Pin.js +7 -12
- package/dist/index.d.ts +1 -1
- package/dist/index.js +3 -3
- package/dist/layover/Banner.d.ts +10 -3
- package/dist/layover/Banner.js +6 -3
- package/dist/lists/Row.d.ts +2 -1
- package/dist/lists/Row.js +5 -5
- package/dist/media/Postcard.js +3 -5
- package/dist/numbers/Band.d.ts +3 -1
- package/dist/numbers/Picker.js +3 -10
- package/dist/numbers/Track.d.ts +4 -2
- package/dist/numbers/Track.js +3 -3
- package/dist/people/AvatarPick.d.ts +3 -1
- package/dist/people/AvatarPick.js +2 -2
- package/dist/scaffold/ActionBar.d.ts +3 -3
- package/dist/scaffold/ActionBar.js +2 -2
- package/dist/scaffold/Centre.d.ts +2 -2
- package/dist/scaffold/Centre.js +2 -2
- package/dist/scaffold/PagerAt.d.ts +1 -1
- package/dist/scaffold/PagerAt.js +1 -1
- package/dist/scaffold/Screen.js +4 -7
- package/dist/scaffold/TopBar.js +3 -5
- package/dist/sheets/Drawer.js +3 -4
- package/dist/sheets/Sheet.js +9 -22
- package/dist/sheets/SheetStack.d.ts +2 -2
- package/dist/sheets/SheetStack.js +20 -13
- package/dist/sheets/SheetSteps.js +8 -11
- package/dist/sheets/StackBack.js +2 -1
- package/dist/sheets/StackSheet.d.ts +3 -2
- package/dist/sheets/StackSheet.js +7 -11
- package/dist/state.d.ts +24 -0
- package/dist/state.js +57 -0
- package/dist/templates/CallSheet.js +2 -4
- package/dist/templates/Home.d.ts +3 -2
- package/dist/templates/Home.js +2 -4
- package/dist/templates/Splash.js +3 -3
- package/dist/templates/Walkthrough.js +4 -5
- package/dist/type/Icon.js +3 -5
- package/dist/type/Text.d.ts +1 -1
- package/dist/type/textScale.d.ts +6 -0
- package/dist/type/textScale.js +12 -0
- package/package.json +7 -4
- package/dist/layover/Deck.d.ts +0 -9
- package/dist/layover/Deck.js +0 -10
package/dist/cards/Card.d.ts
CHANGED
|
@@ -1,14 +1,17 @@
|
|
|
1
|
-
import { type ComponentProps } from 'react';
|
|
1
|
+
import { type ComponentProps, type ReactNode } from 'react';
|
|
2
|
+
import { type CardHeadProps } from './CardHead.js';
|
|
3
|
+
/** a card's paper: 1 (default, light) · 2 (tinted) · 3 (dark / accent — controls invert) · 4 · 5 (more colours, from the palette) */
|
|
4
|
+
export type Tone = 1 | 2 | 3 | 4 | 5;
|
|
2
5
|
export interface CardProps extends ComponentProps<'article'> {
|
|
3
|
-
/** the tone slot
|
|
4
|
-
tone?:
|
|
6
|
+
/** the tone slot — see `Tone` */
|
|
7
|
+
tone?: Tone;
|
|
5
8
|
/** compact: a small card inside a card or a sheet body (a note, a promo) */
|
|
6
9
|
sm?: boolean;
|
|
7
10
|
/** a list row that is its own card: thumb · body · end, in a CardList */
|
|
8
11
|
row?: boolean;
|
|
9
12
|
/** the image IS the card: a Placeholder or img first, text over a scrim */
|
|
10
13
|
cover?: boolean;
|
|
11
|
-
/** a sticky-note corner, no border (
|
|
14
|
+
/** a sticky-note corner, no border (quotes) */
|
|
12
15
|
fold?: boolean;
|
|
13
16
|
/** one card at the human centre of a `Screen fill` (the introduction screens) */
|
|
14
17
|
centre?: boolean;
|
|
@@ -17,14 +20,28 @@ export interface CardProps extends ComponentProps<'article'> {
|
|
|
17
20
|
/** the element: article (default), a when it links, label when it wraps an input, div/section */
|
|
18
21
|
as?: 'article' | 'div' | 'a' | 'label' | 'section' | 'li';
|
|
19
22
|
href?: string;
|
|
23
|
+
/** THE HEAD, filled in place: the heading (wraps freely) — the card writes its CardHead first. For a head of your own shape
|
|
24
|
+
* (a chip before the words, a tile badge) write `<CardHead>` as the first child instead, and leave these out */
|
|
25
|
+
heading?: ReactNode;
|
|
26
|
+
/** the muted line under the heading */
|
|
27
|
+
caption?: ReactNode;
|
|
28
|
+
/** the head's far-right thing: a Chip, an IconBtn, a Badge, a small Ring */
|
|
29
|
+
end?: ReactNode;
|
|
30
|
+
/** the heading's level (h2 default; h1 for the one-feature page) */
|
|
31
|
+
level?: CardHeadProps['level'];
|
|
32
|
+
/** THE FOOT, filled in place: its Btns (≤4, one line) — the card writes its CardFoot last */
|
|
33
|
+
foot?: ReactNode;
|
|
34
|
+
/** the small Link under the foot's buttons (CardFoot `link`) */
|
|
35
|
+
footLink?: ReactNode;
|
|
20
36
|
}
|
|
21
37
|
/**
|
|
22
38
|
* Card — ONE boundary: head · content · foot. Cards are content the system offers (the words, the thing to read).
|
|
23
|
-
*
|
|
24
|
-
*
|
|
39
|
+
* The head and the foot are SLOTS: `heading` · `caption` · `end` (the card writes its CardHead first) and `foot` · `footLink`
|
|
40
|
+
* (its CardFoot last); the children are the content between them (frameless rows, kv, a ring, a paragraph — never a second card
|
|
41
|
+
* boundary). The order is the card's, never the writer's. A head of its own shape: write `<CardHead>` as the first child instead.
|
|
25
42
|
* A page with one feature and one CTA may be a single card. Keep everything big.
|
|
26
43
|
*/
|
|
27
|
-
export declare function Card({ tone, sm, row, cover, fold, centre, band, as, className, ...rest }: CardProps): import("react").DetailedReactHTMLElement<{
|
|
44
|
+
export declare function Card({ tone, sm, row, cover, fold, centre, band, as, heading, caption, end, level, foot, footLink, className, children, ...rest }: CardProps): import("react").DetailedReactHTMLElement<{
|
|
28
45
|
href?: string;
|
|
29
46
|
ref?: import("react").Ref<HTMLElement> | undefined;
|
|
30
47
|
key?: import("react").Key | null | undefined;
|
|
@@ -135,7 +152,6 @@ export declare function Card({ tone, sm, row, cover, fold, centre, band, as, cla
|
|
|
135
152
|
"aria-valuemin"?: number | undefined;
|
|
136
153
|
"aria-valuenow"?: number | undefined;
|
|
137
154
|
"aria-valuetext"?: string | undefined;
|
|
138
|
-
children?: import("react").ReactNode | undefined;
|
|
139
155
|
dangerouslySetInnerHTML?: {
|
|
140
156
|
__html: string | TrustedHTML;
|
|
141
157
|
} | undefined;
|
package/dist/cards/Card.js
CHANGED
|
@@ -1,14 +1,29 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { Children, createElement, isValidElement } from 'react';
|
|
2
3
|
import { cx } from '../cx.js';
|
|
4
|
+
import { warnOnce } from '../state.js';
|
|
5
|
+
import { CardHead } from './CardHead.js';
|
|
6
|
+
import { CardFoot } from './CardFoot.js';
|
|
3
7
|
/**
|
|
4
8
|
* Card — ONE boundary: head · content · foot. Cards are content the system offers (the words, the thing to read).
|
|
5
|
-
*
|
|
6
|
-
*
|
|
9
|
+
* The head and the foot are SLOTS: `heading` · `caption` · `end` (the card writes its CardHead first) and `foot` · `footLink`
|
|
10
|
+
* (its CardFoot last); the children are the content between them (frameless rows, kv, a ring, a paragraph — never a second card
|
|
11
|
+
* boundary). The order is the card's, never the writer's. A head of its own shape: write `<CardHead>` as the first child instead.
|
|
7
12
|
* A page with one feature and one CTA may be a single card. Keep everything big.
|
|
8
13
|
*/
|
|
9
|
-
export function Card({ tone, sm, row, cover, fold, centre, band, as = 'article', className, ...rest }) {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
+
export function Card({ tone, sm, row, cover, fold, centre, band, as = 'article', heading, caption, end, level, foot, footLink, className, children, ...rest }) {
|
|
15
|
+
const head = heading != null || caption != null || end != null;
|
|
16
|
+
const tail = foot != null || footLink != null;
|
|
17
|
+
if (head || tail) {
|
|
18
|
+
const parts = Children.toArray(children).filter(isValidElement); // dev hint only
|
|
19
|
+
if (head && parts.some((c) => c.type === CardHead))
|
|
20
|
+
warnOnce('card-head-twice', 'cardds Card: `heading`/`caption`/`end` AND a <CardHead> child — one head per card; use one way');
|
|
21
|
+
if (tail && parts.some((c) => c.type === CardFoot))
|
|
22
|
+
warnOnce('card-foot-twice', 'cardds Card: `foot`/`footLink` AND a <CardFoot> child — one foot per card; use one way');
|
|
23
|
+
}
|
|
24
|
+
const props = { className: cx('card', tone && tone !== 1 && `card--${tone}`, sm && 'card--sm', row && 'card--row', cover && 'card--cover', fold && 'card--fold', centre && 'card--centre', band && 'card--band', className), ...rest };
|
|
25
|
+
if (!head && !tail)
|
|
26
|
+
return createElement(as, props, children);
|
|
27
|
+
return createElement(as, props, head && _jsx(CardHead, { heading: heading, caption: caption, end: end, level: level }, "head"), ...Children.toArray(children), // keyed: the slots sit around them
|
|
28
|
+
tail && _jsx(CardFoot, { link: footLink, children: foot }, "foot"));
|
|
14
29
|
}
|
package/dist/cards/CardHead.d.ts
CHANGED
|
@@ -2,7 +2,6 @@ import type { ComponentProps, ReactNode } from 'react';
|
|
|
2
2
|
export interface CardHeadProps extends ComponentProps<'div'> {
|
|
3
3
|
/** the heading (a string becomes an h2 at level `t-h2`) — wraps freely, as many lines as the words need */
|
|
4
4
|
heading?: ReactNode;
|
|
5
|
-
/** small caps above the heading ("Step 1 of 4", "Time bank") */
|
|
6
5
|
/** the muted line under the heading (a date, a subtitle) */
|
|
7
6
|
caption?: ReactNode;
|
|
8
7
|
/** the contextual thing at the far right: a chip, an IconBtn (more), a Link, a small Ring, an Avatar, a Badge (a count in a stack head) */
|
package/dist/cards/CardHead.js
CHANGED
|
@@ -7,5 +7,5 @@ import { cx } from '../cx.js';
|
|
|
7
7
|
*/
|
|
8
8
|
export function CardHead({ heading, caption, end, top, level = 'h2', className, children, ...rest }) {
|
|
9
9
|
const H = level === 'h1' ? 'h1' : 'h2';
|
|
10
|
-
return (_jsxs("div", { className: cx('card__head', top && 'card__head--top', className), ...rest, children: [heading != null && _jsx(H, { className:
|
|
10
|
+
return (_jsxs("div", { className: cx('card__head', top && 'card__head--top', className), ...rest, children: [heading != null && _jsx(H, { className: `t-${level}`, children: heading }), caption != null && _jsx("span", { className: "t-caption t-muted", children: caption }), children, end] }));
|
|
11
11
|
}
|
package/dist/choice/Calendar.js
CHANGED
|
@@ -1,13 +1,10 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import {
|
|
2
|
+
import { useControlled } from '../state.js';
|
|
3
3
|
import { cx } from '../cx.js';
|
|
4
4
|
import { IconBtn } from '../actions/IconBtn.js';
|
|
5
5
|
/** Calendar — a month grid of 44px round cells: one accent day, optional marks; prev/next in the head. It shows ONE month and knows no dates:
|
|
6
6
|
* the app owns which month (`title`, `days`, `start` + `onPrev` / `onNext`) and which day (`selected` + `onSelect`, or `defaultSelected`). */
|
|
7
7
|
export function Calendar({ title, days = 30, start = 1, selected, defaultSelected, onSelect, onPrev, onNext, prevLabel = 'Previous', nextLabel = 'Next', marks = [], marks2 = [], disabled = [], weekdays = ['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa'], nav, className, ...rest }) {
|
|
8
|
-
const [
|
|
9
|
-
const day = selected !== undefined ? selected : inner;
|
|
10
|
-
const pick = (d) => { if (selected === undefined)
|
|
11
|
-
setInner(d); onSelect?.(d); };
|
|
8
|
+
const [day, pick] = useControlled(selected, defaultSelected, onSelect);
|
|
12
9
|
return (_jsxs("div", { className: cx('calendar', className), ...rest, children: [_jsxs("div", { className: "calendar__head", children: [_jsx("span", { className: "t-title", children: title }), nav ?? (_jsxs("span", { className: "icon-row", children: [_jsx(IconBtn, { sm: true, icon: "chevron-left", label: prevLabel, onClick: onPrev }), _jsx(IconBtn, { sm: true, icon: "chevron-right", label: nextLabel, onClick: onNext })] }))] }), _jsxs("div", { className: "calendar__grid", children: [weekdays.map((d) => _jsx("span", { className: "calendar__wd", children: d }, d)), Array.from({ length: days }, (_, i) => i + 1).map((d) => (_jsx("button", { type: "button", className: cx('calendar__day', marks.includes(d) && 'calendar__day--mark', marks2.includes(d) && 'calendar__day--mark2'), "aria-selected": d === day ? 'true' : undefined, onClick: () => pick(d), disabled: disabled.includes(d), style: d === 1 ? { '--start': start } : undefined, children: d }, d)))] })] }));
|
|
13
10
|
}
|
package/dist/choice/Mood.d.ts
CHANGED
|
@@ -1,11 +1,16 @@
|
|
|
1
1
|
import type { ComponentProps } from 'react';
|
|
2
|
-
|
|
2
|
+
type MoodValue = 1 | 2 | 3 | 4 | 5;
|
|
3
|
+
export interface MoodProps extends Omit<ComponentProps<'fieldset'>, 'onChange' | 'defaultValue'> {
|
|
3
4
|
/** the radio group name */
|
|
4
5
|
name?: string;
|
|
5
|
-
/** the picked dot, 1 (worst) to 5 (best) */
|
|
6
|
-
value?:
|
|
6
|
+
/** CONTROLLED: the picked dot, 1 (worst) to 5 (best) — with `onChange`; or `defaultValue` */
|
|
7
|
+
value?: MoodValue;
|
|
8
|
+
/** UNCONTROLLED: the dot picked on arrival; the Mood then keeps its own */
|
|
9
|
+
defaultValue?: MoodValue;
|
|
7
10
|
label?: string;
|
|
8
|
-
|
|
11
|
+
/** the dot the member tapped */
|
|
12
|
+
onChange?: (value: MoodValue) => void;
|
|
9
13
|
}
|
|
10
14
|
/** Mood — five dots in a pill from bad to good; the picked one grows. */
|
|
11
|
-
export declare function Mood({ name, value, label, onChange, className, ...rest }: MoodProps): import("react").JSX.Element;
|
|
15
|
+
export declare function Mood({ name, value, defaultValue, label, onChange, className, ...rest }: MoodProps): import("react").JSX.Element;
|
|
16
|
+
export {};
|
package/dist/choice/Mood.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { cx } from '../cx.js';
|
|
3
|
+
import { useControlled } from '../state.js';
|
|
3
4
|
/** Mood — five dots in a pill from bad to good; the picked one grows. */
|
|
4
|
-
export function Mood({ name = 'mood', value, label = 'Mood', onChange, className, ...rest }) {
|
|
5
|
-
|
|
5
|
+
export function Mood({ name = 'mood', value, defaultValue, label = 'Mood', onChange, className, ...rest }) {
|
|
6
|
+
const [picked, pick] = useControlled(value, defaultValue, onChange);
|
|
7
|
+
return (_jsx("fieldset", { className: cx('mood', className), "aria-label": label, ...rest, children: [1, 2, 3, 4, 5].map((n) => (_jsxs("label", { className: "mood__opt", children: [_jsx("input", { type: "radio", name: name, value: n, checked: n === picked, onChange: () => pick(n) }), _jsx("span", { className: "mood__dot" })] }, n))) }));
|
|
6
8
|
}
|
package/dist/forms/Field.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { useEffect, useLayoutEffect, useRef, useState } from 'react';
|
|
3
|
+
import { watchSize } from '../state.js';
|
|
3
4
|
import { formatOk, useCheck } from './check.js';
|
|
4
5
|
import { cx } from '../cx.js';
|
|
5
6
|
import { Icon } from '../type/Icon.js';
|
|
@@ -59,10 +60,8 @@ export function Field({ icon, action, label, error, format, digits, formatError,
|
|
|
59
60
|
el.style.removeProperty('--_ph-fit');
|
|
60
61
|
};
|
|
61
62
|
fit();
|
|
62
|
-
const ro = new ResizeObserver(fit);
|
|
63
|
-
ro.observe(el);
|
|
64
63
|
document.fonts?.ready.then(fit);
|
|
65
|
-
return (
|
|
64
|
+
return watchSize([el], fit);
|
|
66
65
|
}, [input.placeholder]);
|
|
67
66
|
useEffect(() => {
|
|
68
67
|
if (wrong) {
|
package/dist/forms/FileBtn.js
CHANGED
|
@@ -6,5 +6,5 @@ import { cx } from '../cx.js';
|
|
|
6
6
|
* opens the camera; without `capture` the gallery. The picked file arrives in `onChange` like any input.
|
|
7
7
|
*/
|
|
8
8
|
export function FileBtn({ primary, quiet, block, className, children, ...input }) {
|
|
9
|
-
return (_jsxs("label", { className: cx('btn', primary && 'btn--primary', quiet && 'btn--quiet', block && 'btn--block', className), children: [_jsx("input", { type: "file",
|
|
9
|
+
return (_jsxs("label", { className: cx('btn', primary && 'btn--primary', quiet && 'btn--quiet', block && 'btn--block', className), children: [_jsx("input", { type: "file", className: "t-sr", ...input }), children] }));
|
|
10
10
|
}
|
package/dist/forms/Pin.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import { useEffect, useRef, useState } from 'react';
|
|
3
|
+
import { useControlled, useLatest } from '../state.js';
|
|
3
4
|
import { cx } from '../cx.js';
|
|
4
5
|
import { useCheck } from './check.js';
|
|
5
6
|
const RESET_MS = 900; // a code that does not match: red + shake this long, then the cells empty for a new try
|
|
@@ -11,23 +12,20 @@ const RESET_MS = 900; // a code that does not match: red + shake this long, then
|
|
|
11
12
|
*/
|
|
12
13
|
export function Pin({ length = 6, value, defaultValue = '', label = 'Digit', onChange, autoFocus, error, match, formatError, secret, className, onAnimationEnd, ...rest }) {
|
|
13
14
|
const ref = useRef(null);
|
|
14
|
-
const [
|
|
15
|
-
const code =
|
|
15
|
+
const [typed, request] = useControlled(value, defaultValue, onChange);
|
|
16
|
+
const code = typed.replace(/\D/g, '').slice(0, length);
|
|
16
17
|
const cell = (i) => ref.current?.querySelectorAll('.pin__cell')[i];
|
|
17
18
|
/* a miss — a match that failed, or the app's error: shake, red, then the cells empty for a new try on the same step */
|
|
18
|
-
const latest =
|
|
19
|
-
latest.current = { value, onChange, error };
|
|
19
|
+
const latest = useLatest(error);
|
|
20
20
|
const miss = () => {
|
|
21
21
|
restart.current = true;
|
|
22
22
|
setShake(true);
|
|
23
23
|
clearTimeout(reset.current);
|
|
24
24
|
reset.current = setTimeout(() => {
|
|
25
25
|
setBad(false);
|
|
26
|
-
setCleared(latest.current
|
|
26
|
+
setCleared(latest.current);
|
|
27
27
|
restart.current = false;
|
|
28
|
-
|
|
29
|
-
setInner('');
|
|
30
|
-
latest.current.onChange?.('', false);
|
|
28
|
+
request('', false);
|
|
31
29
|
cell(0)?.focus();
|
|
32
30
|
}, RESET_MS);
|
|
33
31
|
};
|
|
@@ -46,10 +44,7 @@ export function Pin({ length = 6, value, defaultValue = '', label = 'Digit', onC
|
|
|
46
44
|
said.current = true;
|
|
47
45
|
miss();
|
|
48
46
|
}
|
|
49
|
-
|
|
50
|
-
setInner(next);
|
|
51
|
-
if (next !== code)
|
|
52
|
-
onChange?.(next, next.length === length);
|
|
47
|
+
request(next, next.length === length);
|
|
53
48
|
};
|
|
54
49
|
useEffect(() => {
|
|
55
50
|
if (autoFocus)
|
package/dist/index.d.ts
CHANGED
|
@@ -4,6 +4,7 @@ export { cx } from './cx.js';
|
|
|
4
4
|
export * from './type/Icon.js';
|
|
5
5
|
export { ICON_NAMES } from './type/icons.js';
|
|
6
6
|
export * from './type/Text.js';
|
|
7
|
+
export { setTextScale } from './type/textScale.js';
|
|
7
8
|
export * from './scaffold/Screen.js';
|
|
8
9
|
export * from './scaffold/AppBar.js';
|
|
9
10
|
export * from './scaffold/TopBar.js';
|
|
@@ -72,7 +73,6 @@ export * from './media/Tile.js';
|
|
|
72
73
|
export * from './media/Mosaic.js';
|
|
73
74
|
export * from './layover/Banner.js';
|
|
74
75
|
export * from './layover/Callout.js';
|
|
75
|
-
export * from './layover/Deck.js';
|
|
76
76
|
export * from './journey/Route.js';
|
|
77
77
|
export * from './journey/TileBadge.js';
|
|
78
78
|
export * from './journey/NoteRow.js';
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// cardds — the React adapter over the CSS. Thin: every component emits the
|
|
2
|
-
// markup contract the CSS documents
|
|
3
|
-
// the
|
|
2
|
+
// markup contract the CSS documents; a component's own behaviour is its own React code.
|
|
3
|
+
// cardds.js rides along for the environment only: the keyboard's height (--kb) and .bleed's scrollbar.
|
|
4
4
|
import '../cardds.js';
|
|
5
5
|
// Popover for Safari/iOS 16.4–16.x (native from 17): applies itself only where the platform lacks it.
|
|
6
6
|
import '@oddbird/popover-polyfill';
|
|
@@ -8,6 +8,7 @@ export { cx } from './cx.js';
|
|
|
8
8
|
export * from './type/Icon.js';
|
|
9
9
|
export { ICON_NAMES } from './type/icons.js';
|
|
10
10
|
export * from './type/Text.js';
|
|
11
|
+
export { setTextScale } from './type/textScale.js';
|
|
11
12
|
export * from './scaffold/Screen.js';
|
|
12
13
|
export * from './scaffold/AppBar.js';
|
|
13
14
|
export * from './scaffold/TopBar.js';
|
|
@@ -76,7 +77,6 @@ export * from './media/Tile.js';
|
|
|
76
77
|
export * from './media/Mosaic.js';
|
|
77
78
|
export * from './layover/Banner.js';
|
|
78
79
|
export * from './layover/Callout.js';
|
|
79
|
-
export * from './layover/Deck.js';
|
|
80
80
|
export * from './journey/Route.js';
|
|
81
81
|
export * from './journey/TileBadge.js';
|
|
82
82
|
export * from './journey/NoteRow.js';
|
package/dist/layover/Banner.d.ts
CHANGED
|
@@ -1,8 +1,15 @@
|
|
|
1
1
|
import type { ComponentProps, ReactNode } from 'react';
|
|
2
|
-
export interface BannerProps extends Omit<ComponentProps<'details'>, 'summary'> {
|
|
2
|
+
export interface BannerProps extends Omit<ComponentProps<'details'>, 'summary' | 'open' | 'onToggle'> {
|
|
3
3
|
/** the line that opens it — words (and an inline Icon); the chevron is the Banner's own */
|
|
4
4
|
summary: ReactNode;
|
|
5
|
+
/** CONTROLLED: open — with `onOpenChange`; or `defaultOpen` */
|
|
6
|
+
open?: boolean;
|
|
7
|
+
/** UNCONTROLLED: start open */
|
|
8
|
+
defaultOpen?: boolean;
|
|
9
|
+
/** the summary was tapped: the state it asks for */
|
|
10
|
+
onOpenChange?: (open: boolean) => void;
|
|
5
11
|
}
|
|
6
12
|
/** Banner — ONE band: the line that opens it and what it opens share the same ground, so they read as one piece (Lh 2026-09-24).
|
|
7
|
-
* A light tint with a darker rule above and below, edge to edge of its card or screen — a band, never a card in a card.
|
|
8
|
-
|
|
13
|
+
* A light tint with a darker rule above and below, edge to edge of its card or screen — a band, never a card in a card.
|
|
14
|
+
* A native details, controlled like an input: `open` + `onOpenChange`, or `defaultOpen`. */
|
|
15
|
+
export declare function Banner({ summary, open, defaultOpen, onOpenChange, className, children, ...rest }: BannerProps): import("react").JSX.Element;
|
package/dist/layover/Banner.js
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { cx } from '../cx.js';
|
|
3
3
|
import { Icon } from '../type/Icon.js';
|
|
4
|
+
import { useDisclosure } from '../state.js';
|
|
4
5
|
/** Banner — ONE band: the line that opens it and what it opens share the same ground, so they read as one piece (Lh 2026-09-24).
|
|
5
|
-
* A light tint with a darker rule above and below, edge to edge of its card or screen — a band, never a card in a card.
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
* A light tint with a darker rule above and below, edge to edge of its card or screen — a band, never a card in a card.
|
|
7
|
+
* A native details, controlled like an input: `open` + `onOpenChange`, or `defaultOpen`. */
|
|
8
|
+
export function Banner({ summary, open, defaultOpen, onOpenChange, className, children, ...rest }) {
|
|
9
|
+
const disclosure = useDisclosure(open, defaultOpen, onOpenChange);
|
|
10
|
+
return (_jsxs("details", { className: cx('banner', className), ...rest, ...disclosure, children: [_jsxs("summary", { className: "banner__summary", children: [summary, _jsx(Icon, { name: "chevron-down", size: "xs" })] }), _jsx("div", { className: "banner__body", children: children })] }));
|
|
8
11
|
}
|
package/dist/lists/Row.d.ts
CHANGED
|
@@ -41,7 +41,8 @@ export interface RowProps extends Omit<ComponentProps<'div'>, 'title'> {
|
|
|
41
41
|
*/
|
|
42
42
|
export declare function Row({ lead, leadIcon, title, meta, body, end, endValue, endCaption, lg, done, as, href, more, open, defaultOpen, onOpenChange, className, children, ...rest }: RowProps): import("react").JSX.Element;
|
|
43
43
|
export interface RowsProps extends ComponentProps<'div'> {
|
|
44
|
-
/** the group's name, above its rows (Today · Tomorrow · Later): a long list is GROUPED, not spaced out — several Rows one after another
|
|
44
|
+
/** the group's name, above its rows (Today · Tomorrow · Later): a long list is GROUPED, not spaced out — several Rows one after another.
|
|
45
|
+
* Words = the small label; an ELEMENT (`<Text level="title" as="h3">`) is used as the heading itself — the group is labelled by it. */
|
|
45
46
|
heading?: ReactNode;
|
|
46
47
|
}
|
|
47
48
|
/** Rows — a list of Rows separated by hairlines; `heading` names the group (a `role="group"` labelled by it). */
|
package/dist/lists/Row.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { createElement, useId } from 'react';
|
|
2
|
+
import { cloneElement, createElement, isValidElement, useId } from 'react';
|
|
3
3
|
import { cx } from '../cx.js';
|
|
4
4
|
import { Icon } from '../type/Icon.js';
|
|
5
|
+
import { useDisclosure } from '../state.js';
|
|
5
6
|
/**
|
|
6
7
|
* Row — a frameless row inside a card: lead · title + meta · end. 48px+ tall, a tap target.
|
|
7
8
|
* Several go in Rows (hairlines between). A row that IS a card is `Card row`.
|
|
@@ -10,17 +11,16 @@ import { Icon } from '../type/Icon.js';
|
|
|
10
11
|
* An `end` chevron turns when it is open — the app fetches whatever `more` lists; the row only shows it.
|
|
11
12
|
*/
|
|
12
13
|
export function Row({ lead, leadIcon, title, meta, body, end, endValue, endCaption, lg, done, as, href, more, open, defaultOpen, onOpenChange, className, children, ...rest }) {
|
|
14
|
+
const disclosure = useDisclosure(open, defaultOpen, onOpenChange);
|
|
13
15
|
const el = more !== undefined ? 'summary' : as ?? (href ? 'a' : 'div');
|
|
14
16
|
const row = createElement(el, { href, className: cx('row', lg && 'row--lg', done && 'row--done', className), 'aria-disabled': done || undefined, ...(more === undefined ? rest : {}) }, leadIcon ? _jsx("span", { className: "row__lead", children: _jsx(Icon, { name: leadIcon }) }) : lead, (title != null || meta != null || body != null) && (_jsxs("div", { className: "row__body", children: [title != null && _jsx("span", { className: "row__title", children: title }), meta != null && _jsx("span", { className: "row__meta", children: meta }), body] })), children, (endValue != null || endCaption != null) && (_jsxs("span", { className: "row__end", children: [endValue != null && _jsx("span", { className: "t-title", children: endValue }), endCaption != null && _jsx("span", { className: "t-caption t-muted", children: endCaption })] })), end, done && _jsx("span", { className: "row__done", children: _jsx(Icon, { name: "check", size: "sm" }) }));
|
|
15
17
|
if (more === undefined)
|
|
16
18
|
return row;
|
|
17
|
-
return (_jsxs("details", { className: "row-expand",
|
|
18
|
-
e.currentTarget.open = open; if (is !== (open ?? !is))
|
|
19
|
-
onOpenChange?.(is); }, children: [row, _jsx("div", { className: "row-expand__more", children: more })] }));
|
|
19
|
+
return (_jsxs("details", { className: "row-expand", ...rest, ...disclosure, children: [row, _jsx("div", { className: "row-expand__more", children: more })] }));
|
|
20
20
|
}
|
|
21
21
|
/** Rows — a list of Rows separated by hairlines; `heading` names the group (a `role="group"` labelled by it). */
|
|
22
22
|
export function Rows({ heading, className, children, ...rest }) {
|
|
23
23
|
const id = useId();
|
|
24
24
|
const named = heading != null;
|
|
25
|
-
return (_jsxs("div", { className: cx('rows', className), role: named ? 'group' : undefined, "aria-labelledby": named ? id : undefined, ...rest, children: [named && _jsx("span", { className: "rows__head", id: id, children: heading }), children] }));
|
|
25
|
+
return (_jsxs("div", { className: cx('rows', className), role: named ? 'group' : undefined, "aria-labelledby": named ? id : undefined, ...rest, children: [named && (isValidElement(heading) ? cloneElement(heading, { id }) : _jsx("span", { className: "rows__head", id: id, children: heading })), children] }));
|
|
26
26
|
}
|
package/dist/media/Postcard.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import {
|
|
2
|
+
import { useControlled } from '../state.js';
|
|
3
3
|
import { cx } from '../cx.js';
|
|
4
4
|
import { IconBtn } from '../actions/IconBtn.js';
|
|
5
5
|
/**
|
|
@@ -9,10 +9,8 @@ import { IconBtn } from '../actions/IconBtn.js';
|
|
|
9
9
|
* Who else liked it, a voice note, a reply go OUTSIDE it — a Row under it (`Row more` expands the list).
|
|
10
10
|
*/
|
|
11
11
|
export function Postcard({ photo, alt = '', name, line, caption, voice, flipped, defaultFlipped = false, onFlip, liked, onLike, likeLabel = 'ถูกใจ', frontLabel = 'พลิกดูด้านหลัง', backLabel = 'พลิกดูด้านหน้า', className, ...rest }) {
|
|
12
|
-
const [
|
|
13
|
-
const
|
|
14
|
-
const turn = () => { if (flipped === undefined)
|
|
15
|
-
setInner(!back); onFlip?.(!back); };
|
|
12
|
+
const [back, flip] = useControlled(flipped, defaultFlipped, onFlip);
|
|
13
|
+
const turn = () => flip(!back);
|
|
16
14
|
const words = (_jsxs("div", { className: "postcard__words", children: [_jsx("span", { className: "t-h1", children: name }), line != null && _jsx("span", { className: "t-body", children: line })] }));
|
|
17
15
|
return (_jsxs("div", { className: cx('postcard', back && 'is-flipped', className), ...rest, children: [_jsxs("div", { className: "postcard__face postcard__front", children: [_jsx("button", { className: "postcard__turn", type: "button", "aria-label": frontLabel, onClick: turn, children: photo ? _jsx("img", { src: photo, alt: alt }) : alt ? _jsx("div", { className: "ph", role: "img", "aria-label": alt }) : _jsx("div", { className: "ph" }) }), _jsxs("div", { className: "postcard__band", children: [words, (liked !== undefined || onLike) && _jsx(IconBtn, { invert: true, icon: "heart", label: likeLabel, "aria-pressed": !!liked, onClick: () => onLike?.(!liked) })] })] }), _jsxs("div", { className: "postcard__face postcard__back", children: [_jsxs("button", { className: "postcard__turn", type: "button", "aria-label": backLabel, onClick: turn, children: [words, caption != null && _jsx("p", { className: "postcard__caption", children: caption })] }), voice != null && _jsx("div", { className: "postcard__voice", children: voice })] })] }));
|
|
18
16
|
}
|
package/dist/numbers/Band.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { ComponentProps, ReactNode } from 'react';
|
|
2
|
+
import type { Tone } from '../cards/Card.js';
|
|
2
3
|
export interface BandProps extends ComponentProps<'article'> {
|
|
3
4
|
/** the two-line label (use a `<br />` to break it) */
|
|
4
5
|
label: ReactNode;
|
|
@@ -6,7 +7,8 @@ export interface BandProps extends ComponentProps<'article'> {
|
|
|
6
7
|
num: ReactNode;
|
|
7
8
|
/** the footnote under the label */
|
|
8
9
|
foot?: ReactNode;
|
|
9
|
-
|
|
10
|
+
/** the paper — see `Tone` */
|
|
11
|
+
tone?: Tone;
|
|
10
12
|
}
|
|
11
13
|
/** Band — a data card: 2-line label · giant number · footnote. Stack several in a BandStack for one boundary with hairlines. */
|
|
12
14
|
export declare function Band({ label, num, foot, tone, className, ...rest }: BandProps): import("react").JSX.Element;
|
package/dist/numbers/Picker.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { createContext, useContext, useEffect, useLayoutEffect, useRef
|
|
2
|
+
import { createContext, useContext, useEffect, useLayoutEffect, useRef } from 'react';
|
|
3
|
+
import { useControlled } from '../state.js';
|
|
3
4
|
import { cx } from '../cx.js';
|
|
4
5
|
const PickerContext = createContext(null);
|
|
5
6
|
/**
|
|
@@ -9,18 +10,10 @@ const PickerContext = createContext(null);
|
|
|
9
10
|
* settled in the centre. The CSS lights the centred item by scroll position; the app never reads the DOM to know what was picked.
|
|
10
11
|
*/
|
|
11
12
|
export function Picker({ value, defaultValue, onChange, unit, label, className, children, ...rest }) {
|
|
12
|
-
const [
|
|
13
|
-
const current = value ?? inner;
|
|
13
|
+
const [current, pick] = useControlled(value, defaultValue, onChange);
|
|
14
14
|
const rail = useRef(null);
|
|
15
15
|
const mounted = useRef(false);
|
|
16
16
|
const settle = useRef(null);
|
|
17
|
-
const pick = (next) => {
|
|
18
|
-
if (next === current)
|
|
19
|
-
return;
|
|
20
|
-
if (value === undefined)
|
|
21
|
-
setInner(next);
|
|
22
|
-
onChange?.(next);
|
|
23
|
-
};
|
|
24
17
|
const items = () => [...(rail.current?.querySelectorAll(':scope > .picker__item') ?? [])];
|
|
25
18
|
const column = () => (rail.current ? rail.current.clientWidth / 3 : 0); // the rail is three columns wide; item i stands in the centre at i × one column
|
|
26
19
|
/* the chosen value stands in the centre — at once on arrival, sliding after */
|
package/dist/numbers/Track.d.ts
CHANGED
|
@@ -7,6 +7,8 @@ export declare function Track({ label, className, ...rest }: TrackProps): import
|
|
|
7
7
|
export interface TrackStepProps extends ComponentProps<'li'> {
|
|
8
8
|
/** this step (and the connector into it) is done */
|
|
9
9
|
done?: boolean;
|
|
10
|
+
/** the step's NUMBER in the round instead of an Icon (1, 2, 3…) — a walk whose steps are counted, not pictured */
|
|
11
|
+
num?: number;
|
|
10
12
|
}
|
|
11
|
-
/** TrackStep — one step of a Track: an Icon in a round; lit when done. */
|
|
12
|
-
export declare function TrackStep({ done, className, ...rest }: TrackStepProps): import("react").JSX.Element;
|
|
13
|
+
/** TrackStep — one step of a Track: an Icon (children) or its number (`num`) in a round; lit when done. */
|
|
14
|
+
export declare function TrackStep({ done, num, className, children, ...rest }: TrackStepProps): import("react").JSX.Element;
|
package/dist/numbers/Track.js
CHANGED
|
@@ -4,7 +4,7 @@ import { cx } from '../cx.js';
|
|
|
4
4
|
export function Track({ label = 'Progress', className, ...rest }) {
|
|
5
5
|
return _jsx("ol", { className: cx('track', className), "aria-label": label, ...rest });
|
|
6
6
|
}
|
|
7
|
-
/** TrackStep — one step of a Track: an Icon in a round; lit when done. */
|
|
8
|
-
export function TrackStep({ done, className, ...rest }) {
|
|
9
|
-
return _jsx("li", { className: cx('track__step', done && 'is-done', className), ...rest });
|
|
7
|
+
/** TrackStep — one step of a Track: an Icon (children) or its number (`num`) in a round; lit when done. */
|
|
8
|
+
export function TrackStep({ done, num, className, children, ...rest }) {
|
|
9
|
+
return _jsx("li", { className: cx('track__step', done && 'is-done', className), ...rest, children: num != null ? _jsx("span", { className: "track__dot", children: num }) : children });
|
|
10
10
|
}
|
|
@@ -13,6 +13,8 @@ export interface AvatarPickItemProps extends Omit<ComponentProps<'button'>, 'nam
|
|
|
13
13
|
role?: ReactNode;
|
|
14
14
|
/** the Avatar (lg) */
|
|
15
15
|
children?: ReactNode;
|
|
16
|
+
/** this person is the one picked (aria-pressed; the app keeps which) */
|
|
17
|
+
selected?: boolean;
|
|
16
18
|
}
|
|
17
19
|
/** AvatarPickItem — one person in an AvatarPick: an `Avatar size="lg"`, a name, a role. */
|
|
18
|
-
export declare function AvatarPickItem({ name, role, className, children, ...rest }: AvatarPickItemProps): import("react").JSX.Element;
|
|
20
|
+
export declare function AvatarPickItem({ name, role, selected, className, children, ...rest }: AvatarPickItemProps): import("react").JSX.Element;
|
|
@@ -5,6 +5,6 @@ export function AvatarPick({ bleed, label, className, ...rest }) {
|
|
|
5
5
|
return _jsx("div", { className: cx('avatar-pick', bleed && 'bleed', className), "aria-label": label, ...rest });
|
|
6
6
|
}
|
|
7
7
|
/** AvatarPickItem — one person in an AvatarPick: an `Avatar size="lg"`, a name, a role. */
|
|
8
|
-
export function AvatarPickItem({ name, role, className, children, ...rest }) {
|
|
9
|
-
return (_jsxs("button", { type: "button", className: cx('avatar-pick__item', className), ...rest, children: [children, _jsx("span", { className: "avatar-pick__name", children: name }), role != null && _jsx("span", { className: "avatar-pick__role", children: role })] }));
|
|
8
|
+
export function AvatarPickItem({ name, role, selected, className, children, ...rest }) {
|
|
9
|
+
return (_jsxs("button", { type: "button", className: cx('avatar-pick__item', className), "aria-pressed": selected, ...rest, children: [children, _jsx("span", { className: "avatar-pick__name", children: name }), role != null && _jsx("span", { className: "avatar-pick__role", children: role })] }));
|
|
10
10
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { ComponentProps } from 'react';
|
|
2
2
|
export interface ActionBarProps extends ComponentProps<'div'> {
|
|
3
|
-
/** `pager`: previous / next as two equal buttons at the edges (a Link may sit between them
|
|
3
|
+
/** `pager`: previous / next as two equal buttons at the edges (a Link may sit between them) · `tiers`: rows stacked — a control tier above the buttons */
|
|
4
4
|
variant?: 'pager' | 'tiers';
|
|
5
5
|
/** a bare bar for a preview: no position, full width, no side padding (a real bar is a Screen's `bottom`) */
|
|
6
6
|
inline?: boolean;
|
|
@@ -8,8 +8,8 @@ export interface ActionBarProps extends ComponentProps<'div'> {
|
|
|
8
8
|
/**
|
|
9
9
|
* ActionBar — the screen's ONE move: the Screen's `bottom` (`<Screen fill bottom={<ActionBar…>}>`), the last part of its flex
|
|
10
10
|
* column, as tall as its rows. Never after `</Screen>`, never positioned by hand.
|
|
11
|
-
* Plain: one wide primary Btn (the step that commits).
|
|
12
|
-
*
|
|
11
|
+
* Plain: one wide primary Btn (the step that commits).
|
|
12
|
+
* `pager`: Back + Next as peers — buttons only. The PagerAt dots may be the bar's first row (a Walkthrough).
|
|
13
13
|
* `tiers`: an ActionBarTier with a control (a Slider) above the button tier.
|
|
14
14
|
* In a `Screen fill` it is a layer over the content's foot; on a scrolling Screen a sticky last row.
|
|
15
15
|
*/
|
|
@@ -3,8 +3,8 @@ import { cx } from '../cx.js';
|
|
|
3
3
|
/**
|
|
4
4
|
* ActionBar — the screen's ONE move: the Screen's `bottom` (`<Screen fill bottom={<ActionBar…>}>`), the last part of its flex
|
|
5
5
|
* column, as tall as its rows. Never after `</Screen>`, never positioned by hand.
|
|
6
|
-
* Plain: one wide primary Btn (the step that commits).
|
|
7
|
-
*
|
|
6
|
+
* Plain: one wide primary Btn (the step that commits).
|
|
7
|
+
* `pager`: Back + Next as peers — buttons only. The PagerAt dots may be the bar's first row (a Walkthrough).
|
|
8
8
|
* `tiers`: an ActionBarTier with a control (a Slider) above the button tier.
|
|
9
9
|
* In a `Screen fill` it is a layer over the content's foot; on a scrolling Screen a sticky last row.
|
|
10
10
|
*/
|
|
@@ -3,12 +3,12 @@ export interface CentreProps extends ComponentProps<'div'> {
|
|
|
3
3
|
}
|
|
4
4
|
/**
|
|
5
5
|
* Centre — the centred group: ONE thing to read at the human centre of the screen, when that thing is not a lone
|
|
6
|
-
* card: an EmptyState; a Card with its quiet second Btn and the PagerAt under it
|
|
6
|
+
* card: an EmptyState; a Card with its quiet second Btn and the PagerAt under it.
|
|
7
7
|
* On a plain `Screen` (the usual case, Lh 2026-09-12) it is in flow: the column is one phone tall, the group takes
|
|
8
8
|
* the room after the TopBar and centres a short card; a long card makes the page longer and scrolls up under the
|
|
9
9
|
* bar — nothing is capped, nothing shrinks. On a `Screen fill` it floats at 40% down (`--screen-centre`), capped
|
|
10
10
|
* and scrolling inside, for a screen that must never scroll. Its children stack at the screen's rhythm.
|
|
11
|
-
* Put it after the TopBar; the ActionBar, if any,
|
|
11
|
+
* Put it after the TopBar; the ActionBar, if any, is the Screen's `bottom`.
|
|
12
12
|
*/
|
|
13
13
|
export declare function Centre({ className, ...rest }: CentreProps): import("react").JSX.Element;
|
|
14
14
|
export interface PagesProps extends ComponentProps<'div'> {
|
package/dist/scaffold/Centre.js
CHANGED
|
@@ -3,12 +3,12 @@ import { flushSync } from 'react-dom';
|
|
|
3
3
|
import { cx } from '../cx.js';
|
|
4
4
|
/**
|
|
5
5
|
* Centre — the centred group: ONE thing to read at the human centre of the screen, when that thing is not a lone
|
|
6
|
-
* card: an EmptyState; a Card with its quiet second Btn and the PagerAt under it
|
|
6
|
+
* card: an EmptyState; a Card with its quiet second Btn and the PagerAt under it.
|
|
7
7
|
* On a plain `Screen` (the usual case, Lh 2026-09-12) it is in flow: the column is one phone tall, the group takes
|
|
8
8
|
* the room after the TopBar and centres a short card; a long card makes the page longer and scrolls up under the
|
|
9
9
|
* bar — nothing is capped, nothing shrinks. On a `Screen fill` it floats at 40% down (`--screen-centre`), capped
|
|
10
10
|
* and scrolling inside, for a screen that must never scroll. Its children stack at the screen's rhythm.
|
|
11
|
-
* Put it after the TopBar; the ActionBar, if any,
|
|
11
|
+
* Put it after the TopBar; the ActionBar, if any, is the Screen's `bottom`.
|
|
12
12
|
*/
|
|
13
13
|
export function Centre({ className, ...rest }) {
|
|
14
14
|
return _jsx("div", { className: cx('screen__centre', className), ...rest });
|
|
@@ -7,5 +7,5 @@ export interface PagerAtProps extends Omit<ComponentProps<'span'>, 'children'> {
|
|
|
7
7
|
/** accessible name; defaults to "Page {at} of {of}" */
|
|
8
8
|
label?: string;
|
|
9
9
|
}
|
|
10
|
-
/** PagerAt — the "where am I" dots: one accent dot at the current page. Under the card that changes (a child of Centre), or a Step's child after its Pages — pinned to the base's foot. One per walk, never inside an ActionBar,
|
|
10
|
+
/** PagerAt — the "where am I" dots: one accent dot at the current page. Under the card that changes (a child of Centre), or a Step's child after its Pages — pinned to the base's foot. One per walk, never inside a page; in a Walkthrough it is the bottom layer's first row (an ActionBar child, centred). */
|
|
11
11
|
export declare function PagerAt({ at, of, label, className, ...rest }: PagerAtProps): import("react").JSX.Element;
|
package/dist/scaffold/PagerAt.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import { cx } from '../cx.js';
|
|
3
|
-
/** PagerAt — the "where am I" dots: one accent dot at the current page. Under the card that changes (a child of Centre), or a Step's child after its Pages — pinned to the base's foot. One per walk, never inside an ActionBar,
|
|
3
|
+
/** PagerAt — the "where am I" dots: one accent dot at the current page. Under the card that changes (a child of Centre), or a Step's child after its Pages — pinned to the base's foot. One per walk, never inside a page; in a Walkthrough it is the bottom layer's first row (an ActionBar child, centred). */
|
|
4
4
|
export function PagerAt({ at, of, label, className, ...rest }) {
|
|
5
5
|
return (_jsx("span", { className: cx('pager__at', className), role: "img", "aria-label": label ?? `Page ${at} of ${of}`, ...rest, children: Array.from({ length: of }, (_, i) => _jsx("i", { className: i + 1 === at ? 'is-at' : undefined }, i)) }));
|
|
6
6
|
}
|