@usableapp/cardds 0.6.16 → 0.7.0

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 CHANGED
@@ -2,6 +2,28 @@
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.0 — 2026-09-24
6
+
7
+ Breaking — the clean-up promised since 0.6.5. Four renames/removals, one new way.
8
+
9
+ ### A bar on a scrolling screen goes INSIDE the Screen
10
+ - Before: on a screen that is not `fill` (it scrolls), the `ActionBar` was written after `</Screen>`, fixed to the
11
+ viewport, and the screen reserved `--bar-reserve` at its bottom. After: write it as `<Screen bottom={<ActionBar>…}>`
12
+ like on a fill screen. The screen becomes a column at least one phone tall; the bar is its last row, `position: sticky`
13
+ at the viewport's foot (above the keyboard) — in reach while the words scroll, under them when they end.
14
+ `validateScreen` already reports a bar after `</Screen>`. Story `ActionBar · OnAScrollingScreen`.
15
+
16
+ ### `BaseContent` removed
17
+ - Before: `BaseContent` (an alias that warned). After: `Page` — same props, same markup.
18
+
19
+ ### `--base-content-*` knobs renamed `--page-*` (no fallback)
20
+ - `--base-content-media-h` → `--page-media-h`, and likewise `-gap`, `-pad-y`, `-body-ink`. The old names do nothing now:
21
+ rename them in your theme.css.
22
+
23
+ ### `Bubble actions` removed
24
+ - Before: small buttons beside a chat message (`actions`, `.bubble__actions`, knob `--bubble-actions-gap`). After: gone —
25
+ a Bubble is the message and its `meta`. The bubble is one column now.
26
+
5
27
  ## 0.6.16 — 2026-09-24
6
28
 
7
29
  ### iOS 16.4 supported (was 18.3)
package/README.md CHANGED
@@ -246,9 +246,10 @@ whose markup has rules, because the sheet's box is the step itself:
246
246
  step that follows anything else keeps the screen's gap, and the sheet
247
247
  stops under that thing.
248
248
  - **The bar is after the step, inside the screen** (the screen's bottom — *Screen: top · content · bottom*). In a
249
- `.screen--fill` the step and the bar share one flex column and touch; the step takes the rest. (A bar outside a
250
- fill screen — an app shell — is still fixed to the viewport and the step reads `--bar-reserve`: the old way,
251
- kept until 0.7.0.)
249
+ `.screen--fill` the bar is a layer over the content's foot. On a SCROLLING screen (not fill, 0.7.0) the screen is a
250
+ column at least one phone tall and the bar its last row, `position: sticky` at the viewport's foot (above `--kb`):
251
+ it stays in reach while the words scroll and sits under them when they end. Either way the bar is written INSIDE
252
+ the Screen (`bottom`) — a bar after `</Screen>` is an error (`validateScreen`).
252
253
  - **Every sheet has one shape** (Lh 2026-09-21): the handle and the head stay at the top and never scroll · the
253
254
  foot's button stands at the bottom — above the keyboard when there is one (`--kb`: a step gives the keyboard
254
255
  its room, a stage sheet gives it up itself as `--_lift`) · everything between them scrolls, as far as it
package/css/actions.css CHANGED
@@ -238,6 +238,15 @@
238
238
  display: flex;
239
239
  gap: var(--sp-2);
240
240
  }
241
+ /* a bar INSIDE a scrolling (not fill) screen (Lh 2026-09-24, 0.7.0): the screen is a column at least one phone tall, the bar its
242
+ last row — at the foot when the words are short, and sticky to the viewport's foot (above the keyboard) while they scroll;
243
+ it takes the room it needs in the column, so nothing is added to the content for it */
244
+ .screen:not(.screen--fill):has(> .action-bar) { display: flex; flex-direction: column; min-height: 100dvh; }
245
+ .screen:not(.screen--fill) > .action-bar {
246
+ position: sticky; inset-inline: auto; bottom: var(--kb, 0rem);
247
+ max-width: none;
248
+ margin: auto calc(-1 * var(--screen-pad)) 0;
249
+ }
241
250
  .action-bar .btn { flex: 1; box-shadow: var(--shadow-float); }
242
251
  .action-bar .icon-btn { width: var(--btn-h); height: var(--btn-h); box-shadow: var(--shadow-float); }
