@pieai/swimmer-ui-kit 2.3.0 → 2.4.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
@@ -3,6 +3,81 @@
3
3
  All notable changes to `@pieai/swimmer-ui-kit`.
4
4
  Format: [Keep a Changelog](https://keepachangelog.com); versioning: semver.
5
5
 
6
+ ## 2.4.0 — 2026-09-11
7
+
8
+ Minor: additive. One new token, six new form names, and a cast shadow that
9
+ every liquid body was missing.
10
+
11
+ ### Added
12
+
13
+ - **A cast shadow on the single-body forms.** `LiquidSurface` accepted a
14
+ `shadow` and no form set one, so every liquid button floated: the flat button
15
+ standing next to it carries a solid lip *and* `--game-ui-shadow-button`, and
16
+ the liquid one carried neither. `press`, `settle`, `drain`, and the new
17
+ `swell`, `reach`, `ripple` and `set` now carry two layers each — a tight,
18
+ barely-offset seat that says the body is touching, and a wide low cast that
19
+ gives it height. Compared at device ratio 1 against the flat control, a seat
20
+ alone glues the body to the page and a cast alone leaves it hovering.
21
+
22
+ Every layer is outer and spreadless, which is the case
23
+ `compositorDropShadowFilter` lifts onto the compositor: it costs no filter
24
+ area and it hugs the poured outline rather than a rounded rectangle. A caller
25
+ that wants its own ground still passes `shadow`, and `shadow="none"` removes
26
+ it.
27
+
28
+ - **`--game-ui-shadow-liquid-ink`.** The colour a liquid body casts, per theme.
29
+ It is a solid colour rather than a finished shadow, so a form states strength
30
+ and offset without restating the room's light. Deliberately **not** added to
31
+ `GAME_UI_THEME_CONTRACT`: that list is exported for downstream themes to
32
+ self-check, and adding an entry would turn a consumer's green check red for a
33
+ token they have never heard of. A theme that does not define it gets the
34
+ light theme's warm brown ink.
35
+
36
+ - **`shadowEngaged` on a form, and a shadow that answers the gesture.** A
37
+ pressed body is nearer the ground, so its seat hardens and its cast collapses
38
+ toward it; `settle` rests mid-air with no seat at all and gains one on
39
+ landing, which is the moment that form exists to mark. The silhouette's
40
+ filter transitions, so the shadow no longer arrives before the thing casting
41
+ it.
42
+
43
+ - **Six more forms: `set`, `swell`, `reach`, `ripple`, `split`, `bead`.** Each
44
+ says something none of the previous six could. `set` is the only one that
45
+ stops being liquid — everything else is a degree of wetness — and it snaps
46
+ rather than tweening, because setting is a discontinuity. `swell` is
47
+ attention with nothing touching it, so it is the one moving form with no
48
+ squash. `reach` is the only form with a direction. `ripple` says 「no」 by
49
+ moving and leaves its shape alone. `split` is `merge` backwards with a harder
50
+ edge and more recoil. `bead` is the one relationship form that pours, because
51
+ its bodies are the message rather than the neck between them.
52
+
53
+ - **`kind` on every form, and `LiquidFormKind`.** A form is one body or a
54
+ relationship between siblings. `LiquidSurface` can only draw the first;
55
+ handing it a group form used to render a correct-looking body that silently
56
+ never moved, and it now warns once, in every build.
57
+
58
+ - **`groupEngaged` on a form.** Group knobs that change while engaged. Only
59
+ `set` uses it. `blob` is path data and `gloss` is a filter pass, so neither
60
+ tweens — they snap, which is right for one form and a flicker for any other.
61
+
62
+ - **`LIQUID_BLOB_MAX_FRACTION`.** The share of a box's shorter side a poured
63
+ outline may swell by (0.18). Exported because it is why one `blob` value can
64
+ be handed to a 44px button and a 14px meter, and a number written in three
65
+ places drifts in two.
66
+
67
+ - **A Liquid page on the showcase site, at `/liquid.html`.** Every form live and
68
+ triggerable, at a control size and a meter size, on any of the four tones, in
69
+ both themes, with its knobs — including the derived edge width in px — written
70
+ out beside it.
71
+
72
+ ### Changed
73
+
74
+ - **`GameUiPreview`'s liquid section is smaller.** It keeps what a component
75
+ gallery is for — `surface` is a second axis on `GameButton` — and links out to
76
+ the Liquid page for the vocabulary. Two shelves meant two to update and, in
77
+ practice, one of them lagging. Hosts that render `<GameUiPreview />` and do
78
+ not serve `liquid.html` will have a link that does not resolve; the section
79
+ otherwise stands on its own.
80
+
6
81
  ## 2.3.0 — 2026-09-11
7
82
 
8
83
  Minor: additive, plus one token value change on the default liquid fill.
package/dist/index.d.ts CHANGED
@@ -2353,10 +2353,22 @@ export declare const LIQUID_FORMS: Readonly<Record<LiquidForm, LiquidFormSpec>>;
2353
2353
  export declare const LIQUID_GOOEY_WAVINESS_MAX_FRACTION = 0.3;
2354
2354
 
2355
2355
  /**
2356
- * The named looks, ordered by how much cohesion the liquid is losing:
2357
- * `press` barely deforms, `drain` stops being a shape at all.
2356
+ * The named looks.
2357
+ *
2358
+ * Bodies first, then the forms that only mean something between siblings, and
2359
+ * within each run they are ordered by how much cohesion the liquid is losing:
2360
+ * `set` stops being liquid at all, `press` barely deforms, `drain` stops being
2361
+ * a shape.
2362
+ *
2363
+ * Six of these were the whole vocabulary until the brand needed more of it,
2364
+ * and six is worth saying out loud as *where it got to* rather than as a
2365
+ * complete set. A form earns its place by having something to say that none of
2366
+ * the others says. That is the only entry requirement — and it is also why a
2367
+ * form existing here is not permission to put it on a screen: the recorded
2368
+ * finding is that gooey on a static solid block reads as damage, and that one
2369
+ * screen wants one liquid element carrying one layer of intent.
2358
2370
  */
2359
- export declare type LiquidForm = 'press' | 'settle' | 'merge' | 'follow' | 'fill' | 'drain';
2371
+ export declare type LiquidForm = 'set' | 'press' | 'swell' | 'settle' | 'fill' | 'reach' | 'ripple' | 'drain' | 'follow' | 'merge' | 'split' | 'bead';
2360
2372
 
2361
2373
  /** Filter-level knobs a form fixes on the group. */
2362
2374
  export declare interface LiquidFormGroup {
@@ -2377,6 +2389,32 @@ export declare interface LiquidFormGroup {
2377
2389
  */
2378
2390
  readonly gloss: number;
2379
2391
  readonly filterPadding: number;
2392
+ /**
2393
+ * What the body casts on the ground at rest, in CSS box-shadow syntax.
2394
+ *
2395
+ * Every liquid button floated before this existed: the flat button has a lip
2396
+ * *and* `--game-ui-shadow-button`, and the liquid one had neither, which is
2397
+ * most of why it read flatter than its own flat twin. A form is where this
2398
+ * belongs rather than a call site, because how far a body sits off the
2399
+ * surface is part of what the form means.
2400
+ *
2401
+ * Keep it to outer layers with no spread. `liquidGooeyShadow` compiles those
2402
+ * to a CSS `drop-shadow()` on the silhouette — the compositor does the blur,
2403
+ * the shadow hugs the poured outline rather than a rounded rectangle, and it
2404
+ * is allowed to paint outside the filter region. Inset and spread are legal
2405
+ * but stay inside the SVG filter and are charged against the filter-area
2406
+ * budget, so they are a deliberate purchase, not a default.
2407
+ */
2408
+ readonly shadow?: string;
2409
+ /**
2410
+ * What it casts while the form is engaged, when that differs.
2411
+ *
2412
+ * A body that squashes toward the surface gets *closer* to it, and a real
2413
+ * contact shadow answers by tightening and darkening rather than staying
2414
+ * put. Leaving this out is fine; the rest shadow then holds through the
2415
+ * whole gesture, which is what a form with no vertical travel wants.
2416
+ */
2417
+ readonly shadowEngaged?: string;
2380
2418
  }
2381
2419
 
2382
2420
  /**
@@ -2399,10 +2437,37 @@ export declare interface LiquidFormItem {
2399
2437
  /** Resolve a form into item props, with the same merge-don't-replace rule. */
2400
2438
  export declare function liquidFormItem(form: LiquidForm, overrides?: LiquidFormItem): LiquidFormItem;
2401
2439
 
2440
+ /**
2441
+ * Whether a form describes one body or a relationship between siblings.
2442
+ *
2443
+ * `LiquidSurface` draws one silhouette, so it can only honour a `body` form;
2444
+ * a `group` form says something about the space *between* items and needs a
2445
+ * `LiquidGroup` the caller arranges. That distinction used to live in a
2446
+ * parenthetical — `ENGAGED` carried two entries marked 「present for
2447
+ * exhaustiveness」 — which meant picking the wrong one failed silently, by
2448
+ * rendering a body that never moves. Naming it lets a shelf group itself, lets
2449
+ * a caller check, and lets the kit say so out loud in development.
2450
+ */
2451
+ export declare type LiquidFormKind = 'body' | 'group';
2452
+
2402
2453
  export declare interface LiquidFormSpec {
2403
2454
  /** One sentence on what a viewer sees, for docs and for picking. */
2404
2455
  readonly summary: string;
2456
+ /** One body, or a relationship between siblings the caller arranges. */
2457
+ readonly kind: LiquidFormKind;
2405
2458
  readonly group: LiquidFormGroup;
2459
+ /**
2460
+ * Group knobs that change while the form is engaged.
2461
+ *
2462
+ * Only `set` uses this, and only because `set` is the one form whose subject
2463
+ * is *stopping* being liquid — without it the vocabulary can say a dozen
2464
+ * degrees of liquid and never say 「solid」. Be careful with it: `blob` is
2465
+ * path data and `gloss` is a filter pass, so neither tweens. They snap. For
2466
+ * `set` that snap is the gesture — a thing clicking into place — and for
2467
+ * anything continuous it would be a flicker, which is why this is not a
2468
+ * general-purpose second bundle.
2469
+ */
2470
+ readonly groupEngaged?: Partial<LiquidFormGroup>;
2406
2471
  readonly item: LiquidFormItem;
2407
2472
  }
2408
2473
 
@@ -2557,7 +2622,7 @@ export declare interface LiquidMetalButtonProps extends ButtonHTMLAttributes<HTM
2557
2622
 
2558
2623
  export declare type LiquidMetalRendererMode = 'auto' | 'css' | 'webgl';
2559
2624
 
2560
- export declare function LiquidSurface({ children, form, active, fill, stroke, shadow, radius, className, style, }: LiquidSurfaceProps): ReactNode;
2625
+ export declare function LiquidSurface({ children, form, active, fill, stroke, shadow: shadowOverride, radius, className, style, }: LiquidSurfaceProps): ReactNode;
2561
2626
 
2562
2627
  export declare interface LiquidSurfaceProps {
2563
2628
  children: ReactNode;
@@ -2571,6 +2636,7 @@ export declare interface LiquidSurfaceProps {
2571
2636
  /** Silhouette paint. Defaults to the kit's raised surface token. */
2572
2637
  fill?: string;
2573
2638
  stroke?: string;
2639
+ /** Overrides the form's own cast shadow. `none` removes it. */
2574
2640
  shadow?: string;
2575
2641
  /** Corner radius of the body, in px. 999 gives a pill. */
2576
2642
  radius?: number;