@usableapp/cardds 0.7.87 → 0.7.88

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.
@@ -23,6 +23,8 @@ export interface RowProps extends Omit<ComponentProps<'div'>, 'title'> {
23
23
  done?: boolean;
24
24
  /** div (default), a link, a label wrapping a Check/Toggle, li */
25
25
  as?: 'div' | 'a' | 'label' | 'li';
26
+ /** with `as="label"`: the `id` of the control the row presses (its `Check`). Needed when the `end` holds a button BEFORE the check (a picked row's own move, "open the map"): a label presses the first control inside it, so without this a touch on the row's words would press that button */
27
+ htmlFor?: string;
26
28
  /** makes the row a link (an `a`); not with `more`, whose row is a summary */
27
29
  href?: string;
28
30
  /** what the row EXPANDS to show under itself (who liked, the rest of a list): the row becomes a `<details>`' summary */
@@ -10,5 +10,6 @@ export interface EmptyStateProps extends Omit<ComponentProps<'div'>, 'title'> {
10
10
  level?: 'h2' | 'h3';
11
11
  }
12
12
  /** EmptyState — centred: a large icon, a heading, a line of body text, an optional CTA. A component in the content: alone in a `Step` it stands at the content's human centre, 40% down (Lh 2026-09-23 — no longer a `Centre` over the screen)
13
- * or inside a card's section ("nothing here yet" under a heading) — the ink follows the card it sits in; full ink throughout, never muted (Lh 2026-09-16). */
13
+ * or inside a card's section ("nothing here yet" under a heading) — the ink follows the card it sits in; full ink throughout, never muted (Lh 2026-09-16).
14
+ * Knob `--empty-state-at`, a number 0–1: the share of the holder's free room that stands above it. In a `Step` the default is 0.4 (two parts above, three below); alone in a `SheetBody` it is 0 (at the top). A theme's `:root { --empty-state-at: 0.2 }` lifts it everywhere, or set it on a `Screen`, `Step` or `Sheet` for the ones inside. */
14
15
  export declare function EmptyState({ icon, title, action, level, className, children, ...rest }: EmptyStateProps): import("react").JSX.Element;
@@ -1,7 +1,8 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { cx } from '../cx.js';
3
3
  /** EmptyState — centred: a large icon, a heading, a line of body text, an optional CTA. A component in the content: alone in a `Step` it stands at the content's human centre, 40% down (Lh 2026-09-23 — no longer a `Centre` over the screen)
4
- * or inside a card's section ("nothing here yet" under a heading) — the ink follows the card it sits in; full ink throughout, never muted (Lh 2026-09-16). */
4
+ * or inside a card's section ("nothing here yet" under a heading) — the ink follows the card it sits in; full ink throughout, never muted (Lh 2026-09-16).
5
+ * Knob `--empty-state-at`, a number 0–1: the share of the holder's free room that stands above it. In a `Step` the default is 0.4 (two parts above, three below); alone in a `SheetBody` it is 0 (at the top). A theme's `:root { --empty-state-at: 0.2 }` lifts it everywhere, or set it on a `Screen`, `Step` or `Sheet` for the ones inside. */
5
6
  export function EmptyState({ icon, title, action, level = 'h2', className, children, ...rest }) {
6
7
  const H = level;
7
8
  return (_jsxs("div", { className: cx('empty-state', className), ...rest, children: [icon, title != null && _jsx(H, { className: "t-h2", children: title }), typeof children === 'string' ? _jsx("p", { className: "t-body", children: children }) : children, action != null && _jsx("div", { className: "empty-state__action", children: action })] }));
package/lint/rules.mjs CHANGED
@@ -209,5 +209,12 @@ export function checkSource(source, file, { classes = carddsClasses() } = {}) {
209
209
  }
210
210
  }
211
211
 
212
+ // 8 · a label presses the FIRST control inside it: a button before the row's Check takes the press meant for the row
213
+ for (const m of text.matchAll(/<Row\b/g)) {
214
+ const tag = tagAt(text, m.index);
215
+ if (/\sas\s*=\s*\{?\s*["']label["']/.test(tag) && /<(?:IconBtn|Btn|Link)\b/.test(tag) && !/\shtmlFor\s*=/.test(tag))
216
+ add('row-label-button', 'warn', m.index, '<Row as="label"> holding a button and no htmlFor: a label presses the first control inside it, so a touch on the row\'s words presses that button, not its Check. Give the Check an id and the row htmlFor={id}.');
217
+ }
218
+
212
219
  return findings.sort((a, b) => a.line - b.line);
213
220
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@usableapp/cardds",
3
- "version": "0.7.87",
3
+ "version": "0.7.88",
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.",