@enigmax/primitives 0.10.0 → 0.11.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/dist/{chunk-L4KA342C.js → chunk-KTW4GO43.js} +3 -2
- package/dist/next/index.js +2 -2
- package/dist/react/index.d.ts +11 -1
- package/dist/react/index.js +1 -1
- package/dist/react-router/index.d.ts +9 -0
- package/dist/react-router/index.js +16 -0
- package/package.json +12 -3
- package/src/react/button.tsx +13 -1
- package/src/react/use-button.ts +4 -2
- package/src/react-router/index.tsx +40 -0
|
@@ -172,7 +172,7 @@ function useButton(options = {}) {
|
|
|
172
172
|
event.preventDefault();
|
|
173
173
|
return;
|
|
174
174
|
}
|
|
175
|
-
void instance.press();
|
|
175
|
+
void instance.press(event);
|
|
176
176
|
},
|
|
177
177
|
"aria-disabled": !state.available,
|
|
178
178
|
"aria-busy": state.loading,
|
|
@@ -202,11 +202,12 @@ var Button = forwardRef(function Button2({
|
|
|
202
202
|
cooldown,
|
|
203
203
|
shortcut,
|
|
204
204
|
onPress,
|
|
205
|
+
onClick,
|
|
205
206
|
onChange,
|
|
206
207
|
type = "button",
|
|
207
208
|
...rest
|
|
208
209
|
}, ref) {
|
|
209
|
-
const button = useButton({ href, disabled, loading, cooldown, shortcut, onPress, onChange });
|
|
210
|
+
const button = useButton({ href, disabled, loading, cooldown, shortcut, onPress: onPress ?? onClick, onChange });
|
|
210
211
|
const state = button;
|
|
211
212
|
const Tag = as ?? (state.element === "a" ? getLinkComponent() : "button");
|
|
212
213
|
const native = Tag === "button" ? { type } : {};
|
package/dist/next/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { Button } from '../chunk-
|
|
3
|
-
export { Input, PasswordStrength, getLinkComponent, setLinkComponent, useButton, useInput, useMarquee, useSearch } from '../chunk-
|
|
2
|
+
import { Button } from '../chunk-KTW4GO43.js';
|
|
3
|
+
export { Input, PasswordStrength, getLinkComponent, setLinkComponent, useButton, useInput, useMarquee, useSearch } from '../chunk-KTW4GO43.js';
|
|
4
4
|
export { estimatePasswordStrength, generatePassword } from '../chunk-42Y7OOJM.js';
|
|
5
5
|
import '../chunk-UZFEEFMF.js';
|
|
6
6
|
import Link from 'next/link';
|
package/dist/react/index.d.ts
CHANGED
|
@@ -18,6 +18,16 @@ export { F as FuseConstructor } from '../search-CsO3L1Lw.js';
|
|
|
18
18
|
* ordinary one means writing the same six lines at every call site, which is how they drift.
|
|
19
19
|
*/
|
|
20
20
|
interface ButtonProps extends ButtonOptions, Omit<ComponentPropsWithoutRef<"button">, "onClick" | "onChange" | "children" | "type"> {
|
|
21
|
+
/**
|
|
22
|
+
* What to run when it is pressed. The same thing as `onPress`, under the name React
|
|
23
|
+
* already uses - write whichever reads better.
|
|
24
|
+
*
|
|
25
|
+
* It is an ALIAS, not a second handler: the component owns the element's real onClick,
|
|
26
|
+
* because that is where a press is refused while the button is loading, disabled or
|
|
27
|
+
* cooling down. Passing one through would replace that and silently take the behaviour
|
|
28
|
+
* with it. Returning a promise drives `loading` for its duration, same as `onPress`.
|
|
29
|
+
*/
|
|
30
|
+
onClick?: ButtonOptions["onPress"];
|
|
21
31
|
/**
|
|
22
32
|
* Override what to render. You rarely need it: an href already renders whatever
|
|
23
33
|
* `setLinkComponent` registered - your router's Link - and a button otherwise.
|
|
@@ -133,7 +143,7 @@ declare function useSearch<T>(options?: SearchOptions<T>): UseSearchResult<T>;
|
|
|
133
143
|
interface UseButtonResult extends ButtonState {
|
|
134
144
|
/** Spread onto the element named by `element`. */
|
|
135
145
|
props: {
|
|
136
|
-
onClick: (event: {
|
|
146
|
+
onClick: (event: Event | {
|
|
137
147
|
preventDefault(): void;
|
|
138
148
|
}) => void;
|
|
139
149
|
"aria-disabled": boolean;
|
package/dist/react/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
export { Button, Input, PasswordStrength, getLinkComponent, setLinkComponent, useButton, useInput, useMarquee, useSearch } from '../chunk-
|
|
2
|
+
export { Button, Input, PasswordStrength, getLinkComponent, setLinkComponent, useButton, useInput, useMarquee, useSearch } from '../chunk-KTW4GO43.js';
|
|
3
3
|
export { estimatePasswordStrength, generatePassword } from '../chunk-42Y7OOJM.js';
|
|
4
4
|
import '../chunk-UZFEEFMF.js';
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import * as react from 'react';
|
|
2
|
+
import { ButtonProps } from '../react/index.js';
|
|
3
|
+
export { BreachChecker, BreachState, BreachStatus, FieldAction, Input, InputProps, PasswordStrength, PasswordStrengthProps, UseButtonResult, UseInputResult, UseMarqueeResult, UseSearchResult, getLinkComponent, setLinkComponent, useButton, useInput, useMarquee, useSearch } from '../react/index.js';
|
|
4
|
+
export { ButtonOptions, ButtonState, EstimateOptions, GeneratePasswordOptions, InputAction, InputIcon, InputOptions, MarqueeHover, MarqueeInstance, MarqueeOptions, PasswordScore, PasswordStrengthReport, estimatePasswordStrength, generatePassword } from '../index.js';
|
|
5
|
+
export { F as FuseConstructor, b as SearchMatch, c as SearchOptions } from '../search-CsO3L1Lw.js';
|
|
6
|
+
|
|
7
|
+
declare const Button: react.ForwardRefExoticComponent<ButtonProps & react.RefAttributes<HTMLElement>>;
|
|
8
|
+
|
|
9
|
+
export { Button, ButtonProps };
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { Button } from '../chunk-KTW4GO43.js';
|
|
3
|
+
export { Input, PasswordStrength, getLinkComponent, setLinkComponent, useButton, useInput, useMarquee, useSearch } from '../chunk-KTW4GO43.js';
|
|
4
|
+
export { estimatePasswordStrength, generatePassword } from '../chunk-42Y7OOJM.js';
|
|
5
|
+
import '../chunk-UZFEEFMF.js';
|
|
6
|
+
import { Link } from 'react-router';
|
|
7
|
+
import { forwardRef, createElement } from 'react';
|
|
8
|
+
|
|
9
|
+
var RouterLink = forwardRef(function RouterLink2({ href = "", ...props }, ref) {
|
|
10
|
+
return createElement(Link, { ...props, to: href, ref });
|
|
11
|
+
});
|
|
12
|
+
var Button2 = forwardRef(function Button3(props, ref) {
|
|
13
|
+
return createElement(Button, { ...props, as: props.as ?? (props.href ? RouterLink : void 0), ref });
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
export { Button2 as Button };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@enigmax/primitives",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.11.1",
|
|
4
4
|
"description": "Headless interaction primitives: the behaviour, the timing and the accessibility of components like a draggable infinite marquee, with no styles of their own. Framework-agnostic core plus thin adapters.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -22,13 +22,17 @@
|
|
|
22
22
|
"./next": {
|
|
23
23
|
"types": "./dist/next/index.d.ts",
|
|
24
24
|
"import": "./dist/next/index.js"
|
|
25
|
+
},
|
|
26
|
+
"./react-router": {
|
|
27
|
+
"types": "./dist/react-router/index.d.ts",
|
|
28
|
+
"import": "./dist/react-router/index.js"
|
|
25
29
|
}
|
|
26
30
|
},
|
|
27
31
|
"scripts": {
|
|
28
32
|
"build": "tsup",
|
|
29
33
|
"typecheck": "tsc --noEmit",
|
|
30
34
|
"test": "npm run test:fixtures && playwright test",
|
|
31
|
-
"test:fixtures": "esbuild test/fixture/react.tsx --bundle --format=esm --jsx=automatic --outfile=test/fixture/build/react.js --tsconfig=tsconfig.json --alias:next/link=./test/fixture/next-link-stub.tsx",
|
|
35
|
+
"test:fixtures": "esbuild test/fixture/react.tsx --bundle --format=esm --jsx=automatic --outfile=test/fixture/build/react.js --tsconfig=tsconfig.json --alias:next/link=./test/fixture/next-link-stub.tsx --alias:react-router=./test/fixture/react-router-stub.tsx",
|
|
32
36
|
"test:install": "playwright install chromium",
|
|
33
37
|
"prepublishOnly": "npm run typecheck && npm run build"
|
|
34
38
|
},
|
|
@@ -42,8 +46,9 @@
|
|
|
42
46
|
],
|
|
43
47
|
"peerDependencies": {
|
|
44
48
|
"fuse.js": ">=6",
|
|
49
|
+
"next": ">=13",
|
|
45
50
|
"react": ">=18",
|
|
46
|
-
"
|
|
51
|
+
"react-router": ">=7"
|
|
47
52
|
},
|
|
48
53
|
"peerDependenciesMeta": {
|
|
49
54
|
"react": {
|
|
@@ -54,6 +59,9 @@
|
|
|
54
59
|
},
|
|
55
60
|
"next": {
|
|
56
61
|
"optional": true
|
|
62
|
+
},
|
|
63
|
+
"react-router": {
|
|
64
|
+
"optional": true
|
|
57
65
|
}
|
|
58
66
|
},
|
|
59
67
|
"devDependencies": {
|
|
@@ -64,6 +72,7 @@
|
|
|
64
72
|
"next": "^15.5.23",
|
|
65
73
|
"react": "^19.2.0",
|
|
66
74
|
"react-dom": "^19.2.8",
|
|
75
|
+
"react-router": "^7.18.2",
|
|
67
76
|
"tsup": "^8.0.0",
|
|
68
77
|
"typescript": "^5.0.0"
|
|
69
78
|
},
|
package/src/react/button.tsx
CHANGED
|
@@ -20,7 +20,18 @@ import { createElement, forwardRef, type ComponentPropsWithoutRef, type ElementT
|
|
|
20
20
|
|
|
21
21
|
// `onChange` is omitted from the DOM side because the primitive's own onChange - which
|
|
22
22
|
// reports the button's state - would otherwise clash with the form event of the same name.
|
|
23
|
+
// `onClick` is omitted and re-declared below, as an alias rather than a second handler.
|
|
23
24
|
export interface ButtonProps extends ButtonOptions, Omit<ComponentPropsWithoutRef<"button">, "onClick" | "onChange" | "children" | "type"> {
|
|
25
|
+
/**
|
|
26
|
+
* What to run when it is pressed. The same thing as `onPress`, under the name React
|
|
27
|
+
* already uses - write whichever reads better.
|
|
28
|
+
*
|
|
29
|
+
* It is an ALIAS, not a second handler: the component owns the element's real onClick,
|
|
30
|
+
* because that is where a press is refused while the button is loading, disabled or
|
|
31
|
+
* cooling down. Passing one through would replace that and silently take the behaviour
|
|
32
|
+
* with it. Returning a promise drives `loading` for its duration, same as `onPress`.
|
|
33
|
+
*/
|
|
34
|
+
onClick?: ButtonOptions["onPress"];
|
|
24
35
|
/**
|
|
25
36
|
* Override what to render. You rarely need it: an href already renders whatever
|
|
26
37
|
* `setLinkComponent` registered - your router's Link - and a button otherwise.
|
|
@@ -52,11 +63,12 @@ export const Button = forwardRef<HTMLElement, ButtonProps>(function Button({
|
|
|
52
63
|
cooldown,
|
|
53
64
|
shortcut,
|
|
54
65
|
onPress,
|
|
66
|
+
onClick,
|
|
55
67
|
onChange,
|
|
56
68
|
type = "button",
|
|
57
69
|
...rest
|
|
58
70
|
}, ref) {
|
|
59
|
-
const button = useButton({ href, disabled, loading, cooldown, shortcut, onPress, onChange });
|
|
71
|
+
const button = useButton({ href, disabled, loading, cooldown, shortcut, onPress: onPress ?? onClick, onChange });
|
|
60
72
|
const state: ButtonState = button;
|
|
61
73
|
|
|
62
74
|
// An href renders the registered link - next/link, react-router's, whatever was passed
|
package/src/react/use-button.ts
CHANGED
|
@@ -4,7 +4,7 @@ import { createButton, type ButtonOptions, type ButtonState } from "@/core/butto
|
|
|
4
4
|
export interface UseButtonResult extends ButtonState {
|
|
5
5
|
/** Spread onto the element named by `element`. */
|
|
6
6
|
props: {
|
|
7
|
-
onClick: (event: { preventDefault(): void; }) => void;
|
|
7
|
+
onClick: (event: Event | { preventDefault(): void; }) => void;
|
|
8
8
|
"aria-disabled": boolean;
|
|
9
9
|
"aria-busy": boolean;
|
|
10
10
|
"data-loading"?: "";
|
|
@@ -76,7 +76,9 @@ export function useButton(options: ButtonOptions = {}): UseButtonResult {
|
|
|
76
76
|
// An unavailable link still receives clicks - aria-disabled is advisory -
|
|
77
77
|
// so the press is refused here rather than relying on the attribute.
|
|
78
78
|
if (!state.available) { event.preventDefault(); return; }
|
|
79
|
-
|
|
79
|
+
// Passed through: a handler that wants to stop propagation or read the
|
|
80
|
+
// target had no way to get at it while press() was called bare.
|
|
81
|
+
void instance.press(event as Event);
|
|
80
82
|
},
|
|
81
83
|
"aria-disabled": !state.available,
|
|
82
84
|
"aria-busy": state.loading,
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { Link } from "react-router";
|
|
4
|
+
import { forwardRef, createElement } from "react";
|
|
5
|
+
import { Button as BaseButton, type ButtonProps } from "@/react/button";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* The React Router entry. Same components, wired to its `Link`.
|
|
9
|
+
*
|
|
10
|
+
* ```tsx
|
|
11
|
+
* import { Button } from "@enigmax/primitives/react-router";
|
|
12
|
+
*
|
|
13
|
+
* <Button href="/settings">Settings</Button> // client navigation
|
|
14
|
+
* ```
|
|
15
|
+
*
|
|
16
|
+
* Same deal as the Next entry: the import path is the configuration, and a subpath is only
|
|
17
|
+
* ever resolved by a project that HAS the router - which is what lets a framework-agnostic
|
|
18
|
+
* package reference one at all.
|
|
19
|
+
*
|
|
20
|
+
* React Router names its target `to`, not `href`, so the prop is translated below. That
|
|
21
|
+
* translation is the whole reason this is a file rather than a line in the docs.
|
|
22
|
+
*
|
|
23
|
+
* React Aria solves the same problem the other way, with a `RouterProvider` taking the
|
|
24
|
+
* router's `navigate` (react-spectrum.adobe.com/react-aria/routing.html). One mechanism
|
|
25
|
+
* covers every router and it always renders a real anchor, but it is still a line of setup
|
|
26
|
+
* in the app. `setLinkComponent` is this package's version of that, for a router with no
|
|
27
|
+
* entry of its own here.
|
|
28
|
+
*/
|
|
29
|
+
|
|
30
|
+
/** Bridges the two names, so a call site writes `href` whatever the router underneath is. */
|
|
31
|
+
const RouterLink = forwardRef<HTMLAnchorElement, { href?: string; }>(function RouterLink({ href = "", ...props }, ref) {
|
|
32
|
+
return createElement(Link, { ...props, to: href, ref });
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
export const Button = forwardRef<HTMLElement, ButtonProps>(function Button(props, ref) {
|
|
36
|
+
// Only an href makes it a link; a plain button must not be handed a router component.
|
|
37
|
+
return createElement(BaseButton, { ...props, as: props.as ?? (props.href ? RouterLink : undefined), ref });
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
export * from "@/react/index";
|