@pieai/swimmer-ui-kit 2.4.0 → 2.6.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,133 @@
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.6.0 — 2026-09-12
7
+
8
+ Minor: new optional material selection and native controls. Existing root
9
+ exports and export-map paths remain; omitted options retain prior defaults.
10
+
11
+ ### Added
12
+
13
+ - `LiquidFinish` and optional `liquidFinish="matte" | "glossy"` across
14
+ LiquidGroup/LiquidSurface, GameButton, GameIconButton, GameToggle,
15
+ GameSegmentedControl, GameProgress and GameSelect. Both finishes reuse the
16
+ existing renderer; matte removes the specular pass, not motion or shadows.
17
+ Explicit LiquidGroup `gloss` remains the advanced override.
18
+ - Liquid icon buttons and switch thumbs; GameSelect uses a real native select
19
+ with optional liquid closed-field decoration, form/reset/ref/optgroup support,
20
+ invalid semantics and ordinary disabled/multiple/list modes. The popup remains
21
+ platform-native; this is not a searchable combobox or custom liquid listbox.
22
+ - Optional flat, filter-free progress and segmented surfaces. Slider forwards
23
+ native step, disabled, name and id.
24
+ - A beginner catalog at the site root: 12 shared recipe groups, 6 liquid control
25
+ categories, matte/glossy comparison, theme/state selection, actual interaction,
26
+ complete copyable/typechecked React examples and shareable configuration URLs.
27
+ Storybook uses the same recipes. The old reference remains at `/?view=reference`
28
+ and old `#game-ui-preview-*` links still open it.
29
+
30
+ ### Fixed and intentionally changed
31
+
32
+ - Press decoration ignores secondary pointer buttons and key repeat, clears on
33
+ lost capture/cancellation/blur, resets through disabled, and honors `static`.
34
+ Native content and hit targets never inherit the squash transform.
35
+ - The liquid button's native element no longer picks up the ordinary button's
36
+ independent CSS `scale` on press or hover lift; only the silhouette moves.
37
+ - Pointer feedback survives macOS WebKit's native pointerdown-then-blur ordering;
38
+ a true window deactivation still cancels the gesture. No focus is forced onto
39
+ the native control to hide this platform difference.
40
+ - Progress ARIA values now agree with the clamped visible value, including invalid
41
+ maxima and non-finite input. Forced-colors decoration falls back to system UI.
42
+ - `GameInput` and `GameTextArea` now expose `invalid` through `aria-invalid`,
43
+ like the new select; an explicit ARIA value still wins.
44
+ - Select decoration is a sibling of the persistent native field. Disabling,
45
+ changing material or switching single/list presentation must not remount the
46
+ select and lose an uncontrolled choice or replace its forwarded DOM ref.
47
+ Catalog material/state adjustments likewise preserve the current example's
48
+ entered values instead of silently resetting the recipe.
49
+ - Disabled icon buttons, switches and segmented options now have a quiet,
50
+ non-hovering treatment. Disabled segmented controls retain the selected option
51
+ on a flat surface instead of reserving animated liquid groups.
52
+ Inherited native fieldset disabling also hides button/icon/switch/select decoration.
53
+ - The liquid form page selects experiments instead of mounting every form, size,
54
+ tone and state simultaneously. At most two liquid groups are mounted; the shared
55
+ budget was not increased and the twelve forms were not removed or retuned.
56
+
57
+ ### Consumer action
58
+
59
+ Pin the new version and run your own product gates. New materials/controls are
60
+ opt-in; University was not modified. Do not remove its destination/route transition
61
+ when adopting kit buttons. See the upgrade playbook for adoption and rollback.
62
+ No new runtime dependency, ambient clock, donor observer, image optimization or
63
+ commercial donor preset is introduced by this release.
64
+
65
+ ## 2.5.0 — 2026-09-12
66
+
67
+ ### Find the right component before reading the whole API
68
+
69
+ - README now starts with a task-based component selection guide. A primary
70
+ button is `GameButton variant="primary"`; a liquid CTA adds
71
+ `surface="liquid"`. The documented README → recipe → live story path takes
72
+ no more than three steps. Preview opens with the same primary-action examples;
73
+ code recipes wrap and the existing showcase navigation fits narrow screens.
74
+ Preview-only grid, asset-path and construction-status wrapping fixes prevent
75
+ horizontal page overflow; anchored headings stay below the sticky navigation.
76
+ These shelf-layout fixes do not alter consumer component styles.
77
+ - A TypeScript-generated inventory classifies all **272** existing named root
78
+ exports (**121 values / 151 types**) and links their definitions. The frozen
79
+ audit records actual local symbol references and read-only University imports;
80
+ no observed import is not evidence that a public helper is safe to remove.
81
+ `pnpm api:inventory` regenerates the index; `pnpm api:check` joins `verify`.
82
+ - **No root export was removed, renamed or moved to a new package subpath.**
83
+ Package export routes, existing class/token names, the ESM-only / zero-runtime-
84
+ dependency contract and all twelve liquid forms remain intact.
85
+
86
+ ### A ready-to-use liquid CTA, not another liquid engine
87
+
88
+ - Add optional `GameButton.fullWidth`. Both the native button and its liquid
89
+ silhouette fill the available row; omitted/false preserves existing layout.
90
+ Native disabled, submit, keyboard, focus, pointer-cancel and reduced-motion
91
+ behavior remain. Preview and Storybook include ordinary, liquid, full-width
92
+ and disabled examples, with browser and markup regression tests.
93
+ - Reuse the existing `press` form and its non-uniform squash / `wobbly` rebound.
94
+ There is **no new `cta` form and no retuning of the 2.4.0 liquid engine,
95
+ geometry, shadows or presets**. Newcomers no longer need to assemble a CTA
96
+ from `LiquidGroup` physics knobs.
97
+
98
+ ### Documentation and evidence convergence
99
+
100
+ - Retire the ambiguous `doc/` tree: preserve the six historical tutorials and
101
+ unimplemented 3D-icon research in `docs/archive/legacy-doc/`; reconcile the
102
+ active liquid-primitives and game-surface guides in `docs/reference/`.
103
+ - Archive the extraction report, retired July upgrade plan and version-scoped
104
+ edge/shadow measurements. The July plan is **not** marked wholly completed.
105
+ Original archive bodies and all pre-existing PNG bytes/paths are retained.
106
+ The [relocation map](docs/archive/relocations-2.5.0.json) records every reason.
107
+ - Keep `PRODUCT.md` and `CONCEPTS.md` as tool adapters pointing to the design
108
+ guide; keep `AGENTS.md`, its `CLAUDE.md` symlink and live donor provenance.
109
+ Label historical `artifacts/` and six `SCRATCH/` captures instead of deleting
110
+ evidence with unenumerated external readers. Ignore new scratch output.
111
+ - Record the next-stage matte/glossy liquid catalog, widget coverage and donor
112
+ investigation in `docs/reference/liquid-next-stage-research.md`.
113
+ **That roadmap is research, not a shipped finish API or new widget suite.**
114
+
115
+ ### Consumer action: University 2.4.0 → 2.5.0
116
+
117
+ Pin **all three** packages (`packages/ui`, `packages/world`, `apps/university`)
118
+ to 2.5.0, then run the product's own gates. Existing imports need no migration.
119
+ University was inspected read-only; it was **not** modified by this release.
120
+
121
+ Migrating its custom `LiquidCtaButton` is a separate optional change:
122
+ `width="full"` maps to `fullWidth`, while the product keeps destination
123
+ registration, routing and `LiquidCtaTransition`. Its old uniform `scale=0.95`
124
+ / `bouncy` motion deliberately changes to the kit's existing `press` behavior
125
+ only when that custom wrapper is migrated. Preserve transition source geometry,
126
+ callback ordering and tests; do not discard the 823-line transition as if the
127
+ kit had absorbed it. See the [upgrade playbook](docs/reference/usage-and-upgrade-playbook.md)
128
+ for exact commands, CSS ownership, acceptance cases and rollback.
129
+
130
+ This is a **minor**: additive opt-in layout and discovery, not a public-export
131
+ restructure. Any future restructure still requires a major and compatibility path.
132
+
6
133
  ## 2.4.0 — 2026-09-11
