@anyknown/axis 0.0.0-stage → 0.2.1
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/LICENSE +21 -0
- package/README.md +217 -2
- package/dist/axis/constants.d.ts +12 -0
- package/dist/axis/constants.js +27 -0
- package/dist/axis/create-axis.d.ts +10 -0
- package/dist/axis/create-axis.js +212 -0
- package/dist/axis/create-drag-client.d.ts +6 -0
- package/dist/axis/create-drag-client.js +95 -0
- package/dist/axis/create-geometry.d.ts +2 -0
- package/dist/axis/create-geometry.js +11 -0
- package/dist/axis/create-hold.d.ts +2 -0
- package/dist/axis/create-hold.js +38 -0
- package/dist/axis/create-scroll-driver.d.ts +2 -0
- package/dist/axis/create-scroll-driver.js +139 -0
- package/dist/axis/create-snap-suspension.d.ts +2 -0
- package/dist/axis/create-snap-suspension.js +23 -0
- package/dist/axis/create-style-overrides.d.ts +2 -0
- package/dist/axis/create-style-overrides.js +35 -0
- package/dist/axis/create-wheel.d.ts +5 -0
- package/dist/axis/create-wheel.js +57 -0
- package/dist/axis/drags-along.d.ts +2 -0
- package/dist/axis/drags-along.js +1 -0
- package/dist/axis/index.d.ts +2 -0
- package/dist/axis/index.js +1 -0
- package/dist/axis/merge-options.d.ts +2 -0
- package/dist/axis/merge-options.js +9 -0
- package/dist/axis/next-axis-state.d.ts +2 -0
- package/dist/axis/next-axis-state.js +14 -0
- package/dist/axis/resolve-axis.d.ts +2 -0
- package/dist/axis/resolve-axis.js +8 -0
- package/dist/axis/types.d.ts +146 -0
- package/dist/axis/types.js +1 -0
- package/dist/coordinator/constants.d.ts +5 -0
- package/dist/coordinator/constants.js +5 -0
- package/dist/coordinator/create-coordinator.d.ts +2 -0
- package/dist/coordinator/create-coordinator.js +191 -0
- package/dist/coordinator/index.d.ts +2 -0
- package/dist/coordinator/index.js +1 -0
- package/dist/coordinator/pick-owner.d.ts +3 -0
- package/dist/coordinator/pick-owner.js +7 -0
- package/dist/coordinator/register.d.ts +2 -0
- package/dist/coordinator/register.js +11 -0
- package/dist/coordinator/types.d.ts +24 -0
- package/dist/coordinator/types.js +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1 -0
- package/dist/react/constants.d.ts +3 -0
- package/dist/react/constants.js +8 -0
- package/dist/react/index.d.ts +3 -0
- package/dist/react/index.js +1 -0
- package/dist/react/types.d.ts +12 -0
- package/dist/react/types.js +1 -0
- package/dist/react/use-applied-options.d.ts +3 -0
- package/dist/react/use-applied-options.js +11 -0
- package/dist/react/use-axis-instance.d.ts +3 -0
- package/dist/react/use-axis-instance.js +19 -0
- package/dist/react/use-axis.d.ts +11 -0
- package/dist/react/use-axis.js +14 -0
- package/dist/react/use-isomorphic-layout-effect.d.ts +2 -0
- package/dist/react/use-isomorphic-layout-effect.js +2 -0
- package/dist/react/use-selected-state.d.ts +4 -0
- package/dist/react/use-selected-state.js +14 -0
- package/dist/react/use-stable-api.d.ts +4 -0
- package/dist/react/use-stable-api.js +7 -0
- package/dist/utils/adjacent-snap.d.ts +1 -0
- package/dist/utils/adjacent-snap.js +8 -0
- package/dist/utils/cap-velocity.d.ts +2 -0
- package/dist/utils/cap-velocity.js +6 -0
- package/dist/utils/clamp.d.ts +1 -0
- package/dist/utils/clamp.js +1 -0
- package/dist/utils/composed-path-matches.d.ts +1 -0
- package/dist/utils/composed-path-matches.js +9 -0
- package/dist/utils/constants.d.ts +9 -0
- package/dist/utils/constants.js +19 -0
- package/dist/utils/css-length-to-px.d.ts +1 -0
- package/dist/utils/css-length-to-px.js +6 -0
- package/dist/utils/dominant-axis.d.ts +2 -0
- package/dist/utils/dominant-axis.js +3 -0
- package/dist/utils/ease-out-cubic.d.ts +1 -0
- package/dist/utils/ease-out-cubic.js +1 -0
- package/dist/utils/glide-duration.d.ts +1 -0
- package/dist/utils/glide-duration.js +9 -0
- package/dist/utils/index.d.ts +28 -0
- package/dist/utils/index.js +27 -0
- package/dist/utils/is-inside-editable.d.ts +1 -0
- package/dist/utils/is-inside-editable.js +2 -0
- package/dist/utils/is-on-scrollbar.d.ts +1 -0
- package/dist/utils/is-on-scrollbar.js +6 -0
- package/dist/utils/is-rtl.d.ts +1 -0
- package/dist/utils/is-rtl.js +1 -0
- package/dist/utils/is-scroll-key.d.ts +1 -0
- package/dist/utils/is-scroll-key.js +7 -0
- package/dist/utils/max-scroll.d.ts +2 -0
- package/dist/utils/max-scroll.js +4 -0
- package/dist/utils/measure-snaps.d.ts +1 -0
- package/dist/utils/measure-snaps.js +31 -0
- package/dist/utils/momentum-distance.d.ts +1 -0
- package/dist/utils/momentum-distance.js +4 -0
- package/dist/utils/momentum-step.d.ts +4 -0
- package/dist/utils/momentum-step.js +4 -0
- package/dist/utils/nearest-snap.d.ts +1 -0
- package/dist/utils/nearest-snap.js +12 -0
- package/dist/utils/parse-snap-align.d.ts +5 -0
- package/dist/utils/parse-snap-align.js +5 -0
- package/dist/utils/parse-snap-type.d.ts +4 -0
- package/dist/utils/parse-snap-type.js +7 -0
- package/dist/utils/pointer-sample.d.ts +2 -0
- package/dist/utils/pointer-sample.js +5 -0
- package/dist/utils/prefers-reduced-motion.d.ts +1 -0
- package/dist/utils/prefers-reduced-motion.js +1 -0
- package/dist/utils/read-scroll.d.ts +2 -0
- package/dist/utils/read-scroll.js +6 -0
- package/dist/utils/snap-items.d.ts +2 -0
- package/dist/utils/snap-items.js +18 -0
- package/dist/utils/snap-positions.d.ts +2 -0
- package/dist/utils/snap-positions.js +28 -0
- package/dist/utils/supported-user-select.d.ts +1 -0
- package/dist/utils/supported-user-select.js +1 -0
- package/dist/utils/to-logical.d.ts +1 -0
- package/dist/utils/to-logical.js +3 -0
- package/dist/utils/to-physical.d.ts +1 -0
- package/dist/utils/to-physical.js +3 -0
- package/dist/utils/try-capture-pointer.d.ts +1 -0
- package/dist/utils/try-capture-pointer.js +6 -0
- package/dist/utils/try-release-pointer.d.ts +1 -0
- package/dist/utils/try-release-pointer.js +7 -0
- package/dist/utils/types.d.ts +22 -0
- package/dist/utils/types.js +1 -0
- package/dist/utils/velocity-from-samples.d.ts +2 -0
- package/dist/utils/velocity-from-samples.js +21 -0
- package/dist/utils/wheel-delta-y-px.d.ts +1 -0
- package/dist/utils/wheel-delta-y-px.js +5 -0
- package/dist/utils/write-scroll.d.ts +2 -0
- package/dist/utils/write-scroll.js +7 -0
- package/package.json +84 -5
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function measureSnaps(win: Window, el: Element): Record<"x" | "y", number[]>;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { cssLengthToPx } from "./css-length-to-px.js";
|
|
2
|
+
import { maxScroll } from "./max-scroll.js";
|
|
3
|
+
import { snapItems } from "./snap-items.js";
|
|
4
|
+
import { snapPositions } from "./snap-positions.js";
|
|
5
|
+
export function measureSnaps(win, el) {
|
|
6
|
+
const style = win.getComputedStyle(el);
|
|
7
|
+
const rect = el.getBoundingClientRect();
|
|
8
|
+
const max = maxScroll(el);
|
|
9
|
+
const items = snapItems(win, el);
|
|
10
|
+
const padding = (side, basis) => cssLengthToPx(style.getPropertyValue(`scroll-padding-${side}`), basis);
|
|
11
|
+
return {
|
|
12
|
+
x: snapPositions({
|
|
13
|
+
start: rect.left + el.clientLeft,
|
|
14
|
+
size: el.clientWidth,
|
|
15
|
+
paddingStart: padding("left", el.clientWidth),
|
|
16
|
+
paddingEnd: padding("right", el.clientWidth),
|
|
17
|
+
scroll: el.scrollLeft,
|
|
18
|
+
maxScroll: max.x,
|
|
19
|
+
rtl: style.direction === "rtl",
|
|
20
|
+
}, items.x),
|
|
21
|
+
y: snapPositions({
|
|
22
|
+
start: rect.top + el.clientTop,
|
|
23
|
+
size: el.clientHeight,
|
|
24
|
+
paddingStart: padding("top", el.clientHeight),
|
|
25
|
+
paddingEnd: padding("bottom", el.clientHeight),
|
|
26
|
+
scroll: el.scrollTop,
|
|
27
|
+
maxScroll: max.y,
|
|
28
|
+
rtl: false,
|
|
29
|
+
}, items.y),
|
|
30
|
+
};
|
|
31
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function momentumDistance(velocity: number): number;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function nearestSnap(positions: readonly number[], target: number): number;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export function nearestSnap(positions, target) {
|
|
2
|
+
let best = target;
|
|
3
|
+
let bestDistance = Infinity;
|
|
4
|
+
for (const position of positions) {
|
|
5
|
+
const distance = Math.abs(position - target);
|
|
6
|
+
if (distance < bestDistance) {
|
|
7
|
+
best = position;
|
|
8
|
+
bestDistance = distance;
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
return best;
|
|
12
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const prefersReducedMotion: (win: Window) => boolean;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const prefersReducedMotion = (win) => win.matchMedia?.("(prefers-reduced-motion: reduce)").matches ?? false;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { cssLengthToPx } from "./css-length-to-px.js";
|
|
2
|
+
import { parseSnapAlign } from "./parse-snap-align.js";
|
|
3
|
+
export function snapItems(win, el) {
|
|
4
|
+
const items = { x: [], y: [] };
|
|
5
|
+
for (const child of el.children) {
|
|
6
|
+
const childStyle = win.getComputedStyle(child);
|
|
7
|
+
const align = parseSnapAlign(childStyle.scrollSnapAlign);
|
|
8
|
+
if (align.x === "none" && align.y === "none")
|
|
9
|
+
continue;
|
|
10
|
+
const box = child.getBoundingClientRect();
|
|
11
|
+
const margin = (side) => cssLengthToPx(childStyle.getPropertyValue(`scroll-margin-${side}`), 0);
|
|
12
|
+
const left = margin("left");
|
|
13
|
+
const top = margin("top");
|
|
14
|
+
items.x.push({ start: box.left - left, size: box.width + left + margin("right"), align: align.x });
|
|
15
|
+
items.y.push({ start: box.top - top, size: box.height + top + margin("bottom"), align: align.y });
|
|
16
|
+
}
|
|
17
|
+
return items;
|
|
18
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { clamp } from "./clamp.js";
|
|
2
|
+
import { toLogical } from "./to-logical.js";
|
|
3
|
+
export function snapPositions(axis, items) {
|
|
4
|
+
const { rtl } = axis;
|
|
5
|
+
const portLow = axis.start + axis.paddingStart;
|
|
6
|
+
const portHigh = axis.start + axis.size - axis.paddingEnd;
|
|
7
|
+
const positions = [];
|
|
8
|
+
for (const item of items) {
|
|
9
|
+
if (item.align === "none")
|
|
10
|
+
continue;
|
|
11
|
+
const high = item.start + item.size;
|
|
12
|
+
const alignsLowEdge = (item.align === "start") !== rtl;
|
|
13
|
+
const delta = item.align === "center"
|
|
14
|
+
? (item.start + high) / 2 - (portLow + portHigh) / 2
|
|
15
|
+
: alignsLowEdge
|
|
16
|
+
? item.start - portLow
|
|
17
|
+
: high - portHigh;
|
|
18
|
+
positions.push(clamp(toLogical(axis.scroll + delta, rtl), 0, axis.maxScroll));
|
|
19
|
+
}
|
|
20
|
+
positions.sort((a, b) => a - b);
|
|
21
|
+
const unique = [];
|
|
22
|
+
for (const position of positions) {
|
|
23
|
+
const previous = unique.at(-1);
|
|
24
|
+
if (previous === undefined || position - previous > 1)
|
|
25
|
+
unique.push(position);
|
|
26
|
+
}
|
|
27
|
+
return unique;
|
|
28
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const supportedUserSelect: (style: CSSStyleDeclaration) => "user-select" | "-webkit-user-select";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const supportedUserSelect = (style) => "userSelect" in style ? "user-select" : "-webkit-user-select";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function toLogical(scrollLeft: number, rtl: boolean): number;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function toPhysical(logical: number, rtl: boolean): number;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function tryCapturePointer(el: Element, pointerId: number): void;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function tryReleasePointer(el: Element, pointerId: number): void;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export interface Vector {
|
|
2
|
+
x: number;
|
|
3
|
+
y: number;
|
|
4
|
+
}
|
|
5
|
+
export interface Sample extends Vector {
|
|
6
|
+
t: number;
|
|
7
|
+
}
|
|
8
|
+
export type SnapAlign = "start" | "center" | "end" | "none";
|
|
9
|
+
export interface SnapAxis {
|
|
10
|
+
start: number;
|
|
11
|
+
size: number;
|
|
12
|
+
paddingStart: number;
|
|
13
|
+
paddingEnd: number;
|
|
14
|
+
scroll: number;
|
|
15
|
+
maxScroll: number;
|
|
16
|
+
rtl: boolean;
|
|
17
|
+
}
|
|
18
|
+
export interface SnapItem {
|
|
19
|
+
start: number;
|
|
20
|
+
size: number;
|
|
21
|
+
align: SnapAlign;
|
|
22
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { clamp } from "./clamp.js";
|
|
2
|
+
import { MAX_VELOCITY, VELOCITY_WINDOW } from "./constants.js";
|
|
3
|
+
export function velocityFromSamples(samples, window = VELOCITY_WINDOW) {
|
|
4
|
+
const last = samples.at(-1);
|
|
5
|
+
if (!last)
|
|
6
|
+
return { x: 0, y: 0 };
|
|
7
|
+
let first = last;
|
|
8
|
+
for (let i = samples.length - 2; i >= 0; i--) {
|
|
9
|
+
const sample = samples[i];
|
|
10
|
+
if (last.t - sample.t > window)
|
|
11
|
+
break;
|
|
12
|
+
first = sample;
|
|
13
|
+
}
|
|
14
|
+
const dt = last.t - first.t;
|
|
15
|
+
if (dt <= 0)
|
|
16
|
+
return { x: 0, y: 0 };
|
|
17
|
+
return {
|
|
18
|
+
x: clamp((last.x - first.x) / dt, -MAX_VELOCITY, MAX_VELOCITY),
|
|
19
|
+
y: clamp((last.y - first.y) / dt, -MAX_VELOCITY, MAX_VELOCITY),
|
|
20
|
+
};
|
|
21
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function wheelDeltaYPx(event: WheelEvent, pagePx: number): number;
|
package/package.json
CHANGED
|
@@ -1,6 +1,85 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
2
|
+
"name": "@anyknown/axis",
|
|
3
|
+
"version": "0.2.1",
|
|
4
|
+
"description": "Headless scroll primitive for x, y and 2D panning: native scroll first, mouse drag as an enhancement",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"carousel",
|
|
7
|
+
"drag-scroll",
|
|
8
|
+
"headless",
|
|
9
|
+
"kanban",
|
|
10
|
+
"pan",
|
|
11
|
+
"react",
|
|
12
|
+
"scroll",
|
|
13
|
+
"scroll-snap"
|
|
14
|
+
],
|
|
15
|
+
"bugs": {
|
|
16
|
+
"url": "https://github.com/anyknown-com/axis/issues"
|
|
17
|
+
},
|
|
18
|
+
"license": "MIT",
|
|
19
|
+
"repository": {
|
|
20
|
+
"type": "git",
|
|
21
|
+
"url": "git+https://github.com/anyknown-com/axis.git"
|
|
22
|
+
},
|
|
23
|
+
"files": [
|
|
24
|
+
"dist",
|
|
25
|
+
"LICENSE"
|
|
26
|
+
],
|
|
27
|
+
"type": "module",
|
|
28
|
+
"sideEffects": false,
|
|
29
|
+
"types": "./dist/index.d.ts",
|
|
30
|
+
"typesVersions": {
|
|
31
|
+
"*": {
|
|
32
|
+
"react": [
|
|
33
|
+
"./dist/react/index.d.ts"
|
|
34
|
+
]
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
"exports": {
|
|
38
|
+
".": {
|
|
39
|
+
"types": "./dist/index.d.ts",
|
|
40
|
+
"default": "./dist/index.js"
|
|
41
|
+
},
|
|
42
|
+
"./react": {
|
|
43
|
+
"types": "./dist/react/index.d.ts",
|
|
44
|
+
"default": "./dist/react/index.js"
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
"publishConfig": {
|
|
48
|
+
"access": "public"
|
|
49
|
+
},
|
|
50
|
+
"scripts": {
|
|
51
|
+
"build": "rm -rf dist && tsc -p tsconfig.build.json && node scripts/esm-extensions.mjs",
|
|
52
|
+
"typecheck": "tsc --noEmit",
|
|
53
|
+
"lint": "oxlint --deny-warnings src test playground scripts vitest.config.ts",
|
|
54
|
+
"fmt": "oxfmt",
|
|
55
|
+
"fmt:check": "oxfmt --check",
|
|
56
|
+
"check": "pnpm typecheck && pnpm lint && pnpm fmt:check",
|
|
57
|
+
"test": "vitest run",
|
|
58
|
+
"dev": "vite --config playground/vite.config.ts",
|
|
59
|
+
"prepublishOnly": "pnpm check && pnpm test && pnpm build"
|
|
60
|
+
},
|
|
61
|
+
"devDependencies": {
|
|
62
|
+
"@stylistic/eslint-plugin": "5.10.0",
|
|
63
|
+
"@types/node": "^26.4.0",
|
|
64
|
+
"@types/react": "^19.2.0",
|
|
65
|
+
"@types/react-dom": "^19.2.5",
|
|
66
|
+
"@vitest/browser-playwright": "^4.1.11",
|
|
67
|
+
"oxfmt": "^0.65.0",
|
|
68
|
+
"oxlint": "^1.80.0",
|
|
69
|
+
"playwright": "^1.55.0",
|
|
70
|
+
"react": "^19.2.8",
|
|
71
|
+
"react-dom": "^19.2.8",
|
|
72
|
+
"typescript": "^5.9.0",
|
|
73
|
+
"vite": "^8.2.2",
|
|
74
|
+
"vitest": "^4.1.11"
|
|
75
|
+
},
|
|
76
|
+
"peerDependencies": {
|
|
77
|
+
"react": "^18.0.0 || ^19.0.0"
|
|
78
|
+
},
|
|
79
|
+
"peerDependenciesMeta": {
|
|
80
|
+
"react": {
|
|
81
|
+
"optional": true
|
|
82
|
+
}
|
|
83
|
+
},
|
|
84
|
+
"packageManager": "pnpm@10.30.3"
|
|
85
|
+
}
|