@usableapp/cardds 0.2.2 → 0.4.0
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/README.md +35 -107
- package/cardds.js +6 -449
- package/css/actions.css +41 -35
- package/css/base.css +9 -9
- package/css/card.css +26 -25
- package/css/choice.css +50 -50
- package/css/forms.css +18 -18
- package/css/journey.css +16 -16
- package/css/layover.css +45 -45
- package/css/lists.css +43 -43
- package/css/media.css +33 -33
- package/css/numbers.css +25 -25
- package/css/people.css +11 -11
- package/css/sheet.css +29 -29
- package/css/step.css +6 -6
- package/css/theme.template.css +6 -3
- package/css/tokens.css +2 -0
- package/dist/actions/Btn.d.ts +109 -108
- package/dist/actions/BtnRow.d.ts +2 -2
- package/dist/actions/Chip.d.ts +102 -101
- package/dist/actions/Dot.d.ts +2 -2
- package/dist/actions/Dropdown.d.ts +36 -19
- package/dist/actions/Dropdown.js +41 -11
- package/dist/actions/Fab.d.ts +2 -2
- package/dist/actions/IconBtn.d.ts +298 -10
- package/dist/actions/IconBtn.js +6 -8
- package/dist/actions/Link.d.ts +105 -104
- package/dist/actions/Segment.d.ts +3 -3
- package/dist/cardds.css +354 -345
- package/dist/cards/Card.d.ts +99 -98
- package/dist/cards/CardFoot.d.ts +2 -2
- package/dist/cards/CardHead.d.ts +2 -2
- package/dist/cards/CardParts.d.ts +7 -7
- package/dist/cards/Placeholder.d.ts +2 -2
- package/dist/cards/Stat.d.ts +7 -5
- package/dist/cards/Stat.js +2 -2
- package/dist/choice/Calendar.d.ts +17 -6
- package/dist/choice/Calendar.js +9 -3
- package/dist/choice/Check.d.ts +3 -3
- package/dist/choice/DayStrip.d.ts +3 -3
- package/dist/choice/Mood.d.ts +2 -2
- package/dist/choice/Slider.d.ts +3 -3
- package/dist/choice/Slider.js +12 -8
- package/dist/forms/AddRow.d.ts +2 -2
- package/dist/forms/Composer.d.ts +2 -2
- package/dist/forms/Field.d.ts +2 -2
- package/dist/forms/FileBtn.d.ts +2 -2
- package/dist/forms/Pin.d.ts +10 -7
- package/dist/forms/Pin.js +47 -18
- package/dist/journey/NoteRow.d.ts +2 -2
- package/dist/journey/Route.d.ts +2 -2
- package/dist/journey/TileBadge.d.ts +2 -2
- package/dist/layover/Banner.d.ts +2 -2
- package/dist/layover/Callout.d.ts +2 -2
- package/dist/layover/Deck.d.ts +3 -3
- package/dist/lists/Bubble.d.ts +3 -3
- package/dist/lists/Kv.d.ts +5 -5
- package/dist/lists/Legend.d.ts +3 -3
- package/dist/lists/Row.d.ts +5 -4
- package/dist/lists/Timeline.d.ts +3 -3
- package/dist/media/MapArea.d.ts +2 -2
- package/dist/media/Mosaic.d.ts +3 -3
- package/dist/media/Postcard.d.ts +9 -5
- package/dist/media/Postcard.js +8 -3
- package/dist/media/Quote.d.ts +2 -2
- package/dist/media/Tile.d.ts +5 -4
- package/dist/numbers/Badge.d.ts +2 -2
- package/dist/numbers/Band.d.ts +3 -3
- package/dist/numbers/Bars.d.ts +3 -3
- package/dist/numbers/DotGrid.d.ts +2 -2
- package/dist/numbers/Picker.d.ts +20 -8
- package/dist/numbers/Picker.js +51 -13
- package/dist/numbers/Ring.d.ts +2 -2
- package/dist/numbers/Track.d.ts +3 -3
- package/dist/people/Avatar.d.ts +100 -99
- package/dist/people/AvatarPick.d.ts +3 -3
- package/dist/scaffold/ActionBar.d.ts +3 -3
- package/dist/scaffold/AppBar.d.ts +2 -2
- package/dist/scaffold/BaseContent.d.ts +7 -7
- package/dist/scaffold/BaseContent.js +4 -4
- package/dist/scaffold/Centre.d.ts +3 -3
- package/dist/scaffold/EmptyState.d.ts +2 -2
- package/dist/scaffold/FilterRow.d.ts +2 -2
- package/dist/scaffold/FloatBar.d.ts +105 -104
- package/dist/scaffold/PagerAt.d.ts +2 -2
- package/dist/scaffold/Screen.d.ts +100 -99
- package/dist/scaffold/TopBar.d.ts +2 -2
- package/dist/sheets/CardBack.d.ts +2 -2
- package/dist/sheets/Drawer.d.ts +19 -8
- package/dist/sheets/Drawer.js +29 -5
- package/dist/sheets/Sheet.d.ts +29 -16
- package/dist/sheets/Sheet.js +157 -11
- package/dist/sheets/SheetBody.d.ts +2 -2
- package/dist/sheets/SheetHead.d.ts +2 -2
- package/dist/sheets/SheetStack.d.ts +15 -3
- package/dist/sheets/SheetStack.js +74 -2
- package/dist/sheets/SheetStage.d.ts +2 -2
- package/dist/sheets/Step.d.ts +2 -2
- package/dist/type/Icon.d.ts +22 -7
- package/dist/type/Icon.js +27 -4
- package/dist/type/Text.d.ts +7 -1
- package/dist/type/Text.js +2 -2
- package/package.json +3 -2
package/dist/forms/Pin.js
CHANGED
|
@@ -1,27 +1,56 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
import { useEffect, useRef } from 'react';
|
|
2
|
+
import { useEffect, useRef, useState } from 'react';
|
|
3
3
|
import { cx } from '../cx.js';
|
|
4
4
|
/**
|
|
5
5
|
* Pin — big code entry, one digit per pill; a filled cell turns accent. Lives in a Sheet.
|
|
6
|
-
*
|
|
7
|
-
*
|
|
6
|
+
* Its own behaviour, inside it: typing a digit moves to the next cell, Backspace in an empty cell moves back and clears, the
|
|
7
|
+
* arrows walk the cells, a pasted code fills them from the one it landed in; only digits stay. The first cell takes the SMS
|
|
8
|
+
* one-time-code autofill. The code is a VALUE, controlled like an input: `value` + `onChange`, or `defaultValue`.
|
|
8
9
|
*/
|
|
9
|
-
export function Pin({ length = 6, value = '', label = 'Digit', onChange, autoFocus, className, ...rest }) {
|
|
10
|
+
export function Pin({ length = 6, value, defaultValue = '', label = 'Digit', onChange, autoFocus, className, ...rest }) {
|
|
10
11
|
const ref = useRef(null);
|
|
12
|
+
const [inner, setInner] = useState(defaultValue);
|
|
13
|
+
const code = (value ?? inner).replace(/\D/g, '').slice(0, length);
|
|
14
|
+
const cell = (i) => ref.current?.querySelectorAll('.pin__cell')[i];
|
|
15
|
+
const set = (next) => {
|
|
16
|
+
next = next.slice(0, length);
|
|
17
|
+
if (value === undefined)
|
|
18
|
+
setInner(next);
|
|
19
|
+
if (next !== code)
|
|
20
|
+
onChange?.(next, next.length === length);
|
|
21
|
+
};
|
|
11
22
|
useEffect(() => {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
const on = (e) => { const d = e.detail; onChange(d.code, d.complete); };
|
|
16
|
-
el.addEventListener('cardds:pin', on);
|
|
17
|
-
return () => el.removeEventListener('cardds:pin', on);
|
|
18
|
-
}, [onChange]);
|
|
19
|
-
useEffect(() => {
|
|
20
|
-
if (!autoFocus)
|
|
21
|
-
return;
|
|
22
|
-
const cells = ref.current?.querySelectorAll('.pin__cell');
|
|
23
|
-
if (cells)
|
|
24
|
-
([...cells].find((c) => !c.value) ?? cells[cells.length - 1])?.focus();
|
|
23
|
+
if (autoFocus)
|
|
24
|
+
cell(Math.min(code.length, length - 1))?.focus();
|
|
25
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps -- on mount only
|
|
25
26
|
}, [autoFocus]);
|
|
26
|
-
|
|
27
|
+
const input = (i) => (e) => {
|
|
28
|
+
const digits = e.target.value.replace(/\D/g, '');
|
|
29
|
+
const at = Math.min(i, code.length); // a code has no gaps: a digit typed further along lands in the first empty cell
|
|
30
|
+
if (!digits) {
|
|
31
|
+
set(code.slice(0, at) + code.slice(at + 1));
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
set(code.slice(0, at) + digits + code.slice(at + digits.length)); // a paste (or a typed run) spills over the cells that follow
|
|
35
|
+
cell(Math.min(at + digits.length, length - 1))?.focus();
|
|
36
|
+
};
|
|
37
|
+
const key = (i) => (e) => {
|
|
38
|
+
if (e.key === 'Backspace' && !e.currentTarget.value && i > 0) {
|
|
39
|
+
e.preventDefault();
|
|
40
|
+
set(code.slice(0, i - 1) + code.slice(i));
|
|
41
|
+
cell(i - 1)?.focus();
|
|
42
|
+
}
|
|
43
|
+
else if (e.key === 'ArrowLeft' && i > 0) {
|
|
44
|
+
e.preventDefault();
|
|
45
|
+
cell(i - 1)?.focus();
|
|
46
|
+
}
|
|
47
|
+
else if (e.key === 'ArrowRight' && i < length - 1) {
|
|
48
|
+
e.preventDefault();
|
|
49
|
+
cell(i + 1)?.focus();
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
return (_jsx("div", { ref: ref, className: cx('pin', className), ...rest, children: Array.from({ length }, (_, i) => (
|
|
53
|
+
// no maxLength: the browser would cut a pasted code before this ever saw it. A cell holds one digit — typing into a full one
|
|
54
|
+
// replaces it, so its digit is selected whenever the cell takes the focus
|
|
55
|
+
_jsx("input", { className: "pin__cell", inputMode: "numeric", pattern: "[0-9]*", placeholder: " ", value: code[i] ?? '', "aria-label": `${label} ${i + 1}`, autoComplete: i === 0 ? 'one-time-code' : 'off', onChange: input(i), onKeyDown: key(i), onFocus: (e) => e.currentTarget.select() }, i))) }));
|
|
27
56
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { ComponentProps } from 'react';
|
|
2
2
|
import { type IconName } from '../type/Icon.js';
|
|
3
|
-
export interface NoteRowProps extends
|
|
3
|
+
export interface NoteRowProps extends ComponentProps<'div'> {
|
|
4
4
|
icon?: IconName;
|
|
5
5
|
}
|
|
6
6
|
/** NoteRow — icon + caption: transit hints, fine print. */
|
package/dist/journey/Route.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { ComponentProps, ReactNode } from 'react';
|
|
2
2
|
import { type IconName } from '../type/Icon.js';
|
|
3
3
|
export interface RoutePoint {
|
|
4
4
|
/** the place name (caption) */
|
|
@@ -8,7 +8,7 @@ export interface RoutePoint {
|
|
|
8
8
|
/** the time */
|
|
9
9
|
time: ReactNode;
|
|
10
10
|
}
|
|
11
|
-
export interface RouteProps extends
|
|
11
|
+
export interface RouteProps extends ComponentProps<'div'> {
|
|
12
12
|
from: RoutePoint;
|
|
13
13
|
to: RoutePoint;
|
|
14
14
|
/** the icon on the dotted connector (plane by default) */
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
export interface TileBadgeProps extends
|
|
1
|
+
import type { ComponentProps, ReactNode } from 'react';
|
|
2
|
+
export interface TileBadgeProps extends ComponentProps<'span'> {
|
|
3
3
|
/** the small label above ("Gate") */
|
|
4
4
|
label: ReactNode;
|
|
5
5
|
/** the big value ("21") */
|
package/dist/layover/Banner.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
export interface BannerProps extends
|
|
1
|
+
import type { ComponentProps, ReactNode } from 'react';
|
|
2
|
+
export interface BannerProps extends ComponentProps<'details'> {
|
|
3
3
|
/** the chip that opens it (a `Chip on` with a chevron Icon xs) */
|
|
4
4
|
summary: ReactNode;
|
|
5
5
|
/** the tone of the opened card */
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
export interface CalloutProps extends Omit<
|
|
1
|
+
import type { ComponentProps, ReactNode } from 'react';
|
|
2
|
+
export interface CalloutProps extends Omit<ComponentProps<'div'>, 'title'> {
|
|
3
3
|
title: ReactNode;
|
|
4
4
|
sub?: ReactNode;
|
|
5
5
|
/** position over the stage background (CSS lengths / percentages) */
|
package/dist/layover/Deck.d.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
export interface DeckProps extends
|
|
1
|
+
import type { ComponentProps } from 'react';
|
|
2
|
+
export interface DeckProps extends ComponentProps<'div'> {
|
|
3
3
|
}
|
|
4
4
|
/** Deck — swipe cards fanned behind each other; the LAST child is on top. Children are Cards (the front one may `fold`). */
|
|
5
5
|
export declare function Deck({ className, ...rest }: DeckProps): import("react").JSX.Element;
|
|
6
|
-
export interface DeckActionsProps extends
|
|
6
|
+
export interface DeckActionsProps extends ComponentProps<'div'> {
|
|
7
7
|
}
|
|
8
8
|
/** DeckActions — the two big round buttons under a Deck (skip · keep). */
|
|
9
9
|
export declare function DeckActions({ className, ...rest }: DeckActionsProps): import("react").JSX.Element;
|
package/dist/lists/Bubble.d.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
export interface ThreadProps extends
|
|
1
|
+
import type { ComponentProps, ReactNode } from 'react';
|
|
2
|
+
export interface ThreadProps extends ComponentProps<'div'> {
|
|
3
3
|
}
|
|
4
4
|
/** Thread — a stack of Bubbles: a conversation. */
|
|
5
5
|
export declare function Thread({ className, ...rest }: ThreadProps): import("react").JSX.Element;
|
|
6
|
-
export interface BubbleProps extends
|
|
6
|
+
export interface BubbleProps extends ComponentProps<'div'> {
|
|
7
7
|
/** whose: theirs on the left (default), mine on the right */
|
|
8
8
|
side?: 'left' | 'right';
|
|
9
9
|
/** the caption under the message — a time, a tick (an Icon) */
|
package/dist/lists/Kv.d.ts
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { ComponentProps, ReactNode } from 'react';
|
|
2
2
|
import { type IconName } from '../type/Icon.js';
|
|
3
|
-
export interface KvProps extends
|
|
3
|
+
export interface KvProps extends ComponentProps<'dl'> {
|
|
4
4
|
/** hairlines between rows */
|
|
5
5
|
lined?: boolean;
|
|
6
6
|
}
|
|
7
7
|
/** Kv — key-value rows: label left, value right (Pay with · Time credits); children are KVRows. */
|
|
8
8
|
export declare function Kv({ lined, className, ...rest }: KvProps): import("react").JSX.Element;
|
|
9
|
-
export interface KvRowProps extends
|
|
9
|
+
export interface KvRowProps extends ComponentProps<'div'> {
|
|
10
10
|
/** the key */
|
|
11
11
|
label: ReactNode;
|
|
12
12
|
/** the value */
|
|
@@ -14,11 +14,11 @@ export interface KvRowProps extends ComponentPropsWithoutRef<'div'> {
|
|
|
14
14
|
}
|
|
15
15
|
/** KvRow — one key · value line (48px tall); the value may hold a Chip, an Avatar, an Icon. */
|
|
16
16
|
export declare function KvRow({ label, className, children, ...rest }: KvRowProps): import("react").JSX.Element;
|
|
17
|
-
export interface KvGridProps extends
|
|
17
|
+
export interface KvGridProps extends ComponentProps<'div'> {
|
|
18
18
|
}
|
|
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
|
-
export interface KvCellProps extends
|
|
21
|
+
export interface KvCellProps extends ComponentProps<'div'> {
|
|
22
22
|
icon?: IconName;
|
|
23
23
|
value: ReactNode;
|
|
24
24
|
label: ReactNode;
|
package/dist/lists/Legend.d.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
export interface LegendProps extends
|
|
1
|
+
import type { ComponentProps } from 'react';
|
|
2
|
+
export interface LegendProps extends ComponentProps<'div'> {
|
|
3
3
|
}
|
|
4
4
|
/** Legend — signal dots with captions under a chart; children are LegendItems. */
|
|
5
5
|
export declare function Legend({ className, ...rest }: LegendProps): import("react").JSX.Element;
|
|
6
|
-
export interface LegendItemProps extends
|
|
6
|
+
export interface LegendItemProps extends ComponentProps<'span'> {
|
|
7
7
|
/** which signal dot: `a` (default) or `b` */
|
|
8
8
|
dot?: 'a' | 'b';
|
|
9
9
|
}
|
package/dist/lists/Row.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { type
|
|
1
|
+
import { type ComponentProps, type ReactNode } from 'react';
|
|
2
2
|
import { type IconName } from '../type/Icon.js';
|
|
3
|
-
export interface RowProps extends Omit<
|
|
3
|
+
export interface RowProps extends Omit<ComponentProps<'div'>, 'title'> {
|
|
4
4
|
/** the leading visual: an Avatar, an AvatarStack, an Icon */
|
|
5
5
|
lead?: ReactNode;
|
|
6
6
|
/** an icon in the outlined 48px lead box (menu rows) */
|
|
@@ -264,6 +264,7 @@ export declare function Row({ lead, leadIcon, title, meta, body, end, endValue,
|
|
|
264
264
|
onTransitionRunCapture?: import("react").TransitionEventHandler<HTMLDivElement> | undefined;
|
|
265
265
|
onTransitionStart?: import("react").TransitionEventHandler<HTMLDivElement> | undefined;
|
|
266
266
|
onTransitionStartCapture?: import("react").TransitionEventHandler<HTMLDivElement> | undefined;
|
|
267
|
+
ref?: import("react").Ref<HTMLDivElement> | undefined;
|
|
267
268
|
key?: import("react").Key | null | undefined;
|
|
268
269
|
defaultChecked?: boolean | undefined | undefined;
|
|
269
270
|
defaultValue?: string | number | readonly string[] | undefined;
|
|
@@ -310,8 +311,8 @@ export declare function Row({ lead, leadIcon, title, meta, body, end, endValue,
|
|
|
310
311
|
exportparts?: string | undefined | undefined;
|
|
311
312
|
href: string | undefined;
|
|
312
313
|
className: string;
|
|
313
|
-
},
|
|
314
|
-
export interface RowsProps extends
|
|
314
|
+
}, HTMLDivElement>;
|
|
315
|
+
export interface RowsProps extends ComponentProps<'div'> {
|
|
315
316
|
}
|
|
316
317
|
/** Rows — a list of Rows separated by hairlines. */
|
|
317
318
|
export declare function Rows({ className, ...rest }: RowsProps): import("react").JSX.Element;
|
package/dist/lists/Timeline.d.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
export interface TimelineProps extends
|
|
1
|
+
import type { ComponentProps, ReactNode } from 'react';
|
|
2
|
+
export interface TimelineProps extends ComponentProps<'ol'> {
|
|
3
3
|
}
|
|
4
4
|
/** Timeline — a hairline with accent dots, date marks and entries to the right; children are TimelineItems. */
|
|
5
5
|
export declare function Timeline({ className, ...rest }: TimelineProps): import("react").JSX.Element;
|
|
6
|
-
export interface TimelineItemProps extends
|
|
6
|
+
export interface TimelineItemProps extends ComponentProps<'li'> {
|
|
7
7
|
/** the date chip ("Wed 14") */
|
|
8
8
|
mark: ReactNode;
|
|
9
9
|
}
|
package/dist/media/MapArea.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
export interface MapAreaProps extends
|
|
1
|
+
import type { ComponentProps, ReactNode, Ref } from 'react';
|
|
2
|
+
export interface MapAreaProps extends ComponentProps<'div'> {
|
|
3
3
|
/** the words over the map, under the bar's line */
|
|
4
4
|
hint?: ReactNode;
|
|
5
5
|
/** the tile provider's credit, bottom right (OSM requires it) — a caption, never the engine's own control */
|
package/dist/media/Mosaic.d.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
export interface MosaicProps extends
|
|
1
|
+
import type { ComponentProps } from 'react';
|
|
2
|
+
export interface MosaicProps extends ComponentProps<'div'> {
|
|
3
3
|
label?: string;
|
|
4
4
|
}
|
|
5
5
|
/** Mosaic — one big photo + two small in a card (three Placeholders or imgs). */
|
|
6
6
|
export declare function Mosaic({ label, className, ...rest }: MosaicProps): import("react").JSX.Element;
|
|
7
|
-
export interface WaveProps extends
|
|
7
|
+
export interface WaveProps extends ComponentProps<'span'> {
|
|
8
8
|
label?: string;
|
|
9
9
|
}
|
|
10
10
|
/** Wave — the waveform stand-in for a voice note, filling a Row's body. */
|
package/dist/media/Postcard.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type
|
|
2
|
-
export interface PostcardProps extends
|
|
1
|
+
import { type ComponentProps, type ReactNode } from 'react';
|
|
2
|
+
export interface PostcardProps extends ComponentProps<'div'> {
|
|
3
3
|
/** the photo on the front; none = the wireframe box */
|
|
4
4
|
photo?: string | null;
|
|
5
5
|
alt?: string;
|
|
@@ -7,14 +7,18 @@ export interface PostcardProps extends ComponentPropsWithoutRef<'div'> {
|
|
|
7
7
|
name: ReactNode;
|
|
8
8
|
/** the words on the back */
|
|
9
9
|
caption?: ReactNode;
|
|
10
|
-
/**
|
|
10
|
+
/** CONTROLLED: the back is showing. The app owns it — pair it with `onFlip`. */
|
|
11
11
|
flipped?: boolean;
|
|
12
|
+
/** UNCONTROLLED: start turned over; the card then keeps its own side */
|
|
13
|
+
defaultFlipped?: boolean;
|
|
14
|
+
/** a face was tapped: the side it asks to show */
|
|
15
|
+
onFlip?: (flipped: boolean) => void;
|
|
12
16
|
frontLabel?: string;
|
|
13
17
|
backLabel?: string;
|
|
14
18
|
}
|
|
15
19
|
/**
|
|
16
20
|
* Postcard — a member's introduction as a card in the hand: the photo (or the wireframe box) with the name in front,
|
|
17
|
-
* the caption on the back; a tap on either face turns it over (
|
|
21
|
+
* the caption on the back; a tap on either face turns it over (`--motion-flip`). Which side shows is a state: `flipped` + `onFlip`, or `defaultFlipped`.
|
|
18
22
|
* A voice note, a like, a reply go OUTSIDE it, in a Row under it — a face is a button and holds no button.
|
|
19
23
|
*/
|
|
20
|
-
export declare function Postcard({ photo, alt, name, caption, flipped, frontLabel, backLabel, className, ...rest }: PostcardProps): import("react").JSX.Element;
|
|
24
|
+
export declare function Postcard({ photo, alt, name, caption, flipped, defaultFlipped, onFlip, frontLabel, backLabel, className, ...rest }: PostcardProps): import("react").JSX.Element;
|
package/dist/media/Postcard.js
CHANGED
|
@@ -1,10 +1,15 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useState } from 'react';
|
|
2
3
|
import { cx } from '../cx.js';
|
|
3
4
|
/**
|
|
4
5
|
* Postcard — a member's introduction as a card in the hand: the photo (or the wireframe box) with the name in front,
|
|
5
|
-
* the caption on the back; a tap on either face turns it over (
|
|
6
|
+
* the caption on the back; a tap on either face turns it over (`--motion-flip`). Which side shows is a state: `flipped` + `onFlip`, or `defaultFlipped`.
|
|
6
7
|
* A voice note, a like, a reply go OUTSIDE it, in a Row under it — a face is a button and holds no button.
|
|
7
8
|
*/
|
|
8
|
-
export function Postcard({ photo, alt = '', name, caption, flipped, frontLabel = 'พลิกดูด้านหลัง', backLabel = 'พลิกดูด้านหน้า', className, ...rest }) {
|
|
9
|
-
|
|
9
|
+
export function Postcard({ photo, alt = '', name, caption, flipped, defaultFlipped = false, onFlip, frontLabel = 'พลิกดูด้านหลัง', backLabel = 'พลิกดูด้านหน้า', className, ...rest }) {
|
|
10
|
+
const [inner, setInner] = useState(defaultFlipped);
|
|
11
|
+
const back = flipped ?? inner;
|
|
12
|
+
const turn = () => { if (flipped === undefined)
|
|
13
|
+
setInner(!back); onFlip?.(!back); };
|
|
14
|
+
return (_jsxs("div", { className: cx('postcard', back && 'is-flipped', className), ...rest, children: [_jsxs("button", { className: "postcard__face postcard__front", 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" }), _jsx("span", { className: "postcard__label", children: name })] }), _jsxs("button", { className: "postcard__face postcard__back", type: "button", "aria-label": backLabel, onClick: turn, children: [caption != null && _jsx("p", { className: "postcard__caption", children: caption }), _jsx("span", { className: "postcard__label", children: name })] })] }));
|
|
10
15
|
}
|
package/dist/media/Quote.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
export interface QuoteProps extends
|
|
1
|
+
import type { ComponentProps, ReactNode } from 'react';
|
|
2
|
+
export interface QuoteProps extends ComponentProps<'blockquote'> {
|
|
3
3
|
/** the words */
|
|
4
4
|
text: ReactNode;
|
|
5
5
|
/** the attribution */
|
package/dist/media/Tile.d.ts
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import { type
|
|
1
|
+
import { type ComponentProps, type ReactNode } from 'react';
|
|
2
2
|
import { type IconName } from '../type/Icon.js';
|
|
3
|
-
export interface TileGridProps extends
|
|
3
|
+
export interface TileGridProps extends ComponentProps<'div'> {
|
|
4
4
|
/** three across on a phone (attachments, upload kinds) */
|
|
5
5
|
cols3?: boolean;
|
|
6
6
|
bleed?: boolean;
|
|
7
7
|
}
|
|
8
8
|
/** TileGrid — big square Tiles in a responsive grid. */
|
|
9
9
|
export declare function TileGrid({ cols3, bleed, className, ...rest }: TileGridProps): import("react").JSX.Element;
|
|
10
|
-
export interface TileProps extends Omit<
|
|
10
|
+
export interface TileProps extends Omit<ComponentProps<'div'>, 'onChange'> {
|
|
11
11
|
/** the icon at the top */
|
|
12
12
|
icon?: IconName;
|
|
13
13
|
/** the label at the bottom */
|
|
@@ -272,6 +272,7 @@ export declare function Tile({ icon, label, value, sub, pick, type, name, checke
|
|
|
272
272
|
onTransitionRunCapture?: import("react").TransitionEventHandler<HTMLDivElement> | undefined;
|
|
273
273
|
onTransitionStart?: import("react").TransitionEventHandler<HTMLDivElement> | undefined;
|
|
274
274
|
onTransitionStartCapture?: import("react").TransitionEventHandler<HTMLDivElement> | undefined;
|
|
275
|
+
ref?: import("react").Ref<HTMLDivElement> | undefined;
|
|
275
276
|
key?: import("react").Key | null | undefined;
|
|
276
277
|
defaultValue?: string | number | readonly string[] | undefined;
|
|
277
278
|
suppressContentEditableWarning?: boolean | undefined | undefined;
|
|
@@ -317,4 +318,4 @@ export declare function Tile({ icon, label, value, sub, pick, type, name, checke
|
|
|
317
318
|
exportparts?: string | undefined | undefined;
|
|
318
319
|
type: string | undefined;
|
|
319
320
|
className: string;
|
|
320
|
-
},
|
|
321
|
+
}, HTMLDivElement>;
|
package/dist/numbers/Badge.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
export interface BadgeProps extends
|
|
1
|
+
import type { ComponentProps } from 'react';
|
|
2
|
+
export interface BadgeProps extends ComponentProps<'span'> {
|
|
3
3
|
/** tinted instead of accent */
|
|
4
4
|
soft?: boolean;
|
|
5
5
|
}
|
package/dist/numbers/Band.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
export interface BandProps extends
|
|
1
|
+
import type { ComponentProps, ReactNode } from 'react';
|
|
2
|
+
export interface BandProps extends ComponentProps<'article'> {
|
|
3
3
|
/** the two-line label (use a `<br />` to break it) */
|
|
4
4
|
label: ReactNode;
|
|
5
5
|
/** the giant number; wrap a unit in `<small>` */
|
|
@@ -10,7 +10,7 @@ export interface BandProps extends ComponentPropsWithoutRef<'article'> {
|
|
|
10
10
|
}
|
|
11
11
|
/** Band — a data card: 2-line label · giant number · footnote. Stack several in a BandStack for one boundary with hairlines. */
|
|
12
12
|
export declare function Band({ label, num, foot, tone, className, ...rest }: BandProps): import("react").JSX.Element;
|
|
13
|
-
export interface BandStackProps extends
|
|
13
|
+
export interface BandStackProps extends ComponentProps<'div'> {
|
|
14
14
|
}
|
|
15
15
|
/** BandStack — several Bands as ONE card boundary, a hairline between each. */
|
|
16
16
|
export declare function BandStack({ className, ...rest }: BandStackProps): import("react").JSX.Element;
|
package/dist/numbers/Bars.d.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
export interface BarsProps extends
|
|
1
|
+
import type { ComponentProps } from 'react';
|
|
2
|
+
export interface BarsProps extends ComponentProps<'div'> {
|
|
3
3
|
/** the value of the tallest bar */
|
|
4
4
|
max: number;
|
|
5
5
|
}
|
|
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
|
-
export interface BarProps extends
|
|
8
|
+
export interface BarProps extends ComponentProps<'div'> {
|
|
9
9
|
value: number;
|
|
10
10
|
/** the highlighted bar (accent, its count in a pill) */
|
|
11
11
|
on?: boolean;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
export interface DotGridProps extends
|
|
1
|
+
import type { ComponentProps } from 'react';
|
|
2
|
+
export interface DotGridProps extends ComponentProps<'div'> {
|
|
3
3
|
/** how many dots */
|
|
4
4
|
total: number;
|
|
5
5
|
/** how many are done (filled, from the top-left) */
|
package/dist/numbers/Picker.d.ts
CHANGED
|
@@ -1,13 +1,25 @@
|
|
|
1
|
-
import { type
|
|
2
|
-
export interface PickerProps extends
|
|
1
|
+
import { type ComponentProps, type ReactNode } from 'react';
|
|
2
|
+
export interface PickerProps extends Omit<ComponentProps<'div'>, 'onChange' | 'defaultValue'> {
|
|
3
|
+
/** CONTROLLED: the chosen PickerItem's `value`. The app owns it — pair it with `onChange`. */
|
|
4
|
+
value?: string;
|
|
5
|
+
/** UNCONTROLLED: the value it starts on; the picker then keeps its own */
|
|
6
|
+
defaultValue?: string;
|
|
7
|
+
/** the member settled on a value — scrolled the rail to it, or tapped it */
|
|
8
|
+
onChange?: (value: string) => void;
|
|
3
9
|
/** the unit under the rail ("hours") */
|
|
4
10
|
unit?: ReactNode;
|
|
5
11
|
label?: string;
|
|
6
12
|
}
|
|
7
|
-
/**
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
13
|
+
/**
|
|
14
|
+
* Picker — a horizontal snap picker, the centre value big between two accent rules; children are PickerItems.
|
|
15
|
+
* It holds a VALUE, controlled like an input: `value` + `onChange`, or `defaultValue`. The value IS the item standing in the centre
|
|
16
|
+
* of the rail: the picker scrolls the chosen one there, and when the member scrolls (or taps an item) it asks for the one that
|
|
17
|
+
* settled in the centre. The CSS lights the centred item by scroll position; the app never reads the DOM to know what was picked.
|
|
18
|
+
*/
|
|
19
|
+
export declare function Picker({ value, defaultValue, onChange, unit, label, className, children, ...rest }: PickerProps): import("react").JSX.Element;
|
|
20
|
+
export interface PickerItemProps extends Omit<ComponentProps<'button'>, 'value'> {
|
|
21
|
+
/** what choosing this item reports; default = its own text */
|
|
22
|
+
value?: string;
|
|
11
23
|
}
|
|
12
|
-
/** PickerItem — one value on the Picker rail. */
|
|
13
|
-
export declare function PickerItem({
|
|
24
|
+
/** PickerItem — one value on the Picker rail; a tap brings it to the centre. */
|
|
25
|
+
export declare function PickerItem({ value, className, children, onClick, ...rest }: PickerItemProps): import("react").JSX.Element;
|
package/dist/numbers/Picker.js
CHANGED
|
@@ -1,18 +1,56 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { useEffect, useRef } from 'react';
|
|
2
|
+
import { createContext, useContext, useEffect, useLayoutEffect, useRef, useState } from 'react';
|
|
3
3
|
import { cx } from '../cx.js';
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
const PickerContext = createContext(null);
|
|
5
|
+
/**
|
|
6
|
+
* Picker — a horizontal snap picker, the centre value big between two accent rules; children are PickerItems.
|
|
7
|
+
* It holds a VALUE, controlled like an input: `value` + `onChange`, or `defaultValue`. The value IS the item standing in the centre
|
|
8
|
+
* of the rail: the picker scrolls the chosen one there, and when the member scrolls (or taps an item) it asks for the one that
|
|
9
|
+
* 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
|
+
export function Picker({ value, defaultValue, onChange, unit, label, className, children, ...rest }) {
|
|
12
|
+
const [inner, setInner] = useState(defaultValue);
|
|
13
|
+
const current = value ?? inner;
|
|
6
14
|
const rail = useRef(null);
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
if (
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
15
|
+
const mounted = useRef(false);
|
|
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
|
+
const items = () => [...(rail.current?.querySelectorAll(':scope > .picker__item') ?? [])];
|
|
25
|
+
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
|
+
/* the chosen value stands in the centre — at once on arrival, sliding after */
|
|
27
|
+
useLayoutEffect(() => {
|
|
28
|
+
const r = rail.current, i = items().findIndex((el) => el.dataset.value === current);
|
|
29
|
+
if (r && i >= 0 && Math.abs(r.scrollLeft - i * column()) > 1)
|
|
30
|
+
r.scrollTo({ left: i * column(), behavior: mounted.current ? 'smooth' : 'auto' });
|
|
31
|
+
mounted.current = true;
|
|
32
|
+
});
|
|
33
|
+
useEffect(() => () => { if (settle.current)
|
|
34
|
+
clearTimeout(settle.current); }, []);
|
|
35
|
+
/* the rail came to rest: whatever stands in the centre is what the member chose */
|
|
36
|
+
const scrolled = () => {
|
|
37
|
+
if (settle.current)
|
|
38
|
+
clearTimeout(settle.current);
|
|
39
|
+
settle.current = setTimeout(() => {
|
|
40
|
+
const r = rail.current, col = column();
|
|
41
|
+
if (!r || !col)
|
|
42
|
+
return;
|
|
43
|
+
const at = items()[Math.round(r.scrollLeft / col)]?.dataset.value;
|
|
44
|
+
if (at !== undefined)
|
|
45
|
+
pick(at);
|
|
46
|
+
}, 120);
|
|
47
|
+
};
|
|
48
|
+
return (_jsx(PickerContext.Provider, { value: { value: current, pick }, children: _jsxs("div", { className: cx('picker', className), "aria-label": label, "data-value": current, ...rest, children: [_jsx("div", { className: "picker__rail", role: "listbox", ref: rail, onScroll: scrolled, children: children }), unit != null && _jsx("span", { className: "picker__unit", children: unit })] }) }));
|
|
14
49
|
}
|
|
15
|
-
/** PickerItem — one value on the Picker rail. */
|
|
16
|
-
export function PickerItem({
|
|
17
|
-
|
|
50
|
+
/** PickerItem — one value on the Picker rail; a tap brings it to the centre. */
|
|
51
|
+
export function PickerItem({ value, className, children, onClick, ...rest }) {
|
|
52
|
+
const picker = useContext(PickerContext);
|
|
53
|
+
const own = value ?? (typeof children === 'string' || typeof children === 'number' ? String(children) : undefined);
|
|
54
|
+
return (_jsx("button", { type: "button", role: "option", "data-value": own, "aria-selected": own !== undefined && picker?.value === own ? 'true' : 'false', className: cx('picker__item', className), onClick: (e) => { onClick?.(e); if (!e.defaultPrevented && own !== undefined)
|
|
55
|
+
picker?.pick(own); }, ...rest, children: children }));
|
|
18
56
|
}
|
package/dist/numbers/Ring.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
export interface RingProps extends
|
|
1
|
+
import type { ComponentProps, ReactNode } from 'react';
|
|
2
|
+
export interface RingProps extends ComponentProps<'div'> {
|
|
3
3
|
/** 0–100 */
|
|
4
4
|
value: number;
|
|
5
5
|
/** sm = an avatar-xl ring · xs = an inline counter in a head (2/3) */
|
package/dist/numbers/Track.d.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
export interface TrackProps extends
|
|
1
|
+
import type { ComponentProps } from 'react';
|
|
2
|
+
export interface TrackProps extends ComponentProps<'ol'> {
|
|
3
3
|
label?: string;
|
|
4
4
|
}
|
|
5
5
|
/** Track — step progress in a dark pill: done · done · todo; children are TrackSteps holding an Icon each. */
|
|
6
6
|
export declare function Track({ label, className, ...rest }: TrackProps): import("react").JSX.Element;
|
|
7
|
-
export interface TrackStepProps extends
|
|
7
|
+
export interface TrackStepProps extends ComponentProps<'li'> {
|
|
8
8
|
/** this step (and the connector into it) is done */
|
|
9
9
|
done?: boolean;
|
|
10
10
|
}
|