243
252
 
package/css/base.css CHANGED
@@ -115,18 +115,18 @@ button { font: inherit; cursor: pointer; }
115
115
  In a .step it is the reading block and step.css adds the flex/scroll rule ---- */
116
116
  .page {
117
117
  display: grid;
118
- gap: var(--base-content-gap, var(--sp-3));
118
+ gap: var(--page-gap, var(--sp-3));
119
119
  align-content: start; /* a tall column never stretches the rows — the words hug the top */
120
- padding-block: var(--base-content-pad-y, var(--sp-4));
120
+ padding-block: var(--page-pad-y, var(--sp-4));
121
121
  }
122
- .page > .t-body { color: var(--base-content-body-ink, var(--on-surface)); max-width: 34ch; } /* full ink: a sentence is read, muted is for meta (Lh 2026-09-22 — the words on the base were grey and hard to read) */
122
+ .page > .t-body { color: var(--page-body-ink, var(--on-surface)); max-width: 34ch; } /* full ink: a sentence is read, muted is for meta (Lh 2026-09-22 — the words on the base were grey and hard to read) */
123
123
  /* an illustration among the words (Lh 2026-09-22): capped, so a tall picture never pushes the words under the bar;
124
124
  (the walk's dots are NOT here — they are the Step's, after its Pages: step.css, Lh 2026-09-22) */
125
125
  /* the page's ONE heading on the base (a screen with no TopBar: CardHead level="h1") reads at the card heading's size —
126
126
  h1 is the semantic level, not a bigger face; --fs-h1 is the bar title's size (Lh 2026-09-22) */
127
127
  .page > .card__head > .t-h1 { font-size: var(--fs-h2); }
128
- .page > :is(img, .ph) { max-height: var(--base-content-media-h, 14rem); width: auto; height: auto; max-width: 100%; object-fit: contain; justify-self: start; align-self: start; } /* height auto: an <img> with width/height attributes keeps its ratio inside the cap — no band under the picture */
129
- .page > .ph { width: 100%; height: var(--base-content-media-h, 14rem); }
128
+ .page > :is(img, .ph) { max-height: var(--page-media-h, 14rem); width: auto; height: auto; max-width: 100%; object-fit: contain; justify-self: start; align-self: start; } /* height auto: an <img> with width/height attributes keeps its ratio inside the cap — no band under the picture */
129
+ .page > .ph { width: 100%; height: var(--page-media-h, 14rem); }
130
130
  .page .cta-pack {
131
131
  display: flex;
132
132
  align-items: start; /* buttons keep their own height, never the row's */
package/css/lists.css CHANGED
@@ -98,29 +98,23 @@
98
98
  /* ---- bubble: a chat message — theirs on the left, mine on the right (Lh 2026-09-18, replaces the chip's tail) ----
99
99
  No tail: a rounded block whose corner nearest the sender is square-ish
100
100
  (bottom-left for theirs, bottom-right for mine), the way messaging apps
101
- draw it. Under it a caption line (time · a tick), beside it small round
102
- actions (a heart, more). A .thread stacks them.
101
+ draw it. Under it a caption line (time · a tick). A .thread stacks them.
103
102
  <div class="thread">
104
- <div class="bubble"><p class="bubble__body">…</p><span class="bubble__actions">…icon-btns…</span><span class="bubble__meta">Dec 4 · 8:15</span></div>
103
+ <div class="bubble"><p class="bubble__body">…</p><span class="bubble__meta">Dec 4 · 8:15</span></div>
105
104
  <div class="bubble bubble--right">…</div>
106
105
  </div> */
107
106
  .thread { display: grid; gap: var(--thread-gap, var(--sp-4)); }
108
- /* two columns: the message (max-content, but it gives way — minmax(0) — so a long one shrinks
109
- and wraps while the actions stay beside it) and the actions; the meta on a second row under the message */
107
+ /* one column: the message (max-content, but it gives way — minmax(0) — so a long one shrinks and wraps); the meta under it */
110
108
  .bubble {
111
109
  display: grid;
112
- grid-template-columns: minmax(0, max-content) auto;
110
+ grid-template-columns: minmax(0, max-content);
113
111
  justify-content: start;
114
112
  align-items: center;
115
113
  gap: var(--sp-1) var(--sp-3);
116
114
  max-width: var(--bubble-max-w, 75%); /* a message may run to three quarters of the thread (Lh 2026-09-23) */
117
115
  margin-right: auto; /* theirs: hugs the left */
118
116
  }
119
- .bubble--right { grid-template-columns: auto minmax(0, max-content); justify-content: end; margin-right: 0; margin-left: auto; } /* mine: hugs the right, the actions on its left */
120
- .bubble__body, .bubble__meta { grid-column: 1; }
121
- .bubble__actions { grid-column: 2; grid-row: 1; }
122
- .bubble--right > :is(.bubble__body, .bubble__meta) { grid-column: 2; }
123
- .bubble--right > .bubble__actions { grid-column: 1; }
117
+ .bubble--right { justify-content: end; margin-right: 0; margin-left: auto; } /* mine: hugs the right */
124
118
  .bubble__body {
125
119
  margin: 0;
126
120
  min-width: 0;
@@ -139,7 +133,6 @@
139
133
  color: var(--on-accent);
140
134
  text-align: right;
141
135
  }
142
- .bubble__actions { display: flex; gap: var(--bubble-actions-gap, var(--sp-1)); flex: none; opacity: 0.7; }
143
136
  .bubble__meta { display: flex; align-items: center; gap: var(--bubble-meta-gap, var(--sp-1)); font: var(--bubble-meta-font, var(--type-caption)); color: var(--bubble-meta-ink, var(--on-surface-muted)); }
144
137
  .bubble--right > .bubble__meta { justify-self: end; }
145
138
  .bubble__meta > .icon { color: var(--accent); }
package/css/stack.css CHANGED
@@ -230,7 +230,7 @@
230
230
  gap: var(--card-gap, var(--sp-5));
231
231
  overflow: clip;
232
232
  }
