@usableapp/cardds 0.7.106 → 0.7.108
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 +121 -0
- package/bin/cardds.mjs +5 -3
- package/cardds.css +1 -0
- package/css/actions.css +9 -9
- package/css/base.css +6 -9
- package/css/card.css +19 -186
- package/css/choice.css +26 -1
- package/css/finish.css +4 -4
- package/css/journey.css +7 -3
- package/css/layover.css +4 -14
- package/css/lists.css +6 -18
- package/css/media.css +1 -7
- package/css/palette.css +1 -1
- package/css/parts.css +380 -0
- package/css/sheet.css +12 -139
- package/css/stack.css +15 -26
- package/css/stamp.css +1 -1
- package/css/step.css +3 -3
- package/css/theme.template.css +1 -1
- package/css/tokens.css +4 -4
- package/dist/actions/BarNote.d.ts +2 -2
- package/dist/actions/BarNote.js +2 -2
- package/dist/actions/Btn.d.ts +2 -2
- package/dist/actions/Btn.js +1 -1
- package/dist/actions/BtnRow.d.ts +1 -1
- package/dist/actions/BtnRow.js +1 -1
- package/dist/actions/IconBtn.d.ts +1 -1
- package/dist/actions/IconBtn.js +1 -1
- package/dist/cardds.css +500 -426
- package/dist/cards/Card.d.ts +6 -22
- package/dist/cards/Card.js +11 -22
- package/dist/cards/CardFeed.d.ts +1 -1
- package/dist/cards/CardFeed.js +5 -5
- package/dist/cards/CardParts.d.ts +2 -13
- package/dist/cards/CardParts.js +2 -13
- package/dist/cards/cardGo.js +1 -1
- package/dist/cards/cardGrounds.js +2 -2
- package/dist/catalog.json +1 -1
- package/dist/choice/Calendar.d.ts +12 -3
- package/dist/choice/Calendar.js +17 -5
- package/dist/choice/CalendarWeeks.d.ts +10 -2
- package/dist/choice/CalendarWeeks.js +18 -4
- package/dist/choice/HourGrid.d.ts +36 -0
- package/dist/choice/HourGrid.js +21 -0
- package/dist/choice/calendarDay.d.ts +7 -2
- package/dist/choice/calendarDay.js +6 -3
- package/dist/choice/span.d.ts +34 -0
- package/dist/choice/span.js +80 -0
- package/dist/forms/Field.d.ts +1 -1
- package/dist/forms/Field.js +1 -1
- package/dist/index.d.ts +8 -5
- package/dist/index.js +7 -5
- package/dist/journey/JourneyBadge.d.ts +2 -1
- package/dist/lists/Kv.d.ts +4 -2
- package/dist/lists/Kv.js +3 -3
- package/dist/lists/Row.d.ts +2 -28
- package/dist/lists/Row.js +2 -17
- package/dist/media/MapArea.d.ts +2 -2
- package/dist/media/MapArea.js +1 -1
- package/dist/media/Tile.d.ts +3 -7
- package/dist/media/Tile.js +5 -5
- package/dist/parts/Body.d.ts +7 -0
- package/dist/parts/Body.js +11 -0
- package/dist/parts/End.d.ts +10 -0
- package/dist/parts/End.js +7 -0
- package/dist/parts/Foot.d.ts +17 -0
- package/dist/parts/Foot.js +11 -0
- package/dist/parts/Head.d.ts +15 -0
- package/dist/parts/Head.js +34 -0
- package/dist/parts/Lead.d.ts +10 -0
- package/dist/parts/Lead.js +9 -0
- package/dist/parts/Words.d.ts +13 -0
- package/dist/parts/Words.js +20 -0
- package/dist/parts/headCtx.d.ts +7 -0
- package/dist/parts/headCtx.js +9 -0
- package/dist/scaffold/EmptyState.d.ts +1 -1
- package/dist/scaffold/EmptyState.js +1 -1
- package/dist/scaffold/Screen.js +1 -1
- package/dist/sheets/Modal.d.ts +3 -7
- package/dist/sheets/Modal.js +3 -7
- package/dist/sheets/Sheet.d.ts +2 -2
- package/dist/sheets/Sheet.js +8 -9
- package/dist/sheets/SheetStack.d.ts +3 -3
- package/dist/sheets/SheetStack.js +4 -4
- package/dist/sheets/SheetSteps.d.ts +1 -1
- package/dist/sheets/SheetSteps.js +2 -2
- package/dist/sheets/StackBack.d.ts +1 -1
- package/dist/sheets/StackBack.js +1 -1
- package/dist/sheets/StackSheet.js +7 -7
- package/dist/sheets/sheetMeasure.js +3 -3
- package/dist/sheets/sheetStepsPile.js +2 -2
- package/dist/sheets/stackCard.js +6 -6
- package/dist/templates/CallSheet.js +6 -5
- package/dist/templates/Walkthrough.js +3 -2
- package/docs/reference.md +76 -37
- package/lib/catalog.mjs +1 -1
- package/lib/mcp.mjs +1 -1
- package/lint/rules.mjs +14 -7
- package/package.json +2 -1
- package/scripts/codemod-parts.mjs +403 -0
- package/dist/cards/CardFoot.d.ts +0 -15
- package/dist/cards/CardFoot.js +0 -9
- package/dist/cards/CardHead.d.ts +0 -21
- package/dist/cards/CardHead.js +0 -39
- package/dist/cards/Stat.d.ts +0 -19
- package/dist/cards/Stat.js +0 -14
- package/dist/sheets/SheetBody.d.ts +0 -5
- package/dist/sheets/SheetBody.js +0 -9
- package/dist/sheets/SheetHead.d.ts +0 -15
- package/dist/sheets/SheetHead.js +0 -6
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { type ComponentProps, type ReactNode } from 'react';
|
|
2
|
+
import { type Span } from './span.js';
|
|
2
3
|
export interface CalendarProps extends Omit<ComponentProps<'div'>, 'title' | 'onSelect'> {
|
|
3
4
|
/** the month shown ("June") */
|
|
4
5
|
title: ReactNode;
|
|
@@ -12,6 +13,12 @@ export interface CalendarProps extends Omit<ComponentProps<'div'>, 'title' | 'on
|
|
|
12
13
|
defaultSelected?: number;
|
|
13
14
|
/** a day was tapped */
|
|
14
15
|
onSelect?: (day: number) => void;
|
|
16
|
+
/** CONTROLLED, a run of days instead of one: `[first, last]` (the same day twice for one), or `null` for none; pair it with `onSpanChange`. Given (or `defaultSpan` / `onSpanChange`), the calendar is a span pick: a drag across the days covers them, or a tap on the first and a tap on the last; `selected` is not read */
|
|
17
|
+
span?: Span | null;
|
|
18
|
+
/** UNCONTROLLED: the run covered on arrival; the calendar then keeps its own */
|
|
19
|
+
defaultSpan?: Span;
|
|
20
|
+
/** the member covered a run: the finger lifted after a drag, or the second tap closed it */
|
|
21
|
+
onSpanChange?: (span: Span) => void;
|
|
15
22
|
/** the previous-month button was tapped: the app turns the month (it owns `title`, `days`, `start`) */
|
|
16
23
|
onPrev?: () => void;
|
|
17
24
|
/** the next-month button was tapped: the app turns the month, as with `onPrev` */
|
|
@@ -24,7 +31,7 @@ export interface CalendarProps extends Omit<ComponentProps<'div'>, 'title' | 'on
|
|
|
24
31
|
marks?: number[];
|
|
25
32
|
/** strongly marked days */
|
|
26
33
|
marks2?: number[];
|
|
27
|
-
/** days that cannot be picked */
|
|
34
|
+
/** days that cannot be picked (a span never covers one: the run stops before it) */
|
|
28
35
|
disabled?: number[];
|
|
29
36
|
/** weekday headers, 7 */
|
|
30
37
|
weekdays?: string[];
|
|
@@ -32,5 +39,7 @@ export interface CalendarProps extends Omit<ComponentProps<'div'>, 'title' | 'on
|
|
|
32
39
|
nav?: ReactNode;
|
|
33
40
|
}
|
|
34
41
|
/** 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:
|
|
35
|
-
* the app owns which month (`title`, `days`, `start` + `onPrev` / `onNext`) and which day (`selected` + `onSelect`, or `defaultSelected`).
|
|
36
|
-
|
|
42
|
+
* the app owns which month (`title`, `days`, `start` + `onPrev` / `onNext`) and which day (`selected` + `onSelect`, or `defaultSelected`).
|
|
43
|
+
* A run of days instead of one (the asker says from when to when, Lh 2026-10-21): `span` + `onSpanChange`, or `defaultSpan` — a drag across
|
|
44
|
+
* the days covers them, or a tap on the first day and a tap on the last; the whole run is one highlight, as a finger drags over words. On a sheet, never in a Card: the sheet is the paper the member fills in (Lh 2026-10-18). */
|
|
45
|
+
export declare function Calendar({ title, days, start, selected, defaultSelected, onSelect, span, defaultSpan, onSpanChange, onPrev, onNext, prevLabel, nextLabel, marks, marks2, disabled, weekdays, nav, className, ...rest }: CalendarProps): import("react").JSX.Element;
|
package/dist/choice/Calendar.js
CHANGED
|
@@ -4,12 +4,24 @@ import { cx } from '../cx.js';
|
|
|
4
4
|
import { IconBtn } from '../actions/IconBtn.js';
|
|
5
5
|
import { word } from '../words.js';
|
|
6
6
|
import { calendarDay } from './calendarDay.js';
|
|
7
|
+
import { useSpan } from './span.js';
|
|
7
8
|
/** 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:
|
|
8
|
-
* the app owns which month (`title`, `days`, `start` + `onPrev` / `onNext`) and which day (`selected` + `onSelect`, or `defaultSelected`).
|
|
9
|
-
|
|
9
|
+
* the app owns which month (`title`, `days`, `start` + `onPrev` / `onNext`) and which day (`selected` + `onSelect`, or `defaultSelected`).
|
|
10
|
+
* A run of days instead of one (the asker says from when to when, Lh 2026-10-21): `span` + `onSpanChange`, or `defaultSpan` — a drag across
|
|
11
|
+
* the days covers them, or a tap on the first day and a tap on the last; the whole run is one highlight, as a finger drags over words. On a sheet, never in a Card: the sheet is the paper the member fills in (Lh 2026-10-18). */
|
|
12
|
+
export function Calendar({ title, days = 30, start = 1, selected, defaultSelected, onSelect, span, defaultSpan, onSpanChange, onPrev, onNext, prevLabel = word('previous'), nextLabel = word('next'), marks = [], marks2 = [], disabled = [], weekdays = ['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa'], nav, className, ...rest }) {
|
|
10
13
|
const [day, pick] = useControlled(selected, defaultSelected, onSelect);
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
+
const spanning = span !== undefined || defaultSpan !== undefined || onSpanChange !== undefined;
|
|
15
|
+
// the hook counts cells from 0; the app counts days from 1
|
|
16
|
+
const run = useSpan({
|
|
17
|
+
span: span ? [span[0] - 1, span[1] - 1] : span, defaultSpan: defaultSpan && [defaultSpan[0] - 1, defaultSpan[1] - 1],
|
|
18
|
+
onSpanChange: onSpanChange && ((s) => onSpanChange([s[0] + 1, s[1] + 1])),
|
|
19
|
+
blocked: (i) => i < 0 || i >= days || disabled.includes(i + 1),
|
|
20
|
+
});
|
|
21
|
+
return (_jsxs("div", { className: cx('calendar', spanning && 'calendar--span', 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", ...(spanning ? run.box : {}), children: [weekdays.map((d) => _jsx("span", { className: "calendar__wd", children: d }, d)), Array.from({ length: days }, (_, i) => i + 1).map((d) => (calendarDay({
|
|
22
|
+
key: d, num: d, mark: marks.includes(d), mark2: marks2.includes(d), selected: !spanning && d === day, disabled: disabled.includes(d),
|
|
23
|
+
style: d === 1 ? { '--start': start } : undefined,
|
|
24
|
+
onPick: () => (spanning ? run.tap(d - 1) : pick(d)),
|
|
25
|
+
...(spanning ? { index: d - 1, span: run.at(d - 1) } : {}),
|
|
14
26
|
})))] })] }));
|
|
15
27
|
}
|
|
@@ -28,6 +28,12 @@ export interface CalendarWeeksProps extends Omit<ComponentProps<'div'>, 'onSelec
|
|
|
28
28
|
defaultSelected?: string;
|
|
29
29
|
/** a day was tapped: its `key` */
|
|
30
30
|
onSelect?: (key: string) => void;
|
|
31
|
+
/** CONTROLLED, a run of days instead of one: `[first, last]` by `key` (the same key twice for one day), or `null` for none; pair it with `onSpanChange`. Given (or `defaultSpan` / `onSpanChange`), the weeks are a span pick: a tap on the first day and a tap on the last covers the days between, across the weeks; a drag along a row covers it too (up and down, the box scrolls); `selected` is not read */
|
|
32
|
+
span?: [string, string] | null;
|
|
33
|
+
/** UNCONTROLLED: the run covered on arrival; the weeks then keep their own */
|
|
34
|
+
defaultSpan?: [string, string];
|
|
35
|
+
/** the member covered a run: the finger lifted after a drag, or the second tap closed it */
|
|
36
|
+
onSpanChange?: (span: [string, string]) => void;
|
|
31
37
|
/** weekday heads, 7 */
|
|
32
38
|
weekdays?: string[];
|
|
33
39
|
/** given, the label is a button: the app opens its own month / year pick. Not given, the label is plain words */
|
|
@@ -37,5 +43,7 @@ export interface CalendarWeeksProps extends Omit<ComponentProps<'div'>, 'onSelec
|
|
|
37
43
|
* the month · year of the first row in sight and the weekday heads. It knows no dates, as Calendar: the app builds `weeks` (each a `label` and 7 days
|
|
38
44
|
* with `key`, `num`, `today`, `disabled`, `mark`) and owns the day (`selected` + `onSelect`, or `defaultSelected`); a tap on the label (`onLabelClick`)
|
|
39
45
|
* is the app's to answer with its month / year pick. It opens at the week that holds today (Lh 2026-10-19): the first row in sight is the week
|
|
40
|
-
* whose day has `today`, at once and without a scroll to watch; with no `today` in the data it opens at the first week. For a day within the coming weeks on a step with little height.
|
|
41
|
-
|
|
46
|
+
* whose day has `today`, at once and without a scroll to watch; with no `today` in the data it opens at the first week. For a day within the coming weeks on a step with little height.
|
|
47
|
+
* A run of days instead of one (the asker says from when to when, Lh 2026-10-21): `span` + `onSpanChange`, or `defaultSpan` — a tap on the first day
|
|
48
|
+
* and a tap on the last covers the days between, across the weeks; a drag along a row covers it too, while a finger moving up or down still scrolls the box. On a sheet, never in a Card. */
|
|
49
|
+
export declare function CalendarWeeks({ weeks, show, selected, defaultSelected, onSelect, span, defaultSpan, onSpanChange, weekdays, onLabelClick, className, ref, ...rest }: CalendarWeeksProps): import("react").JSX.Element;
|
|
@@ -3,13 +3,20 @@ import { useLayoutEffect, useRef, useState } from 'react';
|
|
|
3
3
|
import { useControlled, setRefs } from '../state.js';
|
|
4
4
|
import { cx } from '../cx.js';
|
|
5
5
|
import { calendarDay } from './calendarDay.js';
|
|
6
|
+
import { useSpan, spanByKey } from './span.js';
|
|
6
7
|
/** CalendarWeeks — a run of weeks that scrolls week by week, `show` rows in sight (2 by default), Calendar's own 44px round cells; a sticky head holds
|
|
7
8
|
* the month · year of the first row in sight and the weekday heads. It knows no dates, as Calendar: the app builds `weeks` (each a `label` and 7 days
|
|
8
9
|
* with `key`, `num`, `today`, `disabled`, `mark`) and owns the day (`selected` + `onSelect`, or `defaultSelected`); a tap on the label (`onLabelClick`)
|
|
9
10
|
* is the app's to answer with its month / year pick. It opens at the week that holds today (Lh 2026-10-19): the first row in sight is the week
|
|
10
|
-
* whose day has `today`, at once and without a scroll to watch; with no `today` in the data it opens at the first week. For a day within the coming weeks on a step with little height.
|
|
11
|
-
|
|
11
|
+
* whose day has `today`, at once and without a scroll to watch; with no `today` in the data it opens at the first week. For a day within the coming weeks on a step with little height.
|
|
12
|
+
* A run of days instead of one (the asker says from when to when, Lh 2026-10-21): `span` + `onSpanChange`, or `defaultSpan` — a tap on the first day
|
|
13
|
+
* and a tap on the last covers the days between, across the weeks; a drag along a row covers it too, while a finger moving up or down still scrolls the box. On a sheet, never in a Card. */
|
|
14
|
+
export function CalendarWeeks({ weeks, show = 2, selected, defaultSelected, onSelect, span, defaultSpan, onSpanChange, weekdays = ['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa'], onLabelClick, className, ref, ...rest }) {
|
|
12
15
|
const [day, pick] = useControlled(selected, defaultSelected, onSelect);
|
|
16
|
+
const spanning = span !== undefined || defaultSpan !== undefined || onSpanChange !== undefined;
|
|
17
|
+
const all = weeks.flatMap((w) => w.days);
|
|
18
|
+
const covered = useSpan({ ...spanByKey(all.map((d) => d.key), span, defaultSpan, onSpanChange), blocked: (i) => !all[i] || !!all[i].disabled });
|
|
19
|
+
let at = 0;
|
|
13
20
|
const [first, setFirst] = useState(0);
|
|
14
21
|
const box = useRef(null);
|
|
15
22
|
// the box opens at today's week whenever the run itself is new (its days, not its identity: an app that rebuilds `weeks` on each render
|
|
@@ -58,7 +65,14 @@ export function CalendarWeeks({ weeks, show = 2, selected, defaultSelected, onSe
|
|
|
58
65
|
return () => { watch.disconnect(); el.removeEventListener('scroll', onScroll); cancelAnimationFrame(frame); };
|
|
59
66
|
}, [show, run, todayAt]);
|
|
60
67
|
const label = weeks[Math.min(first, weeks.length - 1)]?.label;
|
|
61
|
-
return (_jsxs("div", { ref: setRefs(box, ref), className: cx('calendar', 'calendar--weeks', className), ...rest, children: [_jsxs("div", { className: "calendar__weeks-head", children: [onLabelClick
|
|
68
|
+
return (_jsxs("div", { ref: setRefs(box, ref), className: cx('calendar', 'calendar--weeks', spanning && 'calendar--span', className), ...rest, ...(spanning ? covered.box : {}), children: [_jsxs("div", { className: "calendar__weeks-head", children: [onLabelClick
|
|
62
69
|
? _jsx("button", { type: "button", className: "calendar__label", onClick: onLabelClick, children: label })
|
|
63
|
-
: _jsx("span", { className: "calendar__label", children: label }), _jsx("div", { className: "calendar__grid", children: weekdays.map((d) => _jsx("span", { className: "calendar__wd", children: d }, d)) })] }), weeks.map((w, i) => (_jsx("div", { className: "calendar__grid calendar__week", children: w.days.map((d) =>
|
|
70
|
+
: _jsx("span", { className: "calendar__label", children: label }), _jsx("div", { className: "calendar__grid", children: weekdays.map((d) => _jsx("span", { className: "calendar__wd", children: d }, d)) })] }), weeks.map((w, i) => (_jsx("div", { className: "calendar__grid calendar__week", children: w.days.map((d) => {
|
|
71
|
+
const i = at++;
|
|
72
|
+
return calendarDay({
|
|
73
|
+
key: d.key, num: d.num, mark: d.mark === 'soft', mark2: d.mark === 'strong', selected: !spanning && d.key === day, today: d.today, disabled: d.disabled,
|
|
74
|
+
onPick: () => (spanning ? covered.tap(i) : pick(d.key)),
|
|
75
|
+
...(spanning ? { index: i, span: covered.at(i) } : {}),
|
|
76
|
+
});
|
|
77
|
+
}) }, w.days[0]?.key ?? i)))] }));
|
|
64
78
|
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { type ComponentProps, type ReactNode } from 'react';
|
|
2
|
+
export interface Hour {
|
|
3
|
+
/** the app's id for the hour ("09:00"): what `onSpanChange` and `onSelect` hand back */
|
|
4
|
+
key: string;
|
|
5
|
+
/** what the cell shows ("9", "๙") */
|
|
6
|
+
num: ReactNode;
|
|
7
|
+
/** the hour cannot be picked (already past, outside the asked span) */
|
|
8
|
+
disabled?: boolean;
|
|
9
|
+
/** a soft mark (the asked hours) or a strong one (booked) */
|
|
10
|
+
mark?: 'soft' | 'strong';
|
|
11
|
+
}
|
|
12
|
+
export interface HourGridProps extends Omit<ComponentProps<'div'>, 'onSelect'> {
|
|
13
|
+
/** the hours, in order; the app builds them (which hours, in whose numerals) */
|
|
14
|
+
hours: Hour[];
|
|
15
|
+
/** the words over the grid: what the numbers are ("hour of the day", "น.") */
|
|
16
|
+
label?: ReactNode;
|
|
17
|
+
/** CONTROLLED, from when to when: `[first, last]` by `key` (the same key twice for one hour), or `null` for none; pair it with `onSpanChange`. Given (or `defaultSpan` / `onSpanChange`), a drag across the hours covers them, or a tap on the first and a tap on the last; `selected` is not read */
|
|
18
|
+
span?: [string, string] | null;
|
|
19
|
+
/** UNCONTROLLED: the run covered on arrival; the grid then keeps its own */
|
|
20
|
+
defaultSpan?: [string, string];
|
|
21
|
+
/** the member covered a run: the finger lifted after a drag, or the second tap closed it */
|
|
22
|
+
onSpanChange?: (span: [string, string]) => void;
|
|
23
|
+
/** CONTROLLED, one hour: the picked hour's `key`, or `null` for none; pair it with `onSelect` */
|
|
24
|
+
selected?: string | null;
|
|
25
|
+
/** UNCONTROLLED: the hour picked on arrival */
|
|
26
|
+
defaultSelected?: string;
|
|
27
|
+
/** an hour was tapped: its `key` */
|
|
28
|
+
onSelect?: (key: string) => void;
|
|
29
|
+
}
|
|
30
|
+
/** HourGrid — the hours of a day as Calendar's own 44px round cells, `--hour-grid-cols` to a row (6 by default), with a label over them. From when
|
|
31
|
+
* to when (the asker's hours, Lh 2026-10-21): `span` + `onSpanChange`, or `defaultSpan` — one drag across the hours covers them, or a tap on the
|
|
32
|
+
* first and a tap on the last; the whole run is one highlight, and it never jumps a disabled hour.
|
|
33
|
+
* One hour instead: `selected` + `onSelect`, or `defaultSelected`. The helper answers within the asked hours: the app marks them (`mark: 'soft'`)
|
|
34
|
+
* and disables the rest, and the helper's own span stays inside. It knows no clock: the app builds `hours` (`key`, `num`, `disabled`, `mark`).
|
|
35
|
+
* On a sheet, never in a Card. */
|
|
36
|
+
export declare function HourGrid({ hours, label, span, defaultSpan, onSpanChange, selected, defaultSelected, onSelect, className, ...rest }: HourGridProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useControlled } from '../state.js';
|
|
3
|
+
import { cx } from '../cx.js';
|
|
4
|
+
import { calendarDay } from './calendarDay.js';
|
|
5
|
+
import { useSpan, spanByKey } from './span.js';
|
|
6
|
+
/** HourGrid — the hours of a day as Calendar's own 44px round cells, `--hour-grid-cols` to a row (6 by default), with a label over them. From when
|
|
7
|
+
* to when (the asker's hours, Lh 2026-10-21): `span` + `onSpanChange`, or `defaultSpan` — one drag across the hours covers them, or a tap on the
|
|
8
|
+
* first and a tap on the last; the whole run is one highlight, and it never jumps a disabled hour.
|
|
9
|
+
* One hour instead: `selected` + `onSelect`, or `defaultSelected`. The helper answers within the asked hours: the app marks them (`mark: 'soft'`)
|
|
10
|
+
* and disables the rest, and the helper's own span stays inside. It knows no clock: the app builds `hours` (`key`, `num`, `disabled`, `mark`).
|
|
11
|
+
* On a sheet, never in a Card. */
|
|
12
|
+
export function HourGrid({ hours, label, span, defaultSpan, onSpanChange, selected, defaultSelected, onSelect, className, ...rest }) {
|
|
13
|
+
const spanning = span !== undefined || defaultSpan !== undefined || onSpanChange !== undefined;
|
|
14
|
+
const [hour, pick] = useControlled(selected, defaultSelected, onSelect);
|
|
15
|
+
const run = useSpan({ ...spanByKey(hours.map((h) => h.key), span, defaultSpan, onSpanChange), blocked: (i) => !hours[i] || !!hours[i].disabled });
|
|
16
|
+
return (_jsxs("div", { className: cx('calendar', 'hour-grid', spanning && 'calendar--span', className), ...rest, children: [label != null && _jsx("span", { className: "calendar__label", children: label }), _jsx("div", { className: "calendar__grid", ...(spanning ? run.box : {}), children: hours.map((h, i) => calendarDay({
|
|
17
|
+
key: h.key, num: h.num, mark: h.mark === 'soft', mark2: h.mark === 'strong', selected: !spanning && h.key === hour, disabled: h.disabled,
|
|
18
|
+
onPick: () => (spanning ? run.tap(i) : pick(h.key)),
|
|
19
|
+
...(spanning ? { index: i, span: run.at(i) } : {}),
|
|
20
|
+
})) })] }));
|
|
21
|
+
}
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { type CSSProperties, type ReactNode } from 'react';
|
|
2
|
-
|
|
3
|
-
|
|
2
|
+
import type { SpanAt } from './span.js';
|
|
3
|
+
/** one `.calendar__day` cell: the button Calendar, CalendarWeeks and HourGrid all draw, so the cell and every `--calendar-day-*` knob are one.
|
|
4
|
+
* In a span (`index` given): the cell carries its order for the span mechanic, and `span` says where it stands under the one highlight
|
|
5
|
+
* (`aria-pressed` says whether it is covered); a key on the cell (not a pointer, which the grid handles) is a tap */
|
|
6
|
+
export declare function calendarDay({ key, num, mark, mark2, selected, today, disabled, style, onPick, index, span }: {
|
|
4
7
|
key: string | number;
|
|
5
8
|
num: ReactNode;
|
|
6
9
|
mark?: boolean;
|
|
@@ -10,4 +13,6 @@ export declare function calendarDay({ key, num, mark, mark2, selected, today, di
|
|
|
10
13
|
disabled?: boolean;
|
|
11
14
|
style?: CSSProperties;
|
|
12
15
|
onPick: () => void;
|
|
16
|
+
index?: number;
|
|
17
|
+
span?: SpanAt;
|
|
13
18
|
}): import("react").JSX.Element;
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import { cx } from '../cx.js';
|
|
3
|
-
/** one `.calendar__day` cell: the button Calendar and
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
/** one `.calendar__day` cell: the button Calendar, CalendarWeeks and HourGrid all draw, so the cell and every `--calendar-day-*` knob are one.
|
|
4
|
+
* In a span (`index` given): the cell carries its order for the span mechanic, and `span` says where it stands under the one highlight
|
|
5
|
+
* (`aria-pressed` says whether it is covered); a key on the cell (not a pointer, which the grid handles) is a tap */
|
|
6
|
+
export function calendarDay({ key, num, mark, mark2, selected, today, disabled, style, onPick, index, span }) {
|
|
7
|
+
return (_jsx("button", { type: "button", className: cx('calendar__day', mark && 'calendar__day--mark', mark2 && 'calendar__day--mark2', span && `calendar__day--span-${span}`), "aria-selected": selected ? 'true' : undefined, "aria-pressed": index === undefined ? undefined : span ? 'true' : 'false', "aria-current": today ? 'date' : undefined, onClick: index === undefined ? onPick : (e) => { if (e.detail === 0)
|
|
8
|
+
onPick(); }, disabled: disabled, style: style, "data-span": index, children: num }, key));
|
|
6
9
|
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { type PointerEvent as ReactPointerEvent } from 'react';
|
|
2
|
+
/** a run of cells, by their index in the holder's order: `[first, last]`, the same index twice for one cell */
|
|
3
|
+
export type Span = [number, number];
|
|
4
|
+
/** where a cell stands in the span: the one cell of a one-cell span, the first, one between, the last — or nowhere */
|
|
5
|
+
export type SpanAt = 'one' | 'start' | 'in' | 'end' | undefined;
|
|
6
|
+
/** the span mechanic, written once for Calendar, CalendarWeeks and HourGrid (Lh 2026-10-21: the asker says from when to when).
|
|
7
|
+
* The holder numbers its cells in order (`data-span` = the index), spreads `box` on the grid, and asks `at(i)` for each cell's class.
|
|
8
|
+
* One drag across the cells covers them: the first cell under the finger is one end, the last the other, whichever way the finger
|
|
9
|
+
* went. Two taps do the same without a drag: a tap makes a one-cell span, a second tap on another cell closes it (a third starts over).
|
|
10
|
+
* A cell that is `blocked` (disabled) is never covered: the run stops before it, so a span never jumps a day that cannot be picked.
|
|
11
|
+
* Controlled like an input: `span` + `onSpanChange`, or `defaultSpan`; while the finger is down the cells show the live run and the
|
|
12
|
+
* app is asked once, when it lifts. A pointer the browser takes away (the box scrolled instead) covers nothing. */
|
|
13
|
+
export declare function useSpan({ span, defaultSpan, onSpanChange, blocked }: {
|
|
14
|
+
span: Span | null | undefined;
|
|
15
|
+
defaultSpan?: Span;
|
|
16
|
+
onSpanChange?: (span: Span) => void;
|
|
17
|
+
blocked: (i: number) => boolean;
|
|
18
|
+
}): {
|
|
19
|
+
span: Span | null;
|
|
20
|
+
at: (i: number) => SpanAt;
|
|
21
|
+
tap: (i: number) => void;
|
|
22
|
+
box: {
|
|
23
|
+
onPointerDown: (e: ReactPointerEvent<HTMLElement>) => void;
|
|
24
|
+
onPointerMove: (e: ReactPointerEvent<HTMLElement>) => void;
|
|
25
|
+
onPointerUp: () => void;
|
|
26
|
+
onPointerCancel: () => void;
|
|
27
|
+
};
|
|
28
|
+
};
|
|
29
|
+
/** the same span by the holder's keys (CalendarWeeks, HourGrid): useSpan's `span`, `defaultSpan` and `onSpanChange` from a `[key, key]` span, the ask handed back in keys */
|
|
30
|
+
export declare function spanByKey(keys: string[], span: [string, string] | null | undefined, defaultSpan: [string, string] | undefined, onSpanChange: ((span: [string, string]) => void) | undefined): {
|
|
31
|
+
span: Span | null | undefined;
|
|
32
|
+
defaultSpan: Span | undefined;
|
|
33
|
+
onSpanChange: ((s: Span) => void) | undefined;
|
|
34
|
+
};
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { useRef, useState } from 'react';
|
|
2
|
+
import { useControlled } from '../state.js';
|
|
3
|
+
const sorted = (a, b) => (a <= b ? [a, b] : [b, a]);
|
|
4
|
+
/** the span mechanic, written once for Calendar, CalendarWeeks and HourGrid (Lh 2026-10-21: the asker says from when to when).
|
|
5
|
+
* The holder numbers its cells in order (`data-span` = the index), spreads `box` on the grid, and asks `at(i)` for each cell's class.
|
|
6
|
+
* One drag across the cells covers them: the first cell under the finger is one end, the last the other, whichever way the finger
|
|
7
|
+
* went. Two taps do the same without a drag: a tap makes a one-cell span, a second tap on another cell closes it (a third starts over).
|
|
8
|
+
* A cell that is `blocked` (disabled) is never covered: the run stops before it, so a span never jumps a day that cannot be picked.
|
|
9
|
+
* Controlled like an input: `span` + `onSpanChange`, or `defaultSpan`; while the finger is down the cells show the live run and the
|
|
10
|
+
* app is asked once, when it lifts. A pointer the browser takes away (the box scrolled instead) covers nothing. */
|
|
11
|
+
export function useSpan({ span, defaultSpan, onSpanChange, blocked }) {
|
|
12
|
+
const [held, request] = useControlled(span, defaultSpan ?? null, onSpanChange);
|
|
13
|
+
const [live, setLive] = useState(null);
|
|
14
|
+
const drag = useRef(null);
|
|
15
|
+
// the farthest cell toward `to` the run from `from` reaches before a blocked cell
|
|
16
|
+
const reach = (from, to) => {
|
|
17
|
+
const step = to < from ? -1 : 1;
|
|
18
|
+
let at = from;
|
|
19
|
+
while (at !== to && !blocked(at + step))
|
|
20
|
+
at += step;
|
|
21
|
+
return at;
|
|
22
|
+
};
|
|
23
|
+
const cellAt = (box, x, y) => {
|
|
24
|
+
const cell = document.elementFromPoint(x, y)?.closest('[data-span]');
|
|
25
|
+
return cell && box.contains(cell) ? Number(cell.dataset.span) : null;
|
|
26
|
+
};
|
|
27
|
+
// a tap on `i` (a finger that did not move, or a key on the cell): the second end of a one-cell span, else a new one-cell span
|
|
28
|
+
const tap = (i) => {
|
|
29
|
+
const one = held && held[0] === held[1] ? held[0] : null;
|
|
30
|
+
request(one !== null && one !== i ? sorted(one, reach(one, i)) : [i, i]);
|
|
31
|
+
};
|
|
32
|
+
const onPointerDown = (e) => {
|
|
33
|
+
const cell = e.target.closest('[data-span]');
|
|
34
|
+
if (!cell || !e.currentTarget.contains(cell))
|
|
35
|
+
return;
|
|
36
|
+
const i = Number(cell.dataset.span);
|
|
37
|
+
if (blocked(i))
|
|
38
|
+
return;
|
|
39
|
+
e.currentTarget.setPointerCapture(e.pointerId);
|
|
40
|
+
drag.current = { from: i, to: i, moved: false };
|
|
41
|
+
setLive([i, i]);
|
|
42
|
+
};
|
|
43
|
+
const onPointerMove = (e) => {
|
|
44
|
+
const d = drag.current;
|
|
45
|
+
if (!d)
|
|
46
|
+
return;
|
|
47
|
+
const i = cellAt(e.currentTarget, e.clientX, e.clientY);
|
|
48
|
+
if (i === null || i === d.to)
|
|
49
|
+
return;
|
|
50
|
+
d.moved = true;
|
|
51
|
+
d.to = reach(d.from, i);
|
|
52
|
+
setLive(sorted(d.from, d.to));
|
|
53
|
+
};
|
|
54
|
+
const onPointerUp = () => {
|
|
55
|
+
const d = drag.current;
|
|
56
|
+
if (!d)
|
|
57
|
+
return;
|
|
58
|
+
drag.current = null;
|
|
59
|
+
setLive(null);
|
|
60
|
+
if (d.moved)
|
|
61
|
+
request(sorted(d.from, d.to));
|
|
62
|
+
else
|
|
63
|
+
tap(d.from);
|
|
64
|
+
};
|
|
65
|
+
const onPointerCancel = () => { drag.current = null; setLive(null); };
|
|
66
|
+
const shown = live ?? held ?? null;
|
|
67
|
+
const at = (i) => {
|
|
68
|
+
if (!shown)
|
|
69
|
+
return undefined;
|
|
70
|
+
if (shown[0] === shown[1])
|
|
71
|
+
return i === shown[0] ? 'one' : undefined;
|
|
72
|
+
return i === shown[0] ? 'start' : i === shown[1] ? 'end' : i > shown[0] && i < shown[1] ? 'in' : undefined;
|
|
73
|
+
};
|
|
74
|
+
return { span: shown, at, tap, box: { onPointerDown, onPointerMove, onPointerUp, onPointerCancel } };
|
|
75
|
+
}
|
|
76
|
+
/** the same span by the holder's keys (CalendarWeeks, HourGrid): useSpan's `span`, `defaultSpan` and `onSpanChange` from a `[key, key]` span, the ask handed back in keys */
|
|
77
|
+
export function spanByKey(keys, span, defaultSpan, onSpanChange) {
|
|
78
|
+
const of = (s) => (s ? [keys.indexOf(s[0]), keys.indexOf(s[1])] : s);
|
|
79
|
+
return { span: of(span), defaultSpan: of(defaultSpan) ?? undefined, onSpanChange: onSpanChange && ((s) => onSpanChange([keys[s[0]], keys[s[1]]])) };
|
|
80
|
+
}
|
package/dist/forms/Field.d.ts
CHANGED
|
@@ -38,7 +38,7 @@ export interface FieldProps extends Omit<ComponentProps<'input'>, 'className' |
|
|
|
38
38
|
export declare function applyMask(v: string, mask: string): string;
|
|
39
39
|
/**
|
|
40
40
|
* Field — the flat outlined input, and where a form field goes is the SHEET: the paper the member fills in, never a Card (Lh 2026-10-18).
|
|
41
|
-
* It stands on a Sheet's `
|
|
41
|
+
* It stands on a Sheet's `Body`, in a `SheetStep`, or on a stack sheet, 1–3 per step; a card is for reading and pressing buttons
|
|
42
42
|
* (`cardds check` rule `field-in-card` flags a Field, or any control the member fills or picks, inside a `<Card>`).
|
|
43
43
|
* The LABEL IS THE PLACEHOLDER. 48px tall (56px with an action inside).
|
|
44
44
|
* Variation `rows={n}`: several lines in the same frame, for what the member writes in words (the request and its reason on the ask
|
package/dist/forms/Field.js
CHANGED
|
@@ -21,7 +21,7 @@ export function applyMask(v, mask) {
|
|
|
21
21
|
}
|
|
22
22
|
/**
|
|
23
23
|
* Field — the flat outlined input, and where a form field goes is the SHEET: the paper the member fills in, never a Card (Lh 2026-10-18).
|
|
24
|
-
* It stands on a Sheet's `
|
|
24
|
+
* It stands on a Sheet's `Body`, in a `SheetStep`, or on a stack sheet, 1–3 per step; a card is for reading and pressing buttons
|
|
25
25
|
* (`cardds check` rule `field-in-card` flags a Field, or any control the member fills or picks, inside a `<Card>`).
|
|
26
26
|
* The LABEL IS THE PLACEHOLDER. 48px tall (56px with an action inside).
|
|
27
27
|
* Variation `rows={n}`: several lines in the same frame, for what the member writes in words (the request and its reason on the ask
|
package/dist/index.d.ts
CHANGED
|
@@ -23,17 +23,12 @@ export * from './scaffold/LayerHistory.js';
|
|
|
23
23
|
export * from './cards/Card.js';
|
|
24
24
|
export * from './cards/cardGrounds.js';
|
|
25
25
|
export * from './cards/inkGrounds.js';
|
|
26
|
-
export * from './cards/CardHead.js';
|
|
27
|
-
export * from './cards/CardFoot.js';
|
|
28
26
|
export * from './cards/CardParts.js';
|
|
29
27
|
export * from './cards/CardFeed.js';
|
|
30
|
-
export * from './cards/Stat.js';
|
|
31
28
|
export * from './cards/Placeholder.js';
|
|
32
29
|
export * from './sheets/SheetStack.js';
|
|
33
30
|
export * from './sheets/StackBack.js';
|
|
34
31
|
export * from './sheets/Sheet.js';
|
|
35
|
-
export * from './sheets/SheetHead.js';
|
|
36
|
-
export * from './sheets/SheetBody.js';
|
|
37
32
|
export * from './sheets/SheetStage.js';
|
|
38
33
|
export * from './sheets/Step.js';
|
|
39
34
|
export * from './sheets/SheetSteps.js';
|
|
@@ -58,6 +53,8 @@ export * from './choice/Check.js';
|
|
|
58
53
|
export * from './choice/DayStrip.js';
|
|
59
54
|
export * from './choice/Calendar.js';
|
|
60
55
|
export * from './choice/CalendarWeeks.js';
|
|
56
|
+
export * from './choice/HourGrid.js';
|
|
57
|
+
export type { Span, SpanAt } from './choice/span.js';
|
|
61
58
|
export * from './choice/Mood.js';
|
|
62
59
|
export * from './choice/Slider.js';
|
|
63
60
|
export * from './numbers/Ring.js';
|
|
@@ -72,6 +69,12 @@ export * from './numbers/Bars.js';
|
|
|
72
69
|
export * from './people/Avatar.js';
|
|
73
70
|
export * from './people/AvatarPick.js';
|
|
74
71
|
export * from './lists/Row.js';
|
|
72
|
+
export * from './parts/Head.js';
|
|
73
|
+
export * from './parts/Lead.js';
|
|
74
|
+
export * from './parts/Words.js';
|
|
75
|
+
export * from './parts/Body.js';
|
|
76
|
+
export * from './parts/Foot.js';
|
|
77
|
+
export * from './parts/End.js';
|
|
75
78
|
export * from './lists/Kv.js';
|
|
76
79
|
export * from './lists/Timeline.js';
|
|
77
80
|
export * from './lists/Legend.js';
|
package/dist/index.js
CHANGED
|
@@ -27,17 +27,12 @@ export * from './scaffold/LayerHistory.js';
|
|
|
27
27
|
export * from './cards/Card.js';
|
|
28
28
|
export * from './cards/cardGrounds.js';
|
|
29
29
|
export * from './cards/inkGrounds.js';
|
|
30
|
-
export * from './cards/CardHead.js';
|
|
31
|
-
export * from './cards/CardFoot.js';
|
|
32
30
|
export * from './cards/CardParts.js';
|
|
33
31
|
export * from './cards/CardFeed.js';
|
|
34
|
-
export * from './cards/Stat.js';
|
|
35
32
|
export * from './cards/Placeholder.js';
|
|
36
33
|
export * from './sheets/SheetStack.js';
|
|
37
34
|
export * from './sheets/StackBack.js';
|
|
38
35
|
export * from './sheets/Sheet.js';
|
|
39
|
-
export * from './sheets/SheetHead.js';
|
|
40
|
-
export * from './sheets/SheetBody.js';
|
|
41
36
|
export * from './sheets/SheetStage.js';
|
|
42
37
|
export * from './sheets/Step.js';
|
|
43
38
|
export * from './sheets/SheetSteps.js';
|
|
@@ -62,6 +57,7 @@ export * from './choice/Check.js';
|
|
|
62
57
|
export * from './choice/DayStrip.js';
|
|
63
58
|
export * from './choice/Calendar.js';
|
|
64
59
|
export * from './choice/CalendarWeeks.js';
|
|
60
|
+
export * from './choice/HourGrid.js';
|
|
65
61
|
export * from './choice/Mood.js';
|
|
66
62
|
export * from './choice/Slider.js';
|
|
67
63
|
export * from './numbers/Ring.js';
|
|
@@ -76,6 +72,12 @@ export * from './numbers/Bars.js';
|
|
|
76
72
|
export * from './people/Avatar.js';
|
|
77
73
|
export * from './people/AvatarPick.js';
|
|
78
74
|
export * from './lists/Row.js';
|
|
75
|
+
export * from './parts/Head.js';
|
|
76
|
+
export * from './parts/Lead.js';
|
|
77
|
+
export * from './parts/Words.js';
|
|
78
|
+
export * from './parts/Body.js';
|
|
79
|
+
export * from './parts/Foot.js';
|
|
80
|
+
export * from './parts/End.js';
|
|
79
81
|
export * from './lists/Kv.js';
|
|
80
82
|
export * from './lists/Timeline.js';
|
|
81
83
|
export * from './lists/Legend.js';
|
|
@@ -8,7 +8,8 @@ export interface JourneyBadgeProps extends ComponentProps<'span'> {
|
|
|
8
8
|
sub?: ReactNode;
|
|
9
9
|
/** no fill: a date box beside a title (Jun / 18) */
|
|
10
10
|
plain?: boolean;
|
|
11
|
-
/** pinned to a CardMedia's corner (rating, price)
|
|
11
|
+
/** pinned to a CardMedia's corner (rating, price, a distance). On a CardMedia: the paper (`--card-1-bg`), its corner concentric with the media's;
|
|
12
|
+
* a theme's `--tile-badge-bg` / `--tile-badge-radius` still win. Ruled (Lh 2026-10-21) */
|
|
12
13
|
corner?: boolean;
|
|
13
14
|
/** a date in a card's head: as tall as the title block beside it, no taller — two lines beside a one-line title (day over number · month),
|
|
14
15
|
* three beside a two-line title (day · number · month). Write it as the head's last child, after the title block */
|
package/dist/lists/Kv.d.ts
CHANGED
|
@@ -15,9 +15,11 @@ export interface KvRowProps extends ComponentProps<'div'> {
|
|
|
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
17
|
export interface KvGridProps extends ComponentProps<'div'> {
|
|
18
|
+
/** the one number in the middle of the room it stands in (a turning card's back, a Centre): the grid takes its holder's height and stands its cells in the middle of it, each cell's value and caption centred */
|
|
19
|
+
centre?: boolean;
|
|
18
20
|
}
|
|
19
|
-
/** KvGrid — value-over-label cells split by a rule (Sex | Weight); children are KVCells. */
|
|
20
|
-
export declare function KvGrid({ className, ...rest }: KvGridProps): import("react").JSX.Element;
|
|
21
|
+
/** KvGrid — value-over-label cells split by a rule (Sex | Weight); children are KVCells. `centre`: one cell at the middle of a card's back (a code the member copies). */
|
|
22
|
+
export declare function KvGrid({ centre, className, ...rest }: KvGridProps): import("react").JSX.Element;
|
|
21
23
|
export interface KvCellProps extends ComponentProps<'div'> {
|
|
22
24
|
/** an icon before the value */
|
|
23
25
|
icon?: IconName;
|
package/dist/lists/Kv.js
CHANGED
|
@@ -9,9 +9,9 @@ export function Kv({ lined, className, ...rest }) {
|
|
|
9
9
|
export function KvRow({ label, className, children, ...rest }) {
|
|
10
10
|
return (_jsxs("div", { className: cx('kv__row', className), ...rest, children: [_jsx("dt", { className: "kv__key", children: label }), _jsx("dd", { className: "kv__val", children: children })] }));
|
|
11
11
|
}
|
|
12
|
-
/** KvGrid — value-over-label cells split by a rule (Sex | Weight); children are KVCells. */
|
|
13
|
-
export function KvGrid({ className, ...rest }) {
|
|
14
|
-
return _jsx("div", { className: cx('kv-grid', className), ...rest });
|
|
12
|
+
/** KvGrid — value-over-label cells split by a rule (Sex | Weight); children are KVCells. `centre`: one cell at the middle of a card's back (a code the member copies). */
|
|
13
|
+
export function KvGrid({ centre, className, ...rest }) {
|
|
14
|
+
return _jsx("div", { className: cx('kv-grid', centre && 'kv-grid--centre', className), ...rest });
|
|
15
15
|
}
|
|
16
16
|
/** KvCell — an icon, a big value, a caption label. */
|
|
17
17
|
export function KvCell({ icon, value, label, className, ...rest }) {
|
package/dist/lists/Row.d.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { type ComponentProps, type ReactNode } from 'react';
|
|
2
|
-
import { type IconName } from '../type/Icon.js';
|
|
3
2
|
export interface RowProps extends Omit<ComponentProps<'div'>, 'title'> {
|
|
4
3
|
/** menu row: more air, a bigger title */
|
|
5
4
|
lg?: boolean;
|
|
@@ -21,8 +20,8 @@ export interface RowProps extends Omit<ComponentProps<'div'>, 'title'> {
|
|
|
21
20
|
onOpenChange?: (open: boolean) => void;
|
|
22
21
|
}
|
|
23
22
|
/**
|
|
24
|
-
* Row — a frameless row inside a card: lead ·
|
|
25
|
-
* The lead is a `
|
|
23
|
+
* Row — a frameless row inside a card: lead · words · end, its children in that order. 48px+ tall, a tap target.
|
|
24
|
+
* The lead is a `Lead` box, or a bare Avatar / AvatarStack; the words are a `Words`; the end is an `End` (a value and its caption)
|
|
26
25
|
* or a bare control (two side by side).
|
|
27
26
|
* Several go in Rows (hairlines between). A row that IS a card is `Card row`.
|
|
28
27
|
* `done` is the checklist's finished line: ticked, muted, not tappable any more.
|
|
@@ -30,31 +29,6 @@ export interface RowProps extends Omit<ComponentProps<'div'>, 'title'> {
|
|
|
30
29
|
* A chevron at the end turns when it is open — the app fetches whatever `more` lists; the row only shows it.
|
|
31
30
|
*/
|
|
32
31
|
export declare function Row({ lg, done, as, href, more, open, defaultOpen, onOpenChange, className, children, ...rest }: RowProps): import("react").JSX.Element;
|
|
33
|
-
export interface RowLeadProps extends ComponentProps<'span'> {
|
|
34
|
-
/** an icon drawn in the box; without it, the box holds its children */
|
|
35
|
-
icon?: IconName;
|
|
36
|
-
}
|
|
37
|
-
/** RowLead — a Row's lead: the outlined 48px box of a menu row, holding an `icon` or its children.
|
|
38
|
-
* A person's or a group's lead takes no box: an Avatar or an AvatarStack goes straight in the Row as its first child. */
|
|
39
|
-
export declare function RowLead({ icon, className, children, ...rest }: RowLeadProps): import("react").JSX.Element;
|
|
40
|
-
export interface RowBodyProps extends Omit<ComponentProps<'div'>, 'title'> {
|
|
41
|
-
/** the title line */
|
|
42
|
-
title?: ReactNode;
|
|
43
|
-
/** the caption under it (may hold a Dot) */
|
|
44
|
-
meta?: ReactNode;
|
|
45
|
-
}
|
|
46
|
-
/** RowBody — a Row's words, filling the room between lead and end: a `title` over a `meta` caption;
|
|
47
|
-
* its children come under them, or instead of them (a Wave for a voice note). */
|
|
48
|
-
export declare function RowBody({ title, meta, className, children, ...rest }: RowBodyProps): import("react").JSX.Element;
|
|
49
|
-
export interface RowEndProps extends ComponentProps<'span'> {
|
|
50
|
-
/** the trailing value, right-aligned (title type) */
|
|
51
|
-
value?: ReactNode;
|
|
52
|
-
/** the muted caption under `value` */
|
|
53
|
-
caption?: ReactNode;
|
|
54
|
-
}
|
|
55
|
-
/** RowEnd — a Row's trailing value: a `value` over its muted `caption`, right-aligned (+1.0 h over Tue); or its children.
|
|
56
|
-
* A control at the end (an IconBtn, a Chip, a Check) takes no RowEnd: it goes straight in the Row after the RowBody. */
|
|
57
|
-
export declare function RowEnd({ value, caption, className, children, ...rest }: RowEndProps): import("react").JSX.Element;
|
|
58
32
|
export interface RowsProps extends ComponentProps<'div'> {
|
|
59
33
|
/** the group's name, above its rows (Today · Tomorrow · Later): a long list is GROUPED, not spaced out — several Rows one after another.
|
|
60
34
|
* Words = the small label; an ELEMENT (`<Text level="title" as="h3">`) is used as the heading itself — the group is labelled by it. */
|
package/dist/lists/Row.js
CHANGED
|
@@ -4,8 +4,8 @@ import { cx } from '../cx.js';
|
|
|
4
4
|
import { Icon } from '../type/Icon.js';
|
|
5
5
|
import { glide, reducedMotion, setRefs, stopMoves, useDisclosure } from '../state.js';
|
|
6
6
|
/**
|
|
7
|
-
* Row — a frameless row inside a card: lead ·
|
|
8
|
-
* The lead is a `
|
|
7
|
+
* Row — a frameless row inside a card: lead · words · end, its children in that order. 48px+ tall, a tap target.
|
|
8
|
+
* The lead is a `Lead` box, or a bare Avatar / AvatarStack; the words are a `Words`; the end is an `End` (a value and its caption)
|
|
9
9
|
* or a bare control (two side by side).
|
|
10
10
|
* Several go in Rows (hairlines between). A row that IS a card is `Card row`.
|
|
11
11
|
* `done` is the checklist's finished line: ticked, muted, not tappable any more.
|
|
@@ -20,21 +20,6 @@ export function Row({ lg, done, as, href, more, open, defaultOpen, onOpenChange,
|
|
|
20
20
|
return row;
|
|
21
21
|
return (_jsxs("details", { className: "row-expand", ...rest, ...disclosure, children: [row, _jsx("div", { className: "row-expand__more", children: more })] }));
|
|
22
22
|
}
|
|
23
|
-
/** RowLead — a Row's lead: the outlined 48px box of a menu row, holding an `icon` or its children.
|
|
24
|
-
* A person's or a group's lead takes no box: an Avatar or an AvatarStack goes straight in the Row as its first child. */
|
|
25
|
-
export function RowLead({ icon, className, children, ...rest }) {
|
|
26
|
-
return _jsx("span", { className: cx('row__lead', className), ...rest, children: icon ? _jsx(Icon, { name: icon }) : children });
|
|
27
|
-
}
|
|
28
|
-
/** RowBody — a Row's words, filling the room between lead and end: a `title` over a `meta` caption;
|
|
29
|
-
* its children come under them, or instead of them (a Wave for a voice note). */
|
|
30
|
-
export function RowBody({ title, meta, className, children, ...rest }) {
|
|
31
|
-
return (_jsxs("div", { className: cx('row__body', className), ...rest, children: [title != null && _jsx("span", { className: "row__title", children: title }), meta != null && _jsx("span", { className: "row__meta", children: meta }), children] }));
|
|
32
|
-
}
|
|
33
|
-
/** RowEnd — a Row's trailing value: a `value` over its muted `caption`, right-aligned (+1.0 h over Tue); or its children.
|
|
34
|
-
* A control at the end (an IconBtn, a Chip, a Check) takes no RowEnd: it goes straight in the Row after the RowBody. */
|
|
35
|
-
export function RowEnd({ value, caption, className, children, ...rest }) {
|
|
36
|
-
return (_jsxs("span", { className: cx('row__end', className), ...rest, children: [value != null && _jsx("span", { className: "t-title", children: value }), caption != null && _jsx("span", { className: "t-caption t-muted", children: caption }), children] }));
|
|
37
|
-
}
|
|
38
23
|
/** Rows — a list of Rows separated by hairlines; `heading` names the group (a `role="group"` labelled by it).
|
|
39
24
|
* REORDERED (the app renders the same keyed rows in another order): each row SLIDES to its new place — the one going up passes
|
|
40
25
|
* over the others — instead of jumping (Lh 2026-10-01). The order is the app's; the move is the list's. */
|
package/dist/media/MapArea.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { ComponentProps, ReactNode, Ref } from 'react';
|
|
2
2
|
export interface MapAreaProps extends ComponentProps<'div'> {
|
|
3
3
|
/** IN FLOW instead of behind a stage: the map is a box in a card or a sheet's body, the ring and the hint in its own box.
|
|
4
|
-
* The only thing in a
|
|
4
|
+
* The only thing in a sheet's Body, it fills the body: the sheet's head stays on top, its foot under it */
|
|
5
5
|
inline?: boolean;
|
|
6
6
|
/** with `inline`: EDGE TO EDGE of what holds it, the sheet's or the card's inset given back, no corner — the map under a step's
|
|
7
7
|
* controls (Lh 2026-10-19, the ask sheet's จุดนัด step). In a `SheetStep` it reaches the sheet's edges; ignored without `inline` */
|
|
@@ -25,7 +25,7 @@ export interface MapAreaProps extends ComponentProps<'div'> {
|
|
|
25
25
|
/**
|
|
26
26
|
* MapArea — the box a map engine draws in: the first child is the engine's mount and fills it; before tiles arrive (or
|
|
27
27
|
* offline) the box shows the wireframe street pattern, never a hole. Two places: behind a stage sheet (the default), or
|
|
28
|
-
* `inline`, in flow inside a card or a sheet's body — as a
|
|
28
|
+
* `inline`, in flow inside a card or a sheet's body — as a sheet's Body's only child it fills the body, so the open sheet
|
|
29
29
|
* becomes the map while its head stays. The ring marks the rough area: behind a stage it is centred in the band a half
|
|
30
30
|
* sheet leaves open, inline at the centre of its own box. Dragging the map underneath is that choice, never a pin to place;
|
|
31
31
|
* `ringRef` is how the engine learns where that is. Places to pick go after the mount, as `MapPick`s.
|