@usableapp/cardds 0.7.25 → 0.7.26
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 +8 -0
- package/css/sheet.css +3 -0
- package/dist/cardds.css +3 -0
- package/lint/rules.mjs +27 -4
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,14 @@
|
|
|
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.26 — 2026-09-29
|
|
6
|
+
|
|
7
|
+
### Fixed (`cardds check` / ESLint — two holes mailpool found, 2026-09-29)
|
|
8
|
+
- `sheet-unmounted` now also catches a `Sheet` whose ANCESTOR is on a condition — `{cond && <SheetStage …><Sheet …/></SheetStage>}` vanishes the same way. Before: only a condition right on the `<Sheet>`.
|
|
9
|
+
|
|
10
|
+
### Fixed
|
|
11
|
+
- `SheetStage over` on a SCROLLING screen (a `Screen` without `fill`) now holds to the phone's window (`position: fixed`). Before: it covered the whole page, so scrolled down the sheet and the scrim were off screen (mailpool, 2026-09-29). Nothing to change in a screen.
|
|
12
|
+
|
|
5
13
|
## 0.7.25 — 2026-09-29
|
|
6
14
|
|
|
7
15
|
### Fixed
|
package/css/sheet.css
CHANGED
|
@@ -257,6 +257,9 @@
|
|
|
257
257
|
background: transparent;
|
|
258
258
|
--_top: 0rem;
|
|
259
259
|
}
|
|
260
|
+
/* …on a SCROLLING screen (no fill) the screen is taller than the phone: absolute would cover the whole page, and scrolled
|
|
261
|
+
down the sheet and the scrim are off screen (mailpool, 2026-09-29). There the stage holds to the phone's window. */
|
|
262
|
+
.screen:not(.screen--fill) > .sheet-stage--over { position: fixed; }
|
|
260
263
|
.appbar + .sheet-stage { margin-top: calc(-1 * (var(--header-h) + var(--header-gap, 0rem))); }
|
|
261
264
|
.sheet-stage__bg { position: absolute; inset: 0; } /* map / previous cards behind */
|
|
262
265
|
/* the hero: ONE thing shown in the band a half sheet leaves open (a postcard being made,
|
package/dist/cardds.css
CHANGED
|
@@ -1545,6 +1545,9 @@ button:enabled { cursor: pointer; } /* a disabled one keeps the arrow */
|
|
|
1545
1545
|
background: transparent;
|
|
1546
1546
|
--_top: 0rem;
|
|
1547
1547
|
}
|
|
1548
|
+
/* …on a SCROLLING screen (no fill) the screen is taller than the phone: absolute would cover the whole page, and scrolled
|
|
1549
|
+
down the sheet and the scrim are off screen (mailpool, 2026-09-29). There the stage holds to the phone's window. */
|
|
1550
|
+
.screen:not(.screen--fill) > .sheet-stage--over { position: fixed; }
|
|
1548
1551
|
.appbar + .sheet-stage { margin-top: calc(-1 * (var(--header-h) + var(--header-gap, 0rem))); }
|
|
1549
1552
|
.sheet-stage__bg { position: absolute; inset: 0; } /* map / previous cards behind */
|
|
1550
1553
|
/* the hero: ONE thing shown in the band a half sheet leaves open (a postcard being made,
|
package/lint/rules.mjs
CHANGED
|
@@ -42,6 +42,21 @@ function tagAt(text, start) {
|
|
|
42
42
|
return text.slice(start);
|
|
43
43
|
}
|
|
44
44
|
|
|
45
|
+
/** a whole JSX element from its `<Name`: to its matching `</Name>` (same-name nesting counted), or the opening tag if self-closing */
|
|
46
|
+
function elementAt(text, start) {
|
|
47
|
+
const open = tagAt(text, start);
|
|
48
|
+
if (open.endsWith('/>')) return open;
|
|
49
|
+
const name = text.slice(start + 1).match(/^[\w.]+/)[0];
|
|
50
|
+
const re = new RegExp(`<${name}\\b|</${name}>`, 'g');
|
|
51
|
+
re.lastIndex = start + open.length;
|
|
52
|
+
let depth = 1, m;
|
|
53
|
+
while ((m = re.exec(text))) {
|
|
54
|
+
if (m[0].startsWith('</')) { if (--depth === 0) return text.slice(start, m.index + m[0].length); }
|
|
55
|
+
else if (!tagAt(text, m.index).endsWith('/>')) depth++;
|
|
56
|
+
}
|
|
57
|
+
return text.slice(start);
|
|
58
|
+
}
|
|
59
|
+
|
|
45
60
|
/** the expression of a `{…}` attribute value from its opening brace */
|
|
46
61
|
function braceAt(text, start) {
|
|
47
62
|
let depth = 0, quote = null;
|
|
@@ -88,14 +103,22 @@ export function checkSource(source, file, { classes = carddsClasses() } = {}) {
|
|
|
88
103
|
if (hit.length) add('raw-class', 'error', m.index, `cardds class written by hand (${hit.map((w) => '.' + w).join(' ')}): the look without the behaviour — use the cardds component (its props pick the classes), or a knob / theme.css for the look.`);
|
|
89
104
|
}
|
|
90
105
|
|
|
91
|
-
// 2 · Sheet: controlled with no way to move · put in the tree on a condition with no slide out
|
|
106
|
+
// 2 · Sheet: controlled with no way to move · put in the tree on a condition (its own, or an ancestor's — a SheetStage, a div) with no slide out
|
|
92
107
|
for (const m of text.matchAll(/<Sheet\b/g)) {
|
|
93
108
|
const tag = tagAt(text, m.index);
|
|
94
109
|
if (/\sstate\s*=/.test(tag) && !/\sonStateChange\s*=/.test(tag))
|
|
95
110
|
add('sheet-frozen', 'warn', m.index, '<Sheet state> without onStateChange: the handle, the drag and the keyboard climb only ASK — nothing answers, the sheet cannot move. Add onStateChange, or use defaultState.');
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
111
|
+
}
|
|
112
|
+
const flagged = new Set();
|
|
113
|
+
for (const c of text.matchAll(/(?:&&|\?|:)\s*\(?\s*(?=<[A-Za-z])/g)) {
|
|
114
|
+
const start = c.index + c[0].length;
|
|
115
|
+
const el = elementAt(text, start);
|
|
116
|
+
for (const s of el.matchAll(/<Sheet\b/g)) {
|
|
117
|
+
const at = start + s.index;
|
|
118
|
+
if (flagged.has(at) || /\sonSettled\s*=/.test(tagAt(text, at))) continue;
|
|
119
|
+
flagged.add(at);
|
|
120
|
+
add('sheet-unmounted', 'warn', at, `<Sheet> rendered on a condition${s.index ? ' (around its ' + el.match(/^<([\w.]+)/)[1] + ')' : ''} without onSettled: taken out of the tree it vanishes instead of sliding out. Set state="away" and unmount it in onSettled (state === "away") — or keep it mounted and switch its state.`);
|
|
121
|
+
}
|
|
99
122
|
}
|
|
100
123
|
|
|
101
124
|
// 3 · the screen: the bar is the Screen's bottom, never after it, never pinned; a sheet finishes on its own foot
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@usableapp/cardds",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.26",
|
|
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.",
|