233
- /* a base that is ONE BaseContent is a page's words (a title, a welcome, the news): it reads from the TOP, like any page —
233
+ /* a base that is ONE Page is a page's words (a title, a welcome, the news): it reads from the TOP, like any page —
234
234
  loose things (a picture, a line) still sit against the peeks (Lh 2026-09-23, the home) */
235
235
  .sheet-stack__base:has(> .page:only-child) { align-content: start; }
236
236
 
package/css/step.css CHANGED
@@ -145,13 +145,13 @@
145
145
  .screen--fill > .appbar:has(+ .step) { margin-bottom: calc(-1 * var(--screen-gap)); }
146
146
  .screen--fill > .appbar + .sheet-stage { margin-top: 0; }
147
147
  /* a walk page that OPENS on a picture (Lh 2026-09-23): the picture takes the lead's room — as wide as the content (edge to edge), from the top edge, as tall as
148
- the lead + the picture's own height (--base-content-media-h), square — so the words start where they always did */
148
+ the lead + the picture's own height (--page-media-h), square — so the words start where they always did */
149
149
  .step > .pages > .page:has(> :is(img, .ph):first-child) { margin-top: 0; }
150
150
  .step > .pages > .page > :is(img, .ph):first-child {
151
151
  width: calc(100% + 2 * var(--screen-pad)); /* the content's width: the page's inset given back */
152
152
  max-width: none;
153
153
  margin-inline: calc(-1 * var(--screen-pad));
154
- height: calc(var(--_lead, 0rem) + var(--base-content-media-h, 14rem));
154
+ height: calc(var(--_lead, 0rem) + var(--page-media-h, 14rem));
155
155
  max-height: none;
156
156
  border-radius: 0;
157
157
  border-inline: 0;
package/dist/cardds.css CHANGED
@@ -495,18 +495,18 @@ button { font: inherit; cursor: pointer; }
495
495
  In a .step it is the reading block and step.css adds the flex/scroll rule ---- */
496
496
  .page {
497
497
  display: grid;
498
- gap: var(--base-content-gap, var(--sp-3));
498
+ gap: var(--page-gap, var(--sp-3));
499
499
  align-content: start; /* a tall column never stretches the rows — the words hug the top */
500
- padding-block: var(--base-content-pad-y, var(--sp-4));
500
+ padding-block: var(--page-pad-y, var(--sp-4));
501
501
  }
502
- .page > .t-body { color: var(--base-content-body-ink, var(--on-surface)); max-width: 34ch; } /* full ink: a sentence is read, muted is for meta (Lh 2026-09-22 — the words on the base were grey and hard to read) */
502
+ .page > .t-body { color: var(--page-body-ink, var(--on-surface)); max-width: 34ch; } /* full ink: a sentence is read, muted is for meta (Lh 2026-09-22 — the words on the base were grey and hard to read) */
503
503
  /* an illustration among the words (Lh 2026-09-22): capped, so a tall picture never pushes the words under the bar;
504
504
  (the walk's dots are NOT here — they are the Step's, after its Pages: step.css, Lh 2026-09-22) */
505
505
  /* the page's ONE heading on the base (a screen with no TopBar: CardHead level="h1") reads at the card heading's size —
506
506
  h1 is the semantic level, not a bigger face; --fs-h1 is the bar title's size (Lh 2026-09-22) */
507
507
  .page > .card__head > .t-h1 { font-size: var(--fs-h2); }
508
- .page > :is(img, .ph) { max-height: var(--base-content-media-h, 14rem); width: auto; height: auto; max-width: 100%; object-fit: contain; justify-self: start; align-self: start; } /* height auto: an <img> with width/height attributes keeps its ratio inside the cap — no band under the picture */
509
- .page > .ph { width: 100%; height: var(--base-content-media-h, 14rem); }
508
+ .page > :is(img, .ph) { max-height: var(--page-media-h, 14rem); width: auto; height: auto; max-width: 100%; object-fit: contain; justify-self: start; align-self: start; } /* height auto: an <img> with width/height attributes keeps its ratio inside the cap — no band under the picture */
509
+ .page > .ph { width: 100%; height: var(--page-media-h, 14rem); }
510
510
  .page .cta-pack {
511
511
  display: flex;
512
512
  align-items: start; /* buttons keep their own height, never the row's */
@@ -1073,7 +1073,7 @@ button { font: inherit; cursor: pointer; }
1073
1073
  gap: var(--card-gap, var(--sp-5));
1074
1074
  overflow: clip;
1075
1075
  }
1076
- /* a base that is ONE BaseContent is a page's words (a title, a welcome, the news): it reads from the TOP, like any page —
1076
+ /* a base that is ONE Page is a page's words (a title, a welcome, the news): it reads from the TOP, like any page —
1077
1077
  loose things (a picture, a line) still sit against the peeks (Lh 2026-09-23, the home) */
1078
1078
  .sheet-stack__base:has(> .page:only-child) { align-content: start; }
1079
1079
 
@@ -1678,13 +1678,13 @@ button { font: inherit; cursor: pointer; }
1678
1678
  .screen--fill > .appbar:has(+ .step) { margin-bottom: calc(-1 * var(--screen-gap)); }
1679
1679
  .screen--fill > .appbar + .sheet-stage { margin-top: 0; }
1680
1680
  /* a walk page that OPENS on a picture (Lh 2026-09-23): the picture takes the lead's room — as wide as the content (edge to edge), from the top edge, as tall as
1681
- the lead + the picture's own height (--base-content-media-h), square — so the words start where they always did */
1681
+ the lead + the picture's own height (--page-media-h), square — so the words start where they always did */
1682
1682
  .step > .pages > .page:has(> :is(img, .ph):first-child) { margin-top: 0; }
1683
1683
  .step > .pages > .page > :is(img, .ph):first-child {
1684
1684
  width: calc(100% + 2 * var(--screen-pad)); /* the content's width: the page's inset given back */
1685
1685
  max-width: none;
1686
1686
  margin-inline: calc(-1 * var(--screen-pad));
1687
- height: calc(var(--_lead, 0rem) + var(--base-content-media-h, 14rem));
1687
+ height: calc(var(--_lead, 0rem) + var(--page-media-h, 14rem));
1688
1688
  max-height: none;
1689
1689
  border-radius: 0;
1690
1690
  border-inline: 0;
@@ -2070,6 +2070,15 @@ button { font: inherit; cursor: pointer; }
2070
2070
  display: flex;
2071
2071
  gap: var(--sp-2);
2072
2072
  }
2073
+ /* a bar INSIDE a scrolling (not fill) screen (Lh 2026-09-24, 0.7.0): the screen is a column at least one phone tall, the bar its
2074
+ last row — at the foot when the words are short, and sticky to the viewport's foot (above the keyboard) while they scroll;
2075
+ it takes the room it needs in the column, so nothing is added to the content for it */
2076
+ .screen:not(.screen--fill):has(> .action-bar) { display: flex; flex-direction: column; min-height: 100dvh; }
2077
+ .screen:not(.screen--fill) > .action-bar {
2078
+ position: sticky; inset-inline: auto; bottom: var(--kb, 0rem);
2079
+ max-width: none;
2080
+ margin: auto calc(-1 * var(--screen-pad)) 0;
2081
+ }
2073
2082
  .action-bar .btn { flex: 1; box-shadow: var(--shadow-float); }
2074
2083
  .action-bar .icon-btn { width: var(--btn-h); height: var(--btn-h); box-shadow: var(--shadow-float); }
2075
2084
 
@@ -2941,29 +2950,23 @@ button { font: inherit; cursor: pointer; }
2941
2950
  /* ---- bubble: a chat message — theirs on the left, mine on the right (Lh 2026-09-18, replaces the chip's tail) ----
2942
2951
  No tail: a rounded block whose corner nearest the sender is square-ish
2943
2952
  (bottom-left for theirs, bottom-right for mine), the way messaging apps
2944
- draw it. Under it a caption line (time · a tick), beside it small round
2945
- actions (a heart, more). A .thread stacks them.
2953
+ draw it. Under it a caption line (time · a tick). A .thread stacks them.
2946
2954
  <div class="thread">
2947
- <div class="bubble"><p class="bubble__body">…</p><span class="bubble__actions">…icon-btns…</span><span class="bubble__meta">Dec 4 · 8:15</span></div>
2955
+ <div class="bubble"><p class="bubble__body">…</p><span class="bubble__meta">Dec 4 · 8:15</span></div>
2948
2956
  <div class="bubble bubble--right">…</div>
2949
2957
  </div> */
2950
2958
  .thread { display: grid; gap: var(--thread-gap, var(--sp-4)); }
2951
- /* two columns: the message (max-content, but it gives way — minmax(0) — so a long one shrinks
2952
- and wraps while the actions stay beside it) and the actions; the meta on a second row under the message */
2959
+ /* one column: the message (max-content, but it gives way — minmax(0) — so a long one shrinks and wraps); the meta under it */
2953
2960
  .bubble {
2954
2961
  display: grid;
2955
- grid-template-columns: minmax(0, max-content) auto;
2962
+ grid-template-columns: minmax(0, max-content);
2956
2963
  justify-content: start;
2957
2964
  align-items: center;
2958
2965
  gap: var(--sp-1) var(--sp-3);
2959
2966
  max-width: var(--bubble-max-w, 75%); /* a message may run to three quarters of the thread (Lh 2026-09-23) */
2960
2967
  margin-right: auto; /* theirs: hugs the left */
2961
2968
  }
2962
- .bubble--right { grid-template-columns: auto minmax(0, max-content); justify-content: end; margin-right: 0; margin-left: auto; } /* mine: hugs the right, the actions on its left */
2963
- .bubble__body, .bubble__meta { grid-column: 1; }
2964
- .bubble__actions { grid-column: 2; grid-row: 1; }
2965
- .bubble--right > :is(.bubble__body, .bubble__meta) { grid-column: 2; }
2966
- .bubble--right > .bubble__actions { grid-column: 1; }
2969
+ .bubble--right { justify-content: end; margin-right: 0; margin-left: auto; } /* mine: hugs the right */
2967
2970
  .bubble__body {
2968
2971
  margin: 0;
2969
2972
  min-width: 0;
@@ -2982,7 +2985,6 @@ button { font: inherit; cursor: pointer; }
2982
2985
  color: var(--on-accent);
2983
2986
  text-align: right;
2984
2987
  }
2985
- .bubble__actions { display: flex; gap: var(--bubble-actions-gap, var(--sp-1)); flex: none; opacity: 0.7; }
2986
2988
  .bubble__meta { display: flex; align-items: center; gap: var(--bubble-meta-gap, var(--sp-1)); font: var(--bubble-meta-font, var(--type-caption)); color: var(--bubble-meta-ink, var(--on-surface-muted)); }
2987
2989
  .bubble--right > .bubble__meta { justify-self: end; }
2988
2990
  .bubble__meta > .icon { color: var(--accent); }
@@ -8,11 +8,9 @@ export interface BubbleProps extends ComponentProps<'div'> {
8
8
  side?: 'left' | 'right';
9
9
  /** the caption under the message — a time, a tick (an Icon) */
10
10
  meta?: ReactNode;
11
- /** small round buttons beside the message (a heart, more) */
12
- actions?: ReactNode;
13
11
  }
14
12
  /**
15
13
  * Bubble — a chat message: a rounded block, its corner nearest the sender squared (bottom-left for theirs, bottom-right
16
- * for mine), no tail. `meta` sits under it on the sender's side, `actions` beside it. Stack them in a Thread.
14
+ * for mine), no tail. `meta` sits under it on the sender's side. Stack them in a Thread.
17
15
  */
18
- export declare function Bubble({ side, meta, actions, className, children, ...rest }: BubbleProps): import("react").JSX.Element;
16
+ export declare function Bubble({ side, meta, className, children, ...rest }: BubbleProps): import("react").JSX.Element;
@@ -6,8 +6,8 @@ export function Thread({ className, ...rest }) {
6
6
  }
7
7
  /**
8
8
  * Bubble — a chat message: a rounded block, its corner nearest the sender squared (bottom-left for theirs, bottom-right
9
- * for mine), no tail. `meta` sits under it on the sender's side, `actions` beside it. Stack them in a Thread.
9
+ * for mine), no tail. `meta` sits under it on the sender's side. Stack them in a Thread.
10
10
  */
11
- export function Bubble({ side = 'left', meta, actions, className, children, ...rest }) {
12
- return (_jsxs("div", { className: cx('bubble', side === 'right' && 'bubble--right', className), ...rest, children: [_jsx("p", { className: "bubble__body", children: children }), actions != null && _jsx("span", { className: "bubble__actions", children: actions }), meta != null && _jsx("span", { className: "bubble__meta", children: meta })] }));
11
+ export function Bubble({ side = 'left', meta, className, children, ...rest }) {
12
+ return (_jsxs("div", { className: cx('bubble', side === 'right' && 'bubble--right', className), ...rest, children: [_jsx("p", { className: "bubble__body", children: children }), meta != null && _jsx("span", { className: "bubble__meta", children: meta })] }));
13
13
  }
@@ -8,9 +8,6 @@ export interface PageProps extends ComponentProps<'section'> {
8
8
  * a still, one-scaffold screen, which is gone.
9
9
  */
10
10
  export declare function Page({ className, ...rest }: PageProps): import("react").JSX.Element;
11
- /** @deprecated renamed `Page` (2026-09-23) — same props, same markup; kept one version for the move */
12
- export declare function BaseContent(props: PageProps): import("react").JSX.Element;
13
- export type BaseContentProps = PageProps;
14
11
  export interface CtaPackProps extends ComponentProps<'div'> {
15
12
  }
16
13
  /** CtaPack — the buttons under a Page's words, wrapping on one line. In a Step it holds ways in (each opens a sheet — the app wires that); the Step's own move is never here. */
@@ -9,15 +9,6 @@ import { cx } from '../cx.js';
9
9
  export function Page({ className, ...rest }) {
10
10
  return _jsx("section", { className: cx('page', className), ...rest });
11
11
  }
12
- let warned = false;
13
- /** @deprecated renamed `Page` (2026-09-23) — same props, same markup; kept one version for the move */
14
- export function BaseContent(props) {
15
- if (!warned) {
16
- warned = true;
17
- console.warn('cardds: BaseContent is now Page — rename it (same props).');
18
- }
19
- return _jsx(Page, { ...props });
20
- }
21
12
  /** CtaPack — the buttons under a Page's words, wrapping on one line. In a Step it holds ways in (each opens a sheet — the app wires that); the Step's own move is never here. */
22
13
  export function CtaPack({ className, ...rest }) {
23
14
  return _jsx("div", { className: cx('cta-pack', className), ...rest });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@usableapp/cardds",
3
- "version": "0.6.16",
3
+ "version": "0.7.0",
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.",