@kolkrabbi/kol-component 0.121.0 → 0.122.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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kolkrabbi/kol-component",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.122.0",
|
|
4
4
|
"description": "KOL design-system components — atoms through organisms, emitting canonical kol-* classes. Pairs with @kolkrabbi/kol-theme for styling.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
"./utilities/markdownToHtml": "./src/utilities/markdownToHtml.js",
|
|
18
18
|
"./utilities/mediaKinds": "./src/utilities/mediaKinds.js",
|
|
19
19
|
"./utilities/ratios": "./src/utilities/ratios.js",
|
|
20
|
+
"./utilities/motion": "./src/utilities/motion.js",
|
|
20
21
|
"./hooks/*": "./src/hooks/*.js"
|
|
21
22
|
},
|
|
22
23
|
"dependencies": {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { useRef, useState, useEffect, useLayoutEffect } from 'react'
|
|
2
|
+
import { DURATION } from '../utilities/motion.js'
|
|
2
3
|
import gsap from 'gsap'
|
|
3
4
|
import { Icon } from '@kolkrabbi/kol-icons'
|
|
4
5
|
import { glyphSize } from '../hooks/glyphLadders.js'
|
|
@@ -73,7 +74,7 @@ const HOUSE_EASE = [0.4, 0, 0.2, 1]
|
|
|
73
74
|
* not a mode. The release then plays the full bounce out. */
|
|
74
75
|
const PRESS_HOLD = 1600
|
|
75
76
|
|
|
76
|
-
const SWAP_MS = 500
|
|
77
|
+
const SWAP_MS = DURATION.spring /* the house 500 (utilities/motion.js) */
|
|
77
78
|
|
|
78
79
|
const CHROME = {
|
|
79
80
|
copy: 'kol-copy-btn',
|
package/src/atoms/ViewToggle.jsx
CHANGED
|
@@ -73,8 +73,12 @@ const ViewToggle = ({
|
|
|
73
73
|
)
|
|
74
74
|
}
|
|
75
75
|
|
|
76
|
+
/* THE WELL IS INSET (ViewToggleWellGap, kol-website 2026-08-28): `p-1` put the box 4px past the
|
|
77
|
+
* last chip on every side, so a row's `gap-4` read 20 on this side and 16 on the other, and every
|
|
78
|
+
* consumer subtracted it with a `-ml-1` on the neighbour. `-mx-1` draws the padding inward from the
|
|
79
|
+
* declared box — the chips sit where the box says, the well bleeds 4px into the gap. */
|
|
76
80
|
const containerClasses = isIconVariant
|
|
77
|
-
? `kol-view-toggle inline-flex items-center gap-1 p-1 bg-surface-secondary rounded ${toneClass(tone)} ${className}`.replace(/\s+/g, ' ').trim()
|
|
81
|
+
? `kol-view-toggle inline-flex items-center gap-1 p-1 -mx-1 bg-surface-secondary rounded ${toneClass(tone)} ${className}`.replace(/\s+/g, ' ').trim()
|
|
78
82
|
: `flex gap-2 ${className}`
|
|
79
83
|
|
|
80
84
|
const buttonClasses = (isActive) => {
|
package/src/hooks/useTilt.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { useRef } from 'react'
|
|
2
2
|
import { useMotionValue, useSpring, useTransform } from 'framer-motion'
|
|
3
|
+
import { SPRING } from '../utilities/motion.js'
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
6
|
* Pointer-driven 3D tilt (framer-motion springs) — the ONE tilt hook.
|
|
@@ -12,7 +13,9 @@ import { useMotionValue, useSpring, useTransform } from 'framer-motion'
|
|
|
12
13
|
* (e.g. TiltCard's `grounded` zone-snapping).
|
|
13
14
|
*
|
|
14
15
|
* Defaults are the design: tilt ±4°, spring 350/35, perspective 700,
|
|
15
|
-
* rest position center (0.5/0.5).
|
|
16
|
+
* rest position center (0.5/0.5). The two spring sets are `SPRING.tilt` and
|
|
17
|
+
* `SPRING.lazy` in `utilities/motion.js` — the JS mirror of kol-animation.css,
|
|
18
|
+
* so a tween elsewhere in the estate cannot drift from this feel (2026-08-28).
|
|
16
19
|
*
|
|
17
20
|
* `grounded` (ShelfCardTiltWrapsCard, kol-website 2026-08-27 — lifted out of
|
|
18
21
|
* TiltCardInner so the shelf and the card share ONE feel, no new component):
|
|
@@ -23,8 +26,8 @@ import { useMotionValue, useSpring, useTransform } from 'framer-motion'
|
|
|
23
26
|
export default function useTilt({
|
|
24
27
|
magnitude = 4,
|
|
25
28
|
perspective = 700,
|
|
26
|
-
stiffness =
|
|
27
|
-
damping =
|
|
29
|
+
stiffness = SPRING.tilt.stiffness,
|
|
30
|
+
damping = SPRING.tilt.damping,
|
|
28
31
|
grounded = false,
|
|
29
32
|
} = {}) {
|
|
30
33
|
const ref = useRef(null)
|
|
@@ -38,7 +41,7 @@ export default function useTilt({
|
|
|
38
41
|
* SELECTED when asked for — a free tilt pays two idle springs, nothing more */
|
|
39
42
|
const zones = 3
|
|
40
43
|
const snap = (v) => Math.round(v * zones) / zones
|
|
41
|
-
const lazy =
|
|
44
|
+
const lazy = SPRING.lazy
|
|
42
45
|
const lazyX = useSpring(useTransform(springX, (v) => Math.min(0, snap(-v / magnitude) * 2.5)), lazy)
|
|
43
46
|
const lazyY = useSpring(useTransform(springY, (v) => snap(v / magnitude) * 2.5), lazy)
|
|
44
47
|
const rotateX = grounded ? lazyX : springX
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* motion.js — the JS side of the motion sheet (user ruling 2026-08-28:
|
|
3
|
+
* "localise animation to its own css … and use it to localise all the gsap
|
|
4
|
+
* framer shit we are doing").
|
|
5
|
+
*
|
|
6
|
+
* kol-theme's `kol-animation.css` is where the estate's CSS motion lives. This
|
|
7
|
+
* is its mirror for the motion CSS cannot express — a gsap tween, a framer
|
|
8
|
+
* spring — so a hand-typed `duration: 0.5, ease: "power3.out"` in some
|
|
9
|
+
* component is not a second, private vocabulary. Same numbers, one import.
|
|
10
|
+
*
|
|
11
|
+
* NOT here: a domain's own physics — the foundry's pressure damping, the
|
|
12
|
+
* marquee's px/s, a scroll-scrub timeline. Those are content, not chrome, and
|
|
13
|
+
* flattening them into house constants would say they are interchangeable.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
/* The house curves. `HOUSE` is `--kol-ease-house` as framer takes it (a
|
|
17
|
+
* cubic-bezier array); the gsap column is the nearest named equivalent, so a
|
|
18
|
+
* tween and a transition on the same element do not disagree. */
|
|
19
|
+
export const EASE = {
|
|
20
|
+
house: [0.4, 0, 0.2, 1],
|
|
21
|
+
houseGsap: 'power2.inOut',
|
|
22
|
+
bounce: [0.34, 1.56, 0.64, 1],
|
|
23
|
+
/* symmetric in-out — an ease-out pops the first 20 % and crawls the rest,
|
|
24
|
+
* which reads as a jerk on a long fade (user, on the rail pill 2026-08-28) */
|
|
25
|
+
longFade: [0.45, 0, 0.55, 1],
|
|
26
|
+
outGsap: 'power3.out',
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/* Milliseconds, mirroring `--kol-transition-*` in kol-design-tokens.css.
|
|
30
|
+
* `s()` because gsap counts in seconds and framer in seconds — the CSS side is
|
|
31
|
+
* the source, so the conversion lives here rather than at each call site. */
|
|
32
|
+
export const DURATION = { fast: 150, base: 200, slow: 300, spring: 500, zoom: 600 }
|
|
33
|
+
export const s = (ms) => ms / 1000
|
|
34
|
+
|
|
35
|
+
/* framer springs. `tilt` is the Tilt family's feel; `lazy` is the grounded
|
|
36
|
+
* chase (heavier, slower to settle) — the two the hook already had inline. */
|
|
37
|
+
export const SPRING = {
|
|
38
|
+
tilt: { stiffness: 350, damping: 35 },
|
|
39
|
+
lazy: { stiffness: 250, damping: 25, mass: 0.6 },
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/* THE RAIL'S GRAB EDGE (RailFlatGrabOpen, kol-mirror 2026-08-28 — kol-r2b2's
|
|
43
|
+
* pill). The chrome is `.kol-rail-grab` in kol-animation.css; these are the
|
|
44
|
+
* numbers JS owns, because they are pointer behaviour, not paint:
|
|
45
|
+
*
|
|
46
|
+
* near / sleep the pill wakes within 20px of the line and sleeps only past
|
|
47
|
+
* 40 — hovering the line itself flapped the class every frame
|
|
48
|
+
* and restarted the fade, so the hysteresis is not optional
|
|
49
|
+
* marks it rests on 20/40/60/80 % of the rail's height and is STICKY:
|
|
50
|
+
* it leaves a mark only within `stick` of the pitch to another
|
|
51
|
+
* (user: "following the mouse a little too much"). The middle
|
|
52
|
+
* of each gap is dead on purpose
|
|
53
|
+
* travel a long chase, so the pill trails the pointer and catches up
|
|
54
|
+
* snap the width tween on release
|
|
55
|
+
* slop under this, a pointerdown/up is a CLICK, not a drag
|
|
56
|
+
*/
|
|
57
|
+
export const GRAB = {
|
|
58
|
+
near: 20,
|
|
59
|
+
sleep: 40,
|
|
60
|
+
marks: [0.2, 0.4, 0.6, 0.8],
|
|
61
|
+
stick: 0.2 * 0.3,
|
|
62
|
+
travel: { duration: 2.8, ease: EASE.outGsap },
|
|
63
|
+
snap: { duration: 0.5, ease: EASE.outGsap },
|
|
64
|
+
slop: 3,
|
|
65
|
+
}
|