utils/web_ui/package.json
Krzysztof kuhy Rudnicki f7418969cf Freeze the motion, haptic and sound vocabularies, and ship them as tokens
dopamine-ux prompt 01. The token layer froze colour, spacing, radius and type,
but every animation in every app picked its own duration and curve out of the
air -- so "200ms ease-in-out" and "180ms ease-out" both existed and neither was
wrong, because nothing said what right was.

unified-design-system/motion.md is the freeze: four durations, three curves,
a haptic vocabulary mapped onto Flutter's HapticFeedback, and three sound cues,
each with its one-line rationale. Shipped as AppDuration/AppCurve in Dart and
--duration-*/--ease-* in CSS, so a consumer imports the scale instead of
transcribing it.

Three things worth stating, because they are the parts easy to get wrong:

- Reduced motion collapses the *tokens themselves* (CSS @media, Flutter
  disableAnimations), so no consumer has to remember to branch.
- Haptics and sound are NOT motion and are deliberately left alone by that
  preference. Suppressing animation is not a request to lose confirmation that
  a tap landed; the sound opt-out is a separate, user-facing setting.
- Reward the recording, never the number recorded. The haptic fires on logging
  a meal, not on hitting a calorie target -- the latter rewards eating less
  rather than recording honestly, and corrupts the app's own data.

gatelock stays untouched: Tkinter has no animation framework, so motion there
is marked `n/a (tk)` rather than shipping a dead constant that reads as a
supported feature.

Tests assert the frozen values on both sides, and that the reduced-motion block
collapses every non-zero step -- verified by mutation: deleting one collapse
line fails the suite. flutter analyze / tsc / eslint clean, 68 Dart and 88 TS
tests pass, palette_check and the 250-line cap still exit 0.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-22 17:28:02 +02:00

53 lines
1.5 KiB
JSON

{
"name": "@kuhyx/web-ui",
"version": "0.3.2",
"private": false,
"type": "module",
"description": "The shared token + component layer for kuhy's web apps: the frozen palette, spacing/radius/type scales as CSS custom properties, and the components that were each reimplemented in two or more repos.",
"license": "MIT",
"engines": {
"node": ">=24",
"pnpm": ">=10"
},
"packageManager": "pnpm@10.13.1",
"files": [
"dist"
],
"main": "./dist/index.js",
"types": "./dist/index.d.ts",
"exports": {
".": {
"types": "./dist/index.d.ts",
"default": "./dist/index.js"
},
"./tokens.css": "./dist/tokens.css",
"./range-slider.css": "./dist/range-slider.css"
},
"scripts": {
"build": "tsc -b && cp src/tokens.css src/range-slider.css dist/",
"lint": "tsc --noEmit -p tsconfig.lint.json && eslint .",
"test": "vitest run",
"coverage": "vitest run --coverage"
},
"peerDependencies": {
"react": ">=19"
},
"devDependencies": {
"@eslint/js": "^10.0.1",
"@testing-library/jest-dom": "^6.9.1",
"@testing-library/react": "^16.3.2",
"@testing-library/user-event": "^14.6.1",
"@types/react": "^19.2.17",
"@types/react-dom": "^19.2.3",
"@vitest/coverage-v8": "^4.1.10",
"eslint": "^10.7.0",
"jsdom": "^29.1.1",
"react": "^19.2.7",
"react-dom": "^19.2.7",
"typescript": "^6.0.3",
"typescript-eslint": "^8.64.0",
"vitest": "^4.1.10",
"@types/node": "^26.1.1"
}
}