7
134
 
8
135
  Minor: additive. One new token, six new form names, and a cast shadow that
@@ -271,7 +398,8 @@ removed member never worked makes the removal correct, not non-breaking.
271
398
  WebKit CPU-rasterises large SVG blurs. Inset and spread stay in SVG; they
272
399
  are not expressible as `drop-shadow()` and they are cheap. The pad no longer
273
400
  reserves the outer blur. Visual comparison of the segmented indicator and
274
- the merged-blob story is in `SHADOW-COST.md`.
401
+ the merged-blob story is in `docs/archive/measurements/liquid-shadow-cost-2.0.0.md`
402
+ (formerly `SHADOW-COST.md`).
275
403
 
276
404
  - **Two authoring warnings were still dead in the published bundle.** 1.11.2
277
405
  unblocked the budget warnings; `LiquidGroup.Item` children-with-border and
package/README.md CHANGED
@@ -9,18 +9,26 @@ Source is publicly readable. Use is governed by the
9
9
  [PieAI Limited Use License](./LICENSE), not an open-source license. The visual
10
10
  assets may not be extracted, modified, or redistributed as a standalone pack.
11
11
 
12
+ - **Start here / 我该用哪个组件?**
13
+ [Primary button, liquid CTA, forms, panels and other tasks](docs/reference/component-selection-guide.md)
12
14
  - Design system truth (tokens, theming, motion, a11y):
13
- `docs/reference/design-system-guide.md`
15
+ [Design system guide](docs/reference/design-system-guide.md)
14
16
  - Consumer onboarding / upgrade SOP / release checklist:
15
- `docs/reference/usage-and-upgrade-playbook.md`
16
- - Live catalog: `pnpm dev` (preview page) and `pnpm storybook`
17
+ [Usage and upgrade playbook](docs/reference/usage-and-upgrade-playbook.md)
18
+ - Exhaustive reference (not the starting point):
19
+ [Generated public API inventory](docs/reference/public-api-inventory.md)
20
+ - [Interactive catalog](https://swimmer-ui-kit.pieaistudio.com/): real controls,
21
+ matte/glossy comparison, theme/state selectors and copyable React examples.
22
+ - [Full reference](https://swimmer-ui-kit.pieaistudio.com/?view=reference) and
23
+ [liquid form laboratory](https://swimmer-ui-kit.pieaistudio.com/liquid.html).
24
+ Local: `pnpm dev` and `pnpm storybook`.
17
25
 
18
26
  ## Install
19
27
 
20
28
  ```json
21
29
  {
22
30
  "dependencies": {
23
- "@pieai/swimmer-ui-kit": "2.1.0"
31
+ "@pieai/swimmer-ui-kit": "2.6.0"
24
32
  }
25
33
  }
26
34
  ```
@@ -48,7 +56,7 @@ import '@pieai/swimmer-ui-kit/tailwind.css';
48
56
 
49
57
  ## What's inside
50
58
 
51
- - **~60 components** across: core controls (`GameButton`,
59
+ - **Ready-to-use components** across: core controls (`GameButton`,
52
60
  `LiquidMetalButton`, `GameTabs`,
53
61
  `GameSlider`, `GameToggle`, `GameForms` inputs…), panels and windows
54
62
  (`GamePanel`, `GameCollapsiblePanel`, `GameWindowPanel`, `GameModal` on
@@ -145,10 +153,15 @@ See `CHANGELOG.md` for release history and migration notes.
145
153
  pnpm install
146
154
  pnpm dev # preview page (token ledger + all surfaces)
147
155
  pnpm storybook # component catalog
148
- pnpm typecheck && pnpm test && pnpm build && pnpm docs:check
156
+ pnpm verify && pnpm docs:check
157
+ pnpm api:inventory # regenerate the public API index after a reviewed API change
149
158
  ```
150
159
 
151
160
  Releases use GitHub Actions Trusted Publishing: bump `package.json`, commit and
152
161
  push `main`, then run `gh workflow run npm-publish.yml --ref main`. The manual
153
162
  workflow is the release safety switch; it publishes to npmjs with short-lived
154
163
  OIDC credentials and provenance, without a local login or stored npm token.
164
+
165
+ The former `doc/` tutorials and one-off root reports are catalogued in the
166
+ [documentation and evidence relocation record](docs/archive/relocations-2.5.0.json). Historical
167
+ material is retained, but installation and component selection follow the guides above.
package/dist/index.d.ts CHANGED
@@ -5,6 +5,7 @@ import { HTMLAttributes } from 'react';
5
5
  import { InputHTMLAttributes } from 'react';
6
6
  import { ReactNode } from 'react';
7
7
  import { RefAttributes } from 'react';
8
+ import { SelectHTMLAttributes } from 'react';
8
9
  import { TextareaHTMLAttributes } from 'react';
9
10
 
10
11
  /** Opt in to placeholders on purpose, and stop being told about it. */
@@ -1376,10 +1377,14 @@ export declare interface GameBuildLibraryProps {
1376
1377
  'data-testid'?: string | undefined;
1377
1378
  }
1378
1379
 
1379
- export declare function GameButton({ children, className, onClick, sound, static: isStatic, surface, type, variant, ...props }: GameButtonProps): ReactNode;
1380
+ export declare function GameButton({ children, className, fullWidth, liquidFinish, onClick, sound, static: isStatic, surface, type, variant, ...props }: GameButtonProps): ReactNode;
1380
1381
 
1381
1382
  export declare interface GameButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
1382
1383
  children: ReactNode;
1384
+ /** Fill the available row, including the liquid silhouette and hit target. */
1385
+ fullWidth?: boolean;
1386
+ /** Named liquid material. Only used with surface="liquid"; omitted keeps the current look. */
1387
+ liquidFinish?: LiquidFinish;
1383
1388
  sound?: GameInteractionSoundOptions | false;
1384
1389
  /** Disable the scale-on-press feedback where the motion would distract. */
1385
1390
  static?: boolean;
@@ -1725,11 +1730,13 @@ export declare interface GameHudProps {
1725
1730
  label: string;
1726
1731
  }
1727
1732
 
1728
- export declare function GameIconButton({ children, className, label, type, ...props }: GameIconButtonProps): ReactNode;
1733
+ export declare function GameIconButton({ children, className, label, surface, liquidFinish, type, ...props }: GameIconButtonProps): ReactNode;
1729
1734
 
1730
1735
  export declare interface GameIconButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
1731
1736
  children: ReactNode;
1732
1737
  label: string;
1738
+ surface?: GameButtonSurface;
1739
+ liquidFinish?: LiquidFinish;
1733
1740
  }
1734
1741
 
1735
1742
  export declare const GameInput: ForwardRefExoticComponent<GameInputProps & RefAttributes<HTMLInputElement>>;
@@ -1910,9 +1917,12 @@ export declare interface GamePlacementToolbarProps {
1910
1917
  title: string;
1911
1918
  }
1912
1919
 
1913
- export declare function GameProgress({ className, label, max, showValue, tone, value, valueLabel, }: GameProgressProps): ReactNode;
1920
+ export declare function GameProgress({ className, label, max, showValue, tone, value, valueLabel, surface, liquidFinish, }: GameProgressProps): ReactNode;
1914
1921
 
1915
1922
  export declare interface GameProgressProps {
1923
+ /** Defaults to the existing liquid leading edge. Flat adds no SVG filter. */
1924
+ surface?: GameButtonSurface;
1925
+ liquidFinish?: LiquidFinish;
1916
1926
  /** Current value, between 0 and `max`. */
1917
1927
  value: number;
1918
1928
  max?: number;
@@ -1978,13 +1988,17 @@ export declare const GameSceneHudLayout: typeof GameShell;
1978
1988
 
1979
1989
  export declare type GameSceneHudLayoutProps = GameShellProps;
1980
1990
 
1981
- export declare function GameSegmentedControl({ activeId, label, onSelect, options, }: GameSegmentedControlProps): ReactNode;
1991
+ export declare function GameSegmentedControl({ activeId, label, onSelect, options, surface, liquidFinish, disabled, }: GameSegmentedControlProps): ReactNode;
1982
1992
 
1983
1993
  export declare interface GameSegmentedControlProps {
1984
1994
  activeId: string;
1985
1995
  label: string;
1986
1996
  onSelect?: (id: string) => void;
1987
1997
  options: readonly GameSegmentedOption[];
1998
+ /** Existing default is liquid. Flat provides a quiet, filter-free option. */
1999
+ surface?: GameButtonSurface;
2000
+ liquidFinish?: LiquidFinish;
2001
+ disabled?: boolean;
1988
2002
  }
1989
2003
 
1990
2004
  declare interface GameSegmentedOption {
@@ -1992,6 +2006,20 @@ declare interface GameSegmentedOption {
1992
2006
  label: string;
1993
2007
  }
1994
2008
 
2009
+ /**
2010
+ * Native select, not a custom listbox state machine. Options/optgroups, form
2011
+ * submission, reset, keyboard and the mobile picker remain browser-owned.
2012
+ * Liquid paints only the closed single-select field. Disabled/multiple/list
2013
+ * modes use the ordinary surface; we do not pretend to animate an OS popup.
2014
+ */
2015
+ export declare const GameSelect: ForwardRefExoticComponent<GameSelectProps & RefAttributes<HTMLSelectElement>>;
2016
+
2017
+ export declare interface GameSelectProps extends SelectHTMLAttributes<HTMLSelectElement> {
2018
+ invalid?: boolean;
2019
+ surface?: GameButtonSurface;
2020
+ liquidFinish?: LiquidFinish;
2021
+ }
2022
+
1995
2023
  export declare function GameShell({ assetLibrary, bottomBar, children, className, density, hud, layout, movementPad, overlay, sidePanel, title, }: GameShellProps): ReactNode;
1996
2024
 
1997
2025
  export declare interface GameShellProps {
@@ -2016,9 +2044,9 @@ export declare interface GameShellProps {
2016
2044
  title: string;
2017
2045
  }
2018
2046
 
2019
- export declare function GameSlider({ label, max, min, onChange, value }: GameSliderProps): ReactNode;
2047
+ export declare function GameSlider({ label, max, min, step, disabled, name, id, onChange, value, }: GameSliderProps): ReactNode;
2020
2048
 
2021
- export declare interface GameSliderProps extends Pick<InputHTMLAttributes<HTMLInputElement>, 'max' | 'min' | 'value'> {
2049
+ export declare interface GameSliderProps extends Pick<InputHTMLAttributes<HTMLInputElement>, 'max' | 'min' | 'value' | 'step' | 'disabled' | 'name' | 'id'> {
2022
2050
  label: string;
2023
2051
  onChange?: (value: number) => void;
2024
2052
  }
@@ -2198,11 +2226,13 @@ export declare interface GameToastProps {
2198
2226
  tone?: 'info' | 'success' | 'danger';
2199
2227
  }
2200
2228
 
2201
- export declare function GameToggle({ checked, disabled, label, onClick }: GameToggleProps): ReactNode;
2229
+ export declare function GameToggle({ checked, disabled, label, onClick, surface, liquidFinish, }: GameToggleProps): ReactNode;
2202
2230
 
2203
2231
  export declare interface GameToggleProps extends Pick<ButtonHTMLAttributes<HTMLButtonElement>, 'disabled' | 'onClick'> {
2204
2232
  checked: boolean;
2205
2233
  label: string;
2234
+ surface?: GameButtonSurface;
2235
+ liquidFinish?: LiquidFinish;
2206
2236
  }
2207
2237
 
2208
2238
  export declare function GameTooltip({ children, label }: GameTooltipProps): ReactNode;
@@ -2352,6 +2382,9 @@ export declare const LIQUID_FORMS: Readonly<Record<LiquidForm, LiquidFormSpec>>;
2352
2382
  */
2353
2383
  export declare const LIQUID_GOOEY_WAVINESS_MAX_FRACTION = 0.3;
2354
2384
 
2385
+ /** Material is independent of a widget's meaning and a form's motion. */
2386
+ export declare type LiquidFinish = 'matte' | 'glossy';
2387
+
2355
2388
  /**
2356
2389
  * The named looks.
2357
2390
  *
@@ -2530,6 +2563,8 @@ export declare interface LiquidGroupProps extends Omit<HTMLAttributes<HTMLDivEle
2530
2563
  * curved surface so it reads as a material rather than as a silhouette.
2531
2564
  */
2532
2565
  gloss?: number;
2566
+ /** Optional named finish. An explicit raw gloss wins; omitted preserves the old rendering. */
2567
+ liquidFinish?: LiquidFinish;
2533
2568
  /** Surface fill. Defaults to the kit's theme surface token. */
2534
2569
  fill?: string;
2535
2570
  /** Extra filter-region slack in px for the silhouette's painted edges. */
@@ -2622,10 +2657,12 @@ export declare interface LiquidMetalButtonProps extends ButtonHTMLAttributes<HTM
2622
2657
 
2623
2658
  export declare type LiquidMetalRendererMode = 'auto' | 'css' | 'webgl';
2624
2659
 
2625
- export declare function LiquidSurface({ children, form, active, fill, stroke, shadow: shadowOverride, radius, className, style, }: LiquidSurfaceProps): ReactNode;
2660
+ export declare function LiquidSurface({ children, liquidFinish, form, active, fill, stroke, shadow: shadowOverride, radius, className, style, }: LiquidSurfaceProps): ReactNode;
2626
2661
 
2627
2662
  export declare interface LiquidSurfaceProps {
2628
2663
  children: ReactNode;
2664
+ /** Omitted keeps the form's existing lighting; matte and glossy share the same motion. */
2665
+ liquidFinish?: LiquidFinish;
2629
2666
  /** Which named look. Defaults to the press form, the one a control wants. */
2630
2667
  form?: LiquidForm;
2631
2668
  /**