@usableapp/cardds 0.7.69 → 0.7.71
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 +10 -0
- package/README.md +6 -0
- package/css/layover.css +1 -0
- package/css/stack.css +43 -0
- package/dist/cardds.css +44 -0
- package/dist/scaffold/Screen.js +6 -4
- package/dist/sheets/SheetStack.d.ts +5 -2
- package/dist/sheets/SheetStack.js +7 -3
- package/dist/templates/Home.d.ts +5 -3
- package/dist/templates/Home.js +4 -4
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,16 @@
|
|
|
2
2
|
|
|
3
3
|
> For: a project that consumes `@usableapp/cardds` and its AI — what changed between versions, written as before → after, so a screen can be brought up to date without reading the source. Newest first. A consumer never edits cardds; if something here leaves you without a way to do what you did before, report the gap.
|
|
4
4
|
|
|
5
|
+
## 0.7.71 — 2026-10-08
|
|
6
|
+
|
|
7
|
+
### Fixed
|
|
8
|
+
- **A popover `Menu` / `Dropdown` on an iPhone was as tall as the screen** (Lh 2026-10-08) — in Safari on iOS 26 an open menu ran from under its button to the foot of the screen, its rows spread out over that height. Before → after: three rows stood 706px tall → 163px, each row its own 48px. Nothing to change in an app: the same markup, the same props. Chrome and Android never showed it.
|
|
9
|
+
|
|
10
|
+
## 0.7.70 — 2026-10-08
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
- **`Home rise="flood"` / `SheetStack closed rise="flood"`: an opened sheet floods the whole screen, over the top bar** (Lh 2026-10-08) — a tap on a sheet head brings that sheet up over the `AppBar` to fill the screen from its top edge to its bottom. The bar is covered, and hidden from the keyboard and a screen reader, while a sheet is open; it is back at once when the sheet folds. At the screen's top the open sheet's top corners are square; folded, they are round again. Closed, the home looks exactly as before: the bar on top, the `base` under it, the heads at the bottom. `<Home rise="flood" top={…} title="…" sheets={…} base={…} />`. Before: an open sheet always stopped under the top bar; that is still the default (`rise="under"`), so nothing to change in a screen that does not ask for it. Only for a `closed` stack in a `Screen fill` (`Home` always is); on any other stack it warns once and is ignored. In plain markup the class is `sheet-stack--flood`. On a phone running edge to edge the sheet stops at the status bar's line (`--safe-top`), it does not go under it. Gallery: screen · Home, the `Flood` story.
|
|
14
|
+
|
|
5
15
|
## 0.7.69 — 2026-10-07
|
|
6
16
|
|
|
7
17
|
### Fixed
|
package/README.md
CHANGED
|
@@ -188,6 +188,12 @@ the card is the material, the sheet is what it is in the stack.
|
|
|
188
188
|
mark changes colour the same way. Right after a fold, while the
|
|
189
189
|
pile is still coming back, a tap is answered by where each head RESTS: the
|
|
190
190
|
head that will stand under the finger opens, whatever is passing there.
|
|
191
|
+
An open sheet stops under the top bar. `rise="flood"` on the `SheetStack` (or
|
|
192
|
+
`Home`) — `sheet-stack--flood` in markup — lets it rise over the bar and fill
|
|
193
|
+
the whole screen instead: the stack is then the whole screen, the bar a layer
|
|
194
|
+
under the sheets (hidden while one is open), nothing resizes. At the screen's
|
|
195
|
+
top the open sheet's top corners are square; folded, they are round again. It needs
|
|
196
|
+
`--closed` in a `Screen fill`.
|
|
191
197
|
- **Five sheets max.** Slots are declared per `:nth-child` in `stack.css`; a
|
|
192
198
|
sixth would render at slot 0, on top of the first.
|
|
193
199
|
- **Every head needs its own `.sheet-stack__back`** if the stack is `--tap`. It stays
|
package/css/layover.css
CHANGED
|
@@ -127,6 +127,7 @@
|
|
|
127
127
|
--menu-pad: var(--sp-2); /* published: a row's radius is concentric with the panel's */
|
|
128
128
|
padding: var(--menu-pad);
|
|
129
129
|
min-width: 12rem;
|
|
130
|
+
align-content: start; /* rows keep their own height: WebKit stretches a popover grid's rows to the whole room under its anchor (iOS 26.5, 2026-10-08) */
|
|
130
131
|
background: var(--menu-bg, var(--action-bg));
|
|
131
132
|
color: var(--menu-ink, var(--action-ink));
|
|
132
133
|
box-shadow: var(--menu-shadow, var(--shadow-float));
|
package/css/stack.css
CHANGED
|
@@ -30,6 +30,7 @@
|
|
|
30
30
|
</div>
|
|
31
31
|
--closed (with --tap): nothing open on arrival — every sheet peeks at the
|
|
32
32
|
bottom, the headroom above is the base's (block below).
|
|
33
|
+
--flood (with --closed): an open sheet fills the whole screen, over the top bar.
|
|
33
34
|
Direct children only, five at most (slots are :nth-child below):
|
|
34
35
|
first = the back of the stack, last = the front. README "Sheet stack
|
|
35
36
|
markup". The SheetStack component opens and closes a --tap stack; without it the
|
|
@@ -295,6 +296,48 @@
|
|
|
295
296
|
.sheet-stack__base:has(> .screen__centre:only-child) { align-content: center; }
|
|
296
297
|
.sheet-stack__base > .screen__centre { padding-inline: 0; }
|
|
297
298
|
|
|
299
|
+
/* ============================================================
|
|
300
|
+
.sheet-stack--flood — a closed stack whose open sheet FLOODS the screen: it rises over the top bar and fills the whole screen
|
|
301
|
+
(`rise="flood"`), instead of stopping under it. Only for a --closed --tap stack in a .screen--fill.
|
|
302
|
+
|
|
303
|
+
A sheet is rigid: it cannot grow to cover the bar, it only moves by translate. So the stack is made the
|
|
304
|
+
whole screen instead, and every sheet is screen-height always. The bar leaves the column and becomes a
|
|
305
|
+
LAYER at the screen's top, under the sheets (they paint at --level 1-5, the bar at 0): closed, the peeks
|
|
306
|
+
still end at the stack's bottom, --_headroom unchanged; open, the same translate lands the sheet flush
|
|
307
|
+
at the stack's top, which is now the screen's top, and the bar is what it covers. Nothing resizes, no
|
|
308
|
+
new state, no script — Screen only measures the bar (--top-h; a bar is a floor, it grows with the text).
|
|
309
|
+
The screen's safe-top padding stays: a sheet stops at that line, never under the phone's status bar.
|
|
310
|
+
|
|
311
|
+
The base must not sit under the bar or take its taps: it starts below the bar (margin, not padding —
|
|
312
|
+
its box does not overlap the bar) and is shorter by the same amount, so its room is exactly what it was
|
|
313
|
+
under a bar in the column. That amount is the bar plus the breathing under it today (--sp-2 under an
|
|
314
|
+
appbar, the screen's gap under a topbar). Covered, the bar is also hidden (visibility), after the sheet
|
|
315
|
+
has covered it and at once when the sheet folds, so a keyboard and a screen reader do not reach it.
|
|
316
|
+
============================================================ */
|
|
317
|
+
.screen--fill:has(> .sheet-stack--flood) { --_bar-gap: var(--sp-2); }
|
|
318
|
+
.screen--fill:has(> .sheet-stack--flood):has(> .topbar:first-child) { --_bar-gap: var(--screen-gap); }
|
|
319
|
+
.screen--fill:has(> .sheet-stack--flood) > :is(.appbar, .topbar):first-child {
|
|
320
|
+
position: absolute;
|
|
321
|
+
inset: var(--safe-top) 0 auto;
|
|
322
|
+
max-width: none;
|
|
323
|
+
margin: 0;
|
|
324
|
+
z-index: 0; /* under every sheet (--level 1-5); the base clears it by margin */
|
|
325
|
+
}
|
|
326
|
+
.sheet-stack--flood { --_bar: calc(var(--top-h, var(--header-h)) + var(--_bar-gap)); }
|
|
327
|
+
.sheet-stack--flood > .sheet-stack__base {
|
|
328
|
+
margin-top: var(--_bar);
|
|
329
|
+
height: calc(var(--_headroom, 0px) - var(--_bar));
|
|
330
|
+
}
|
|
331
|
+
.screen--fill:has(> .sheet-stack--flood > .stack-card.is-open, > .sheet-stack--flood > :not(.stack-card) > .stack-card.is-open) > :is(.appbar, .topbar):first-child {
|
|
332
|
+
visibility: hidden;
|
|
333
|
+
transition: visibility 0s linear var(--motion-sheet); /* gone once the sheet has covered it; back at once on a fold (the rule above has no delay) */
|
|
334
|
+
}
|
|
335
|
+
/* at the screen's top the open sheet's top corners are SQUARE (Lh 2026-10-08): round, they left two small pockets of the
|
|
336
|
+
bar's ground at the glass. They square as the sheet rises and round again as it folds, in the slide's own time. Paint
|
|
337
|
+
only, the sheet's size is untouched. A pull on the head keeps them square until the finger lets go. */
|
|
338
|
+
.sheet-stack--flood > .card { transition: translate var(--motion-sheet) ease, border-radius var(--motion-sheet) ease; }
|
|
339
|
+
.sheet-stack--flood > .card.is-open { border-top-left-radius: 0; border-top-right-radius: 0; }
|
|
340
|
+
|
|
298
341
|
/* back button: lives in a slot the header reserves once open, and DISSOLVES
|
|
299
342
|
into it — an opacity fade in place, never a slide in from the left (the
|
|
300
343
|
slide read as a second thing moving while the sheet itself moved; Lh,
|
package/dist/cardds.css
CHANGED
|
@@ -1054,6 +1054,7 @@ button:enabled { cursor: pointer; } /* a disabled one keeps the arrow */
|
|
|
1054
1054
|
</div>
|
|
1055
1055
|
--closed (with --tap): nothing open on arrival — every sheet peeks at the
|
|
1056
1056
|
bottom, the headroom above is the base's (block below).
|
|
1057
|
+
--flood (with --closed): an open sheet fills the whole screen, over the top bar.
|
|
1057
1058
|
Direct children only, five at most (slots are :nth-child below):
|
|
1058
1059
|
first = the back of the stack, last = the front. README "Sheet stack
|
|
1059
1060
|
markup". The SheetStack component opens and closes a --tap stack; without it the
|
|
@@ -1319,6 +1320,48 @@ button:enabled { cursor: pointer; } /* a disabled one keeps the arrow */
|
|
|
1319
1320
|
.sheet-stack__base:has(> .screen__centre:only-child) { align-content: center; }
|
|
1320
1321
|
.sheet-stack__base > .screen__centre { padding-inline: 0; }
|
|
1321
1322
|
|
|
1323
|
+
/* ============================================================
|
|
1324
|
+
.sheet-stack--flood — a closed stack whose open sheet FLOODS the screen: it rises over the top bar and fills the whole screen
|
|
1325
|
+
(`rise="flood"`), instead of stopping under it. Only for a --closed --tap stack in a .screen--fill.
|
|
1326
|
+
|
|
1327
|
+
A sheet is rigid: it cannot grow to cover the bar, it only moves by translate. So the stack is made the
|
|
1328
|
+
whole screen instead, and every sheet is screen-height always. The bar leaves the column and becomes a
|
|
1329
|
+
LAYER at the screen's top, under the sheets (they paint at --level 1-5, the bar at 0): closed, the peeks
|
|
1330
|
+
still end at the stack's bottom, --_headroom unchanged; open, the same translate lands the sheet flush
|
|
1331
|
+
at the stack's top, which is now the screen's top, and the bar is what it covers. Nothing resizes, no
|
|
1332
|
+
new state, no script — Screen only measures the bar (--top-h; a bar is a floor, it grows with the text).
|
|
1333
|
+
The screen's safe-top padding stays: a sheet stops at that line, never under the phone's status bar.
|
|
1334
|
+
|
|
1335
|
+
The base must not sit under the bar or take its taps: it starts below the bar (margin, not padding —
|
|
1336
|
+
its box does not overlap the bar) and is shorter by the same amount, so its room is exactly what it was
|
|
1337
|
+
under a bar in the column. That amount is the bar plus the breathing under it today (--sp-2 under an
|
|
1338
|
+
appbar, the screen's gap under a topbar). Covered, the bar is also hidden (visibility), after the sheet
|
|
1339
|
+
has covered it and at once when the sheet folds, so a keyboard and a screen reader do not reach it.
|
|
1340
|
+
============================================================ */
|
|
1341
|
+
.screen--fill:has(> .sheet-stack--flood) { --_bar-gap: var(--sp-2); }
|
|
1342
|
+
.screen--fill:has(> .sheet-stack--flood):has(> .topbar:first-child) { --_bar-gap: var(--screen-gap); }
|
|
1343
|
+
.screen--fill:has(> .sheet-stack--flood) > :is(.appbar, .topbar):first-child {
|
|
1344
|
+
position: absolute;
|
|
1345
|
+
inset: var(--safe-top) 0 auto;
|
|
1346
|
+
max-width: none;
|
|
1347
|
+
margin: 0;
|
|
1348
|
+
z-index: 0; /* under every sheet (--level 1-5); the base clears it by margin */
|
|
1349
|
+
}
|
|
1350
|
+
.sheet-stack--flood { --_bar: calc(var(--top-h, var(--header-h)) + var(--_bar-gap)); }
|
|
1351
|
+
.sheet-stack--flood > .sheet-stack__base {
|
|
1352
|
+
margin-top: var(--_bar);
|
|
1353
|
+
height: calc(var(--_headroom, 0px) - var(--_bar));
|
|
1354
|
+
}
|
|
1355
|
+
.screen--fill:has(> .sheet-stack--flood > .stack-card.is-open, > .sheet-stack--flood > :not(.stack-card) > .stack-card.is-open) > :is(.appbar, .topbar):first-child {
|
|
1356
|
+
visibility: hidden;
|
|
1357
|
+
transition: visibility 0s linear var(--motion-sheet); /* gone once the sheet has covered it; back at once on a fold (the rule above has no delay) */
|
|
1358
|
+
}
|
|
1359
|
+
/* at the screen's top the open sheet's top corners are SQUARE (Lh 2026-10-08): round, they left two small pockets of the
|
|
1360
|
+
bar's ground at the glass. They square as the sheet rises and round again as it folds, in the slide's own time. Paint
|
|
1361
|
+
only, the sheet's size is untouched. A pull on the head keeps them square until the finger lets go. */
|
|
1362
|
+
.sheet-stack--flood > .card { transition: translate var(--motion-sheet) ease, border-radius var(--motion-sheet) ease; }
|
|
1363
|
+
.sheet-stack--flood > .card.is-open { border-top-left-radius: 0; border-top-right-radius: 0; }
|
|
1364
|
+
|
|
1322
1365
|
/* back button: lives in a slot the header reserves once open, and DISSOLVES
|
|
1323
1366
|
into it — an opacity fade in place, never a slide in from the left (the
|
|
1324
1367
|
slide read as a second thing moving while the sheet itself moved; Lh,
|
|
@@ -4780,6 +4823,7 @@ button:enabled { cursor: pointer; } /* a disabled one keeps the arrow */
|
|
|
4780
4823
|
--menu-pad: var(--sp-2); /* published: a row's radius is concentric with the panel's */
|
|
4781
4824
|
padding: var(--menu-pad);
|
|
4782
4825
|
min-width: 12rem;
|
|
4826
|
+
align-content: start; /* rows keep their own height: WebKit stretches a popover grid's rows to the whole room under its anchor (iOS 26.5, 2026-10-08) */
|
|
4783
4827
|
background: var(--menu-bg, var(--action-bg));
|
|
4784
4828
|
color: var(--menu-ink, var(--action-ink));
|
|
4785
4829
|
box-shadow: var(--menu-shadow, var(--shadow-float));
|
package/dist/scaffold/Screen.js
CHANGED
|
@@ -28,14 +28,16 @@ export function Screen({ fill, palette, as = 'div', top, bottom, ready = true, c
|
|
|
28
28
|
}
|
|
29
29
|
return watchSize([bar], () => el.style.setProperty('--bottom-h', `${bar.offsetHeight}px`));
|
|
30
30
|
}, [bottom, ready]);
|
|
31
|
-
/*
|
|
31
|
+
/* the TOP's height published as --top-h, a TRACK or a bar: a stage keeps that line free under a track (step.css); a
|
|
32
|
+
stack that rises over the bar (stack.css, `rise="flood"`) starts its base below it. A bar's height is a floor, not a size (it grows
|
|
33
|
+
with the text), so it is measured */
|
|
32
34
|
useEffect(() => {
|
|
33
|
-
const el = own.current,
|
|
34
|
-
if (!el || !
|
|
35
|
+
const el = own.current, lead = el?.querySelector(':scope > :is(.track, .appbar, .topbar):first-child');
|
|
36
|
+
if (!el || !lead) {
|
|
35
37
|
el?.style.removeProperty('--top-h');
|
|
36
38
|
return;
|
|
37
39
|
}
|
|
38
|
-
return watchSize([
|
|
40
|
+
return watchSize([lead], () => el.style.setProperty('--top-h', `${lead.offsetHeight}px`));
|
|
39
41
|
}, [top, ready]);
|
|
40
42
|
const setRef = (node) => {
|
|
41
43
|
own.current = node;
|
|
@@ -19,6 +19,8 @@ export interface SheetStackProps extends ComponentProps<'div'> {
|
|
|
19
19
|
fanned?: boolean;
|
|
20
20
|
/** nothing open on arrival (tap mode): every sheet, the front one too, peeks at the stack's bottom; the room above is the base's (`base`). A tap opens any sheet over it */
|
|
21
21
|
closed?: boolean;
|
|
22
|
+
/** how an OPEN sheet meets the top bar of a closed stack in a `Screen fill`: `under` (default) stops under the bar · `flood` rises over it and fills the WHOLE screen (from the safe-top line down), the bar covered and hidden while a sheet is open. Only for a `closed` tap stack (warns once otherwise). Nothing resizes: the bar is a layer under the sheets */
|
|
23
|
+
rise?: 'under' | 'flood';
|
|
22
24
|
/** what the base shows in a closed stack's headroom, behind the sheets, laid out against the peeks (a picture, a greeting) */
|
|
23
25
|
base?: ReactNode;
|
|
24
26
|
}
|
|
@@ -29,11 +31,12 @@ export interface SheetStackProps extends ComponentProps<'div'> {
|
|
|
29
31
|
* with CHILDREN, in this order: `<StackBack />` (tap mode), `<Text level="h2" caps>Shopping</Text>`, an `<IconRow>` of Icons —
|
|
30
32
|
* never the `heading` prop (a stack head is back · h2 · tabs on ONE line — StackSheet builds it). Put it last in a `Screen fill`, it bleeds
|
|
31
33
|
* off the bottom. `closed`: nothing open on arrival — every head peeks at the bottom and the base above shows `base` (a home screen
|
|
32
|
-
* with a picture over the menu); the `base` slot is rendered after the sheets, so it never takes a sheet's slot.
|
|
34
|
+
* with a picture over the menu); the `base` slot is rendered after the sheets, so it never takes a sheet's slot. An open sheet fills everything under the top bar,
|
|
35
|
+
* or with `rise="flood"` the whole screen, covering the bar. This is the sheet STACK; a single bottom sheet is `Sheet`.
|
|
33
36
|
*
|
|
34
37
|
* A COMPONENT, not a wiring: WHICH sheet is open is the app's (`open` + `onOpenChange`, or `defaultOpen`) — so a button anywhere, a route or
|
|
35
38
|
* the phone's back button can open and close a section. WHAT the sheet does with that, and with `refreshing`, lives on the card (`stack`):
|
|
36
39
|
* the place classes, the grip, the pull. The stack only says which index. Sheets are rigid — the open one slides up, the ones after it leave
|
|
37
40
|
* below, the ones before tuck under nearest-first; closing reverses in two beats. Only `translate` (stack.css); never a size.
|
|
38
41
|
*/
|
|
39
|
-
export declare function SheetStack({ mode, open, defaultOpen, onOpenChange, onRefresh, refreshing, mark, fanned, closed, base, className, children, onClickCapture, onPointerDownCapture, ref: passed, ...rest }: SheetStackProps): import("react").JSX.Element;
|
|
42
|
+
export declare function SheetStack({ mode, open, defaultOpen, onOpenChange, onRefresh, refreshing, mark, fanned, closed, rise, base, className, children, onClickCapture, onPointerDownCapture, ref: passed, ...rest }: SheetStackProps): import("react").JSX.Element;
|
|
@@ -48,14 +48,15 @@ function stamp(child, place) {
|
|
|
48
48
|
* with CHILDREN, in this order: `<StackBack />` (tap mode), `<Text level="h2" caps>Shopping</Text>`, an `<IconRow>` of Icons —
|
|
49
49
|
* never the `heading` prop (a stack head is back · h2 · tabs on ONE line — StackSheet builds it). Put it last in a `Screen fill`, it bleeds
|
|
50
50
|
* off the bottom. `closed`: nothing open on arrival — every head peeks at the bottom and the base above shows `base` (a home screen
|
|
51
|
-
* with a picture over the menu); the `base` slot is rendered after the sheets, so it never takes a sheet's slot.
|
|
51
|
+
* with a picture over the menu); the `base` slot is rendered after the sheets, so it never takes a sheet's slot. An open sheet fills everything under the top bar,
|
|
52
|
+
* or with `rise="flood"` the whole screen, covering the bar. This is the sheet STACK; a single bottom sheet is `Sheet`.
|
|
52
53
|
*
|
|
53
54
|
* A COMPONENT, not a wiring: WHICH sheet is open is the app's (`open` + `onOpenChange`, or `defaultOpen`) — so a button anywhere, a route or
|
|
54
55
|
* the phone's back button can open and close a section. WHAT the sheet does with that, and with `refreshing`, lives on the card (`stack`):
|
|
55
56
|
* the place classes, the grip, the pull. The stack only says which index. Sheets are rigid — the open one slides up, the ones after it leave
|
|
56
57
|
* below, the ones before tuck under nearest-first; closing reverses in two beats. Only `translate` (stack.css); never a size.
|
|
57
58
|
*/
|
|
58
|
-
export function SheetStack({ mode = 'tap', open, defaultOpen = null, onOpenChange, onRefresh, refreshing = null, mark = 'dots', fanned, closed, base, className, children, onClickCapture, onPointerDownCapture, ref: passed, ...rest }) {
|
|
59
|
+
export function SheetStack({ mode = 'tap', open, defaultOpen = null, onOpenChange, onRefresh, refreshing = null, mark = 'dots', fanned, closed, rise = 'under', base, className, children, onClickCapture, onPointerDownCapture, ref: passed, ...rest }) {
|
|
59
60
|
const [current, request] = useControlled(open, defaultOpen, onOpenChange);
|
|
60
61
|
const prev = useRef(current);
|
|
61
62
|
const [closingFrom, setClosingFrom] = useState(null);
|
|
@@ -136,6 +137,9 @@ export function SheetStack({ mode = 'tap', open, defaultOpen = null, onOpenChang
|
|
|
136
137
|
e.stopPropagation();
|
|
137
138
|
request(i);
|
|
138
139
|
};
|
|
140
|
+
const flood = rise === 'flood' && !!closed && mode === 'tap';
|
|
141
|
+
if (rise === 'flood' && !flood)
|
|
142
|
+
warnOnce('stack-rise', 'cardds SheetStack: rise="flood" needs a closed tap stack (`closed`, mode "tap") — the bar a sheet rises over is the screen\'s, and only a closed stack leaves its base under it. Ignored.');
|
|
139
143
|
const closing = current == null && closingFrom != null;
|
|
140
144
|
const anchor = current ?? closingFrom;
|
|
141
145
|
const items = Children.toArray(children);
|
|
@@ -158,5 +162,5 @@ export function SheetStack({ mode = 'tap', open, defaultOpen = null, onOpenChang
|
|
|
158
162
|
};
|
|
159
163
|
return stamp(child, place);
|
|
160
164
|
}) : items;
|
|
161
|
-
return (_jsxs("div", { className: cx('sheet-stack', mode !== 'static' && `sheet-stack--${mode}`, fanned && 'sheet-stack--fanned', closed && 'sheet-stack--closed', className), ...rest, ref: setRef, onClickCapture: clickCapture, onPointerDownCapture: pointerDownCapture, children: [stamped, base != null && _jsx("div", { className: "sheet-stack__base", children: base })] }));
|
|
165
|
+
return (_jsxs("div", { className: cx('sheet-stack', mode !== 'static' && `sheet-stack--${mode}`, fanned && 'sheet-stack--fanned', closed && 'sheet-stack--closed', flood && 'sheet-stack--flood', className), ...rest, ref: setRef, onClickCapture: clickCapture, onPointerDownCapture: pointerDownCapture, children: [stamped, base != null && _jsx("div", { className: "sheet-stack__base", children: base })] }));
|
|
162
166
|
}
|
package/dist/templates/Home.d.ts
CHANGED
|
@@ -37,6 +37,8 @@ export interface HomeProps extends Omit<ComponentProps<typeof Screen>, 'children
|
|
|
37
37
|
refreshing?: number | null;
|
|
38
38
|
/** the grip on every sheet: `dots` (default) or `line` — as `SheetStack mark` */
|
|
39
39
|
mark?: 'dots' | 'line';
|
|
40
|
+
/** how an open sheet meets the top: `under` (default) stops under the AppBar · `flood` rises over it and fills the WHOLE screen, the bar covered while a sheet is open — as `SheetStack rise` */
|
|
41
|
+
rise?: 'under' | 'flood';
|
|
40
42
|
/** CONTENT above the sheet heads — one `Page`: a welcome, the news, a picture. It reads
|
|
41
43
|
* from the top; a sheet coming up covers it */
|
|
42
44
|
base?: ReactNode;
|
|
@@ -51,9 +53,9 @@ export interface HomeProps extends Omit<ComponentProps<typeof Screen>, 'children
|
|
|
51
53
|
}
|
|
52
54
|
/**
|
|
53
55
|
* Home — TEMPLATE, a `Screen` with its parts filled — top: the AppBar · content: the `base` (title, welcome…) over a closed `SheetStack` · no bottom
|
|
54
|
-
* (the stack is content, never the bottom: open, a sheet fills everything under the top).
|
|
56
|
+
* (the stack is content, never the bottom: open, a sheet fills everything under the top, or with `rise="flood"` the whole screen).
|
|
55
57
|
* Every section is a `StackSheet` of three parts: SHEET HEAD (title + icon tabs, a count over a tab; the back button once open) · SHEET BODY (scrolls) · SHEET FOOT (the CTA,
|
|
56
|
-
* at the bottom). A tap on a head brings that sheet up to fill everything under the top. With a LayerHistory above and no `open` prop, that open sheet is one history entry named `home`. Only the open sheet's body is rendered — three
|
|
58
|
+
* at the bottom). A tap on a head brings that sheet up to fill everything under the top (`rise="flood"`: the whole screen, over the bar). With a LayerHistory above and no `open` prop, that open sheet is one history entry named `home`. Only the open sheet's body is rendered — three
|
|
57
59
|
* sections on one home never cost three pages (`keep` holds a body once opened).
|
|
58
60
|
*/
|
|
59
|
-
export declare function Home({ top, title, sheets, open: openProp, defaultOpen, onOpenChange, onRefresh, refreshing, mark, base, keep, backLabel, backAt, children, ...rest }: HomeProps): import("react").JSX.Element;
|
|
61
|
+
export declare function Home({ top, title, sheets, open: openProp, defaultOpen, onOpenChange, onRefresh, refreshing, mark, rise, base, keep, backLabel, backAt, children, ...rest }: HomeProps): import("react").JSX.Element;
|
package/dist/templates/Home.js
CHANGED
|
@@ -11,12 +11,12 @@ const TONES = [2, 3, 1, 2, 3];
|
|
|
11
11
|
const LEAVE = 800; // ms: a closing sheet keeps its body until it has slid home
|
|
12
12
|
/**
|
|
13
13
|
* Home — TEMPLATE, a `Screen` with its parts filled — top: the AppBar · content: the `base` (title, welcome…) over a closed `SheetStack` · no bottom
|
|
14
|
-
* (the stack is content, never the bottom: open, a sheet fills everything under the top).
|
|
14
|
+
* (the stack is content, never the bottom: open, a sheet fills everything under the top, or with `rise="flood"` the whole screen).
|
|
15
15
|
* Every section is a `StackSheet` of three parts: SHEET HEAD (title + icon tabs, a count over a tab; the back button once open) · SHEET BODY (scrolls) · SHEET FOOT (the CTA,
|
|
16
|
-
* at the bottom). A tap on a head brings that sheet up to fill everything under the top. With a LayerHistory above and no `open` prop, that open sheet is one history entry named `home`. Only the open sheet's body is rendered — three
|
|
16
|
+
* at the bottom). A tap on a head brings that sheet up to fill everything under the top (`rise="flood"`: the whole screen, over the bar). With a LayerHistory above and no `open` prop, that open sheet is one history entry named `home`. Only the open sheet's body is rendered — three
|
|
17
17
|
* sections on one home never cost three pages (`keep` holds a body once opened).
|
|
18
18
|
*/
|
|
19
|
-
export function Home({ top, title, sheets, open: openProp, defaultOpen = null, onOpenChange, onRefresh, refreshing, mark, base, keep, backLabel = word('back'), backAt, children, ...rest }) {
|
|
19
|
+
export function Home({ top, title, sheets, open: openProp, defaultOpen = null, onOpenChange, onRefresh, refreshing, mark, rise, base, keep, backLabel = word('back'), backAt, children, ...rest }) {
|
|
20
20
|
const layer = useOptionalLayer('home');
|
|
21
21
|
const [local, change] = useControlled(openProp, defaultOpen, onOpenChange);
|
|
22
22
|
// A passed `open` is the parent's. With no LayerHistory the index stays local, so a story without a router still opens sheets.
|
|
@@ -50,5 +50,5 @@ export function Home({ top, title, sheets, open: openProp, defaultOpen = null, o
|
|
|
50
50
|
}, [leaving]);
|
|
51
51
|
const [tabs, setTabs] = useState(() => Object.fromEntries(sheets.map((x, i) => [i, x.defaultTab ?? x.tabs?.[0]?.id])));
|
|
52
52
|
const shows = (i) => i === shown || i === leaving || (keep && seen.has(i));
|
|
53
|
-
return (_jsxs(Screen, { fill: true, top: top, ...rest, children: [_jsx(Text, { level: "h1", as: "h1", sr: true, children: title }), _jsx(SheetStack, { closed: true, open: shown, onOpenChange: request, onRefresh: onRefresh, refreshing: refreshing, mark: mark, base: base, children: sheets.map((s, i) => (_jsx(StackSheet, { tone: s.tone ?? TONES[i], paper: s.paper, title: s.title, icon: s.icon, tabs: s.tabs, tab: tabs[i], onTabChange: (t) => setTabs((v) => ({ ...v, [i]: t })), backLabel: backLabel, backAt: backAt, foot: typeof s.foot === 'function' ? s.foot(tabs[i]) : s.foot, children: shows(i) ? (typeof s.body === 'function' ? s.body(tabs[i]) : s.body) : null }, i))) }), children] }));
|
|
53
|
+
return (_jsxs(Screen, { fill: true, top: top, ...rest, children: [_jsx(Text, { level: "h1", as: "h1", sr: true, children: title }), _jsx(SheetStack, { closed: true, open: shown, onOpenChange: request, onRefresh: onRefresh, refreshing: refreshing, mark: mark, rise: rise, base: base, children: sheets.map((s, i) => (_jsx(StackSheet, { tone: s.tone ?? TONES[i], paper: s.paper, title: s.title, icon: s.icon, tabs: s.tabs, tab: tabs[i], onTabChange: (t) => setTabs((v) => ({ ...v, [i]: t })), backLabel: backLabel, backAt: backAt, foot: typeof s.foot === 'function' ? s.foot(tabs[i]) : s.foot, children: shows(i) ? (typeof s.body === 'function' ? s.body(tabs[i]) : s.body) : null }, i))) }), children] }));
|
|
54
54
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@usableapp/cardds",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.71",
|
|
4
4
|
"license": "UNLICENSED",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"description": "card-first mobile design system, React-first: the components in src/ are thin wrappers over the CSS contract (css/*.css stays the only truth); gallery/ shows every story live (npm run dev), tests/ measures the geometry.",
|