@usableapp/cardds 0.1.6 → 0.1.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -308,7 +308,7 @@ between at 40% down the screen (see *Anatomy*, "Where the centre is"):
308
308
  | `css/actions.css` | topbar, chips, buttons (`.btn--xl`), `.dropdown` (the standard select: pill + `.menu` popover), `.action-bar` (+ `--pager` for previous/next, two round icon buttons, never labels; `--tiers` for a control row above the buttons), `.fab` | when adding actions |
309
309
  | `css/numbers.css` | `.ring` gauge, `.track` steps, `.card--band` + `.band-stack`, `.dotgrid`, `.picker`, `.badge`, `.bars` | big numbers |
310
310
  | `css/people.css` | `.avatar` (sm/lg/xl, outline, add, on, halo), `.avatar-stack`, `.avatar-pick` | people |
311
- | `css/choice.css` | `.check`, `.toggle`, `.chip--toggle`, `.chip-grid` + `.chip--pick`, `.day-strip`, `.calendar`, `.mood`, `.pin`, `.composer`, `.slider` | choice controls |
311
+ | `css/choice.css` | `.check`, `.toggle`, `.chip-grid` + `.chip--pick` (+ `--sign`), `.day-strip`, `.calendar`, `.mood`, `.pin`, `.composer`, `.slider` | choice controls |
312
312
  | `css/lists.css` | `.row` / `.rows` (frameless rows in a card), `.kv`, `.kv-grid`, `.timeline`, `.legend`, `.link` | lists inside cards |
313
313
  | `css/media.css` | `.card--cover`, `.quote`, `.tile-grid` + `.tile`, `.card--fold`, `.mosaic`, `.wave` | media & display |
314
314
  | `css/layover.css` | `.modal` (the ask: `__lift` + `__drawer`, closes on any drawer button → `cardds:modal`), `.menu` (popover), `.banner` (details), `.float-bar`, `.callout`, `.chip--bubble`, `.deck` | cards over content |
package/css/actions.css CHANGED
@@ -58,7 +58,7 @@
58
58
  .appbar__sub { font: var(--type-caption); color: var(--on-surface-muted); }
59
59
  /* the bar's trailing controls (one or two: a labelled switch chip, a wallet button — home,
60
60
  Lh 2026-09-13) stand on the tap floor: a chip that is a switch grows to --tap here */
61
- .appbar .chip--toggle { min-height: var(--tap); }
61
+ .appbar .chip--pick { min-height: var(--tap); }
62
62
 
63
63
  /* ---- icon button (round) ---- */
64
64
  .icon-btn {
package/css/base.css CHANGED
@@ -8,7 +8,7 @@
8
8
  in cards, rows and bodies stay selectable (an address, a code, a number
9
9
  the member wants to copy), and inputs are untouched. Native buttons and
10
10
  links are matched by element; the rest by the class that makes them one */
11
- button, [role="button"], [role="tab"], [role="option"], [role="menuitem"], a.btn, a.icon-btn, a.chip, label.chip, .chip--toggle, .chip--pick,
11
+ button, [role="button"], [role="tab"], [role="option"], [role="menuitem"], a.btn, a.icon-btn, a.chip, label.chip, .chip--pick,
12
12
  .segment__item, .day, .calendar__day, .mood__opt, .pin__cell, .slider, .picker__item, .float-bar__item, .menu__item, .sheet__handle, .dropdown__trigger, .track__step, .pager__at {
13
13
  user-select: none;
14
14
  -webkit-user-select: none;
package/css/choice.css CHANGED
@@ -71,27 +71,11 @@
71
71
  .toggle:checked::after { translate: calc(var(--_w) - var(--_h)) 0; background: var(--on-accent); opacity: 1; }
72
72
  .toggle:focus-visible { outline: var(--focus); outline-offset: var(--sp-1); }
73
73
 
74
- /* ---- toggle chip: interest / filter picker — shows + off, × on ----
75
- <label class="chip chip--toggle"><input type="checkbox">Nature</label> */
76
- .chip--toggle { cursor: pointer; padding-right: var(--sp-2); }
77
- .chip--toggle > input { appearance: none; position: absolute; width: 1px; height: 1px; margin: 0; opacity: 0; }
78
- .chip--toggle::after {
79
- content: "";
80
- width: var(--icon-xs);
81
- height: var(--icon-xs);
82
- flex: none;
83
- background: currentColor;
84
- mask: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="black" stroke-width="2.5" stroke-linecap="round"><path d="M5 12h14"/><path d="M12 5v14"/></svg>') center / contain no-repeat;
85
- -webkit-mask: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="black" stroke-width="2.5" stroke-linecap="round"><path d="M5 12h14"/><path d="M12 5v14"/></svg>') center / contain no-repeat;
86
- }
87
- .chip--toggle:has(:checked) { background: var(--accent); color: var(--on-accent); border-color: transparent; }
88
- /* checked: the same plus turns 45° into an x — one mask, one rotate, no swap (Lh 2026-09-16) */
89
- .chip--toggle:has(:checked)::after { rotate: 45deg; }
90
- @media (prefers-reduced-motion: no-preference) { .chip--toggle::after { transition: rotate var(--motion-slide); } }
91
- .chip--toggle:has(:focus-visible) { outline: var(--focus); outline-offset: var(--sp-1); }
92
-
93
- /* ---- chip grid: pick one slot / many options in a grid ----
94
- <div class="chip-grid"><label class="chip chip--pick"><input type="radio" name="t">9:00</label>…</div> */
74
+ /* ---- chip pick: a chip that is a choice — a native radio/checkbox inside the label, the picked one filled with accent.
75
+ Full-width in a .chip-grid (one slot / many options), or hugging its word on a .chip-row with --sign (an interest
76
+ picker: + off, × on). Was two things, .chip--toggle and .chip--pick — one chip, one state, the sign is a variant (Lh 2026-09-16).
77
+ <div class="chip-grid"><label class="chip chip--pick"><input type="radio" name="t">9:00</label>…</div>
78
+ <div class="chip-row"><label class="chip chip--pick chip--sign"><input type="checkbox">Nature</label>…</div> */
95
79
  .chip-grid {
96
80
  display: grid;
97
81
  grid-template-columns: repeat(auto-fill, minmax(min(5.5rem, 100%), 1fr));
@@ -102,10 +86,23 @@
102
86
  Matters most in scripts without word spaces (Thai): min-content is the
103
87
  whole string, tracks get wide, and hugging chips leave a ragged grid. */
104
88
  .chip-grid > .chip { justify-self: stretch; justify-content: center; min-height: var(--btn-h); padding-inline: var(--sp-2); position: relative; }
105
- .chip--pick { cursor: pointer; }
89
+ .chip--pick { cursor: pointer; position: relative; } /* the input covers the whole chip, on a row as in a grid */
106
90
  .chip--pick > input { appearance: none; position: absolute; inset: 0; margin: 0; opacity: 0; cursor: pointer; }
107
91
  .chip--pick:has(:checked) { background: var(--accent); color: var(--on-accent); border-color: transparent; }
108
92
  .chip--pick:has(:focus-visible) { outline: var(--focus); outline-offset: var(--sp-1); }
93
+ /* --sign: the trailing + that turns 45° into an × when picked — one mask, one rotate, no swap (Lh 2026-09-16) */
94
+ .chip--sign { padding-right: var(--sp-2); }
95
+ .chip--sign::after {
96
+ content: "";
97
+ width: var(--icon-xs);
98
+ height: var(--icon-xs);
99
+ flex: none;
100
+ background: currentColor;
101
+ mask: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="black" stroke-width="2.5" stroke-linecap="round"><path d="M5 12h14"/><path d="M12 5v14"/></svg>') center / contain no-repeat;
102
+ -webkit-mask: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="black" stroke-width="2.5" stroke-linecap="round"><path d="M5 12h14"/><path d="M12 5v14"/></svg>') center / contain no-repeat;
103
+ }
104
+ .chip--sign:has(:checked)::after { rotate: 45deg; }
105
+ @media (prefers-reduced-motion: no-preference) { .chip--sign::after { transition: rotate var(--motion-slide); } }
109
106
 
110
107
  /* ---- day strip: a week, one day selected ----
111
108
  <div class="day-strip" role="tablist"><button class="day" role="tab" aria-selected="true"><span class="day__name">Thu</span><span class="day__num">16</span></button>…</div> */
@@ -11,7 +11,7 @@ export interface ChipProps extends ComponentPropsWithoutRef<'span'> {
11
11
  href?: string;
12
12
  children?: ReactNode;
13
13
  }
14
- /** Chip — a status or attribute tag (with an optional signal Dot), or a small tap target; `on` when it is the live one. For pickers use ChipToggle / ChipPick. */
14
+ /** Chip — a status or attribute tag (with an optional signal Dot), or a small tap target; `on` when it is the live one. For a choice use ChipPick (`sign` for the +/× interest picker). */
15
15
  export declare function Chip({ on, dot, bubble, as, href, className, children, ...rest }: ChipProps): import("react").DetailedReactHTMLElement<{
16
16
  slot?: string | undefined | undefined;
17
17
  style?: import("react").CSSProperties | undefined;
@@ -296,26 +296,20 @@ export declare function Chip({ on, dot, bubble, as, href, className, children, .
296
296
  type: string | undefined;
297
297
  className: string;
298
298
  }, HTMLElement>;
299
- export interface ChipToggleProps extends Omit<ComponentPropsWithoutRef<'label'>, 'onChange'> {
300
- checked?: boolean;
301
- defaultChecked?: boolean;
302
- name?: string;
303
- value?: string;
304
- onChange?: React.ChangeEventHandler<HTMLInputElement>;
305
- }
306
- /** ChipToggle — an interest / filter chip: shows + off and × on; the state is a native checkbox inside the label. */
307
- export declare function ChipToggle({ checked, defaultChecked, name, value, onChange, className, children, ...rest }: ChipToggleProps): import("react").JSX.Element;
308
299
  export interface ChipPickProps extends Omit<ComponentPropsWithoutRef<'label'>, 'onChange'> {
309
- /** radio for pick-one (a time slot), checkbox for pick-many (skills) */
300
+ /** radio for pick-one (a time slot), checkbox for pick-many (skills); `sign` defaults to checkbox */
310
301
  type?: 'radio' | 'checkbox';
302
+ /** the +/× at the end: an interest / filter chip on a row, hugging its word (was ChipToggle) */
303
+ sign?: boolean;
311
304
  name?: string;
312
305
  value?: string;
313
306
  checked?: boolean;
314
307
  defaultChecked?: boolean;
315
308
  onChange?: React.ChangeEventHandler<HTMLInputElement>;
316
309
  }
317
- /** ChipPick — a full-width pick target in a ChipGrid (9:00 · 9:30 · …); the picked one fills with accent. */
318
- export declare function ChipPick({ type, name, value, checked, defaultChecked, onChange, className, children, ...rest }: ChipPickProps): import("react").JSX.Element;
310
+ /** ChipPick — a chip that is a choice: full-width in a ChipGrid (9:00 · 9:30 · …), or `sign` on a ChipRow (+ off, × on — the
311
+ * interest picker); the picked one fills with accent. A native radio/checkbox inside the label carries the state. */
312
+ export declare function ChipPick({ type, sign, name, value, checked, defaultChecked, onChange, className, children, ...rest }: ChipPickProps): import("react").JSX.Element;
319
313
  export interface ChipRowProps extends ComponentPropsWithoutRef<'div'> {
320
314
  /** run the row to the card's edges as a one-line scrolling strip (`.bleed`: nowrap, overflow, the hairline ink scrollbar) */
321
315
  bleed?: boolean;
@@ -2,18 +2,15 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { createElement } from 'react';
3
3
  import { cx } from '../cx.js';
4
4
  import { Dot } from './Dot.js';
5
- /** Chip — a status or attribute tag (with an optional signal Dot), or a small tap target; `on` when it is the live one. For pickers use ChipToggle / ChipPick. */
5
+ /** Chip — a status or attribute tag (with an optional signal Dot), or a small tap target; `on` when it is the live one. For a choice use ChipPick (`sign` for the +/× interest picker). */
6
6
  export function Chip({ on, dot, bubble, as, href, className, children, ...rest }) {
7
7
  const el = as ?? (href ? 'a' : 'span');
8
8
  return createElement(el, { href, type: el === 'button' ? 'button' : undefined, className: cx('chip', on && 'chip--on', bubble && 'chip--bubble', className), ...rest }, dot && _jsx(Dot, { b: dot === 'b' }), children);
9
9
  }
10
- /** ChipToggle — an interest / filter chip: shows + off and × on; the state is a native checkbox inside the label. */
11
- export function ChipToggle({ checked, defaultChecked, name, value, onChange, className, children, ...rest }) {
12
- return (_jsxs("label", { className: cx('chip chip--toggle', className), ...rest, children: [_jsx("input", { type: "checkbox", checked: checked, defaultChecked: defaultChecked, name: name, value: value, onChange: onChange }), children] }));
13
- }
14
- /** ChipPick — a full-width pick target in a ChipGrid (9:00 · 9:30 · …); the picked one fills with accent. */
15
- export function ChipPick({ type = 'radio', name, value, checked, defaultChecked, onChange, className, children, ...rest }) {
16
- return (_jsxs("label", { className: cx('chip chip--pick', className), ...rest, children: [_jsx("input", { type: type, name: name, value: value, checked: checked, defaultChecked: defaultChecked, onChange: onChange }), children] }));
10
+ /** ChipPick — a chip that is a choice: full-width in a ChipGrid (9:00 · 9:30 · …), or `sign` on a ChipRow (+ off, × on — the
11
+ * interest picker); the picked one fills with accent. A native radio/checkbox inside the label carries the state. */
12
+ export function ChipPick({ type, sign, name, value, checked, defaultChecked, onChange, className, children, ...rest }) {
13
+ return (_jsxs("label", { className: cx('chip chip--pick', sign && 'chip--sign', className), ...rest, children: [_jsx("input", { type: type ?? (sign ? 'checkbox' : 'radio'), name: name, value: value, checked: checked, defaultChecked: defaultChecked, onChange: onChange }), children] }));
17
14
  }
18
15
  /** ChipRow — chips on a wrapping line (or a bleeding strip). */
19
16
  export function ChipRow({ bleed, className, ...rest }) {
package/dist/cardds.css CHANGED
@@ -344,7 +344,7 @@
344
344
  in cards, rows and bodies stay selectable (an address, a code, a number
345
345
  the member wants to copy), and inputs are untouched. Native buttons and
346
346
  links are matched by element; the rest by the class that makes them one */
347
- button, [role="button"], [role="tab"], [role="option"], [role="menuitem"], a.btn, a.icon-btn, a.chip, label.chip, .chip--toggle, .chip--pick,
347
+ button, [role="button"], [role="tab"], [role="option"], [role="menuitem"], a.btn, a.icon-btn, a.chip, label.chip, .chip--pick,
348
348
  .segment__item, .day, .calendar__day, .mood__opt, .pin__cell, .slider, .picker__item, .float-bar__item, .menu__item, .sheet__handle, .dropdown__trigger, .track__step, .pager__at {
349
349
  user-select: none;
350
350
  -webkit-user-select: none;
@@ -1603,7 +1603,7 @@ button { font: inherit; cursor: pointer; }
1603
1603
  .appbar__sub { font: var(--type-caption); color: var(--on-surface-muted); }
1604
1604
  /* the bar's trailing controls (one or two: a labelled switch chip, a wallet button — home,
1605
1605
  Lh 2026-09-13) stand on the tap floor: a chip that is a switch grows to --tap here */
1606
- .appbar .chip--toggle { min-height: var(--tap); }
1606
+ .appbar .chip--pick { min-height: var(--tap); }
1607
1607
 
1608
1608
  /* ---- icon button (round) ---- */
1609
1609
  .icon-btn {
@@ -2237,27 +2237,11 @@ button { font: inherit; cursor: pointer; }
2237
2237
  .toggle:checked::after { translate: calc(var(--_w) - var(--_h)) 0; background: var(--on-accent); opacity: 1; }
2238
2238
  .toggle:focus-visible { outline: var(--focus); outline-offset: var(--sp-1); }
2239
2239
 
2240
- /* ---- toggle chip: interest / filter picker — shows + off, × on ----
2241
- <label class="chip chip--toggle"><input type="checkbox">Nature</label> */
2242
- .chip--toggle { cursor: pointer; padding-right: var(--sp-2); }
2243
- .chip--toggle > input { appearance: none; position: absolute; width: 1px; height: 1px; margin: 0; opacity: 0; }
2244
- .chip--toggle::after {
2245
- content: "";
2246
- width: var(--icon-xs);
2247
- height: var(--icon-xs);
2248
- flex: none;
2249
- background: currentColor;
2250
- mask: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="black" stroke-width="2.5" stroke-linecap="round"><path d="M5 12h14"/><path d="M12 5v14"/></svg>') center / contain no-repeat;
2251
- -webkit-mask: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="black" stroke-width="2.5" stroke-linecap="round"><path d="M5 12h14"/><path d="M12 5v14"/></svg>') center / contain no-repeat;
2252
- }
2253
- .chip--toggle:has(:checked) { background: var(--accent); color: var(--on-accent); border-color: transparent; }
2254
- /* checked: the same plus turns 45° into an x — one mask, one rotate, no swap (Lh 2026-09-16) */
2255
- .chip--toggle:has(:checked)::after { rotate: 45deg; }
2256
- @media (prefers-reduced-motion: no-preference) { .chip--toggle::after { transition: rotate var(--motion-slide); } }
2257
- .chip--toggle:has(:focus-visible) { outline: var(--focus); outline-offset: var(--sp-1); }
2258
-
2259
- /* ---- chip grid: pick one slot / many options in a grid ----
2260
- <div class="chip-grid"><label class="chip chip--pick"><input type="radio" name="t">9:00</label>…</div> */
2240
+ /* ---- chip pick: a chip that is a choice — a native radio/checkbox inside the label, the picked one filled with accent.
2241
+ Full-width in a .chip-grid (one slot / many options), or hugging its word on a .chip-row with --sign (an interest
2242
+ picker: + off, × on). Was two things, .chip--toggle and .chip--pick — one chip, one state, the sign is a variant (Lh 2026-09-16).
2243
+ <div class="chip-grid"><label class="chip chip--pick"><input type="radio" name="t">9:00</label>…</div>
2244
+ <div class="chip-row"><label class="chip chip--pick chip--sign"><input type="checkbox">Nature</label>…</div> */
2261
2245
  .chip-grid {
2262
2246
  display: grid;
2263
2247
  grid-template-columns: repeat(auto-fill, minmax(min(5.5rem, 100%), 1fr));
@@ -2268,10 +2252,23 @@ button { font: inherit; cursor: pointer; }
2268
2252
  Matters most in scripts without word spaces (Thai): min-content is the
2269
2253
  whole string, tracks get wide, and hugging chips leave a ragged grid. */
2270
2254
  .chip-grid > .chip { justify-self: stretch; justify-content: center; min-height: var(--btn-h); padding-inline: var(--sp-2); position: relative; }
2271
- .chip--pick { cursor: pointer; }
2255
+ .chip--pick { cursor: pointer; position: relative; } /* the input covers the whole chip, on a row as in a grid */
2272
2256
  .chip--pick > input { appearance: none; position: absolute; inset: 0; margin: 0; opacity: 0; cursor: pointer; }
2273
2257
  .chip--pick:has(:checked) { background: var(--accent); color: var(--on-accent); border-color: transparent; }
2274
2258
  .chip--pick:has(:focus-visible) { outline: var(--focus); outline-offset: var(--sp-1); }
2259
+ /* --sign: the trailing + that turns 45° into an × when picked — one mask, one rotate, no swap (Lh 2026-09-16) */
2260
+ .chip--sign { padding-right: var(--sp-2); }
2261
+ .chip--sign::after {
2262
+ content: "";
2263
+ width: var(--icon-xs);
2264
+ height: var(--icon-xs);
2265
+ flex: none;
2266
+ background: currentColor;
2267
+ mask: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="black" stroke-width="2.5" stroke-linecap="round"><path d="M5 12h14"/><path d="M12 5v14"/></svg>') center / contain no-repeat;
2268
+ -webkit-mask: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="black" stroke-width="2.5" stroke-linecap="round"><path d="M5 12h14"/><path d="M12 5v14"/></svg>') center / contain no-repeat;
2269
+ }
2270
+ .chip--sign:has(:checked)::after { rotate: 45deg; }
2271
+ @media (prefers-reduced-motion: no-preference) { .chip--sign::after { transition: rotate var(--motion-slide); } }
2275
2272
 
2276
2273
  /* ---- day strip: a week, one day selected ----
2277
2274
  <div class="day-strip" role="tablist"><button class="day" role="tab" aria-selected="true"><span class="day__name">Thu</span><span class="day__num">16</span></button>…</div> */
@@ -7,7 +7,7 @@ export interface AppBarProps extends Omit<ComponentPropsWithoutRef<'header'>, 't
7
7
  /** the second line under the title */
8
8
  sub?: ReactNode;
9
9
  /** the trailing control(s) — an IconBtn with a chevron-down to switch context; on the home bar a labelled
10
- * switch chip (ChipToggle, --tap tall here) and the wallet Btn, side by side (Lh 2026-09-13) */
10
+ * switch chip (ChipPick sign, --tap tall here) and the wallet Btn, side by side (Lh 2026-09-13) */
11
11
  action?: ReactNode;
12
12
  }
13
13
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@usableapp/cardds",
3
- "version": "0.1.6",
3
+ "version": "0.1.7",
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.",