@enigmax/primitives 0.8.0 → 0.9.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/dist/react/index.d.ts +8 -7
- package/dist/react/index.js +11 -2
- package/package.json +1 -1
- package/registry.json +10 -1
- package/src/react/button.tsx +8 -9
- package/src/react/index.ts +1 -0
- package/src/react/link.ts +45 -0
package/dist/react/index.d.ts
CHANGED
|
@@ -143,12 +143,8 @@ declare function useButton(options?: ButtonOptions): UseButtonResult;
|
|
|
143
143
|
*/
|
|
144
144
|
interface ButtonProps extends ButtonOptions, Omit<ComponentPropsWithoutRef<"button">, "onClick" | "onChange" | "children" | "type"> {
|
|
145
145
|
/**
|
|
146
|
-
*
|
|
147
|
-
*
|
|
148
|
-
*
|
|
149
|
-
* ```tsx
|
|
150
|
-
* <Button as={Link} href="/settings">Settings</Button>
|
|
151
|
-
* ```
|
|
146
|
+
* Override what to render. You rarely need it: an href already renders whatever
|
|
147
|
+
* `setLinkComponent` registered - your router's Link - and a button otherwise.
|
|
152
148
|
*/
|
|
153
149
|
as?: ElementType;
|
|
154
150
|
/**
|
|
@@ -168,6 +164,11 @@ interface ButtonProps extends ButtonOptions, Omit<ComponentPropsWithoutRef<"butt
|
|
|
168
164
|
}
|
|
169
165
|
declare const Button: react.ForwardRefExoticComponent<ButtonProps & react.RefAttributes<HTMLElement>>;
|
|
170
166
|
|
|
167
|
+
/** Register the router's link. Pass null to go back to a plain anchor. */
|
|
168
|
+
declare function setLinkComponent(component: ElementType | null): void;
|
|
169
|
+
/** What an href should render as right now. */
|
|
170
|
+
declare function getLinkComponent(): ElementType;
|
|
171
|
+
|
|
171
172
|
/** An extra button inside the field. The built-ins are the same shape. */
|
|
172
173
|
interface FieldAction {
|
|
173
174
|
/** Stable id. Lands on `data-enigma-input-action`, and replaces a built-in of the same name. */
|
|
@@ -278,4 +279,4 @@ interface PasswordStrengthProps extends Omit<ComponentPropsWithoutRef<"div">, "c
|
|
|
278
279
|
*/
|
|
279
280
|
declare function PasswordStrength({ value, report, userInputs, segments, labels, showWarning, classNames, ...props }: PasswordStrengthProps): ReactNode;
|
|
280
281
|
|
|
281
|
-
export { type BreachChecker, type BreachState, type BreachStatus, Button, ButtonOptions, type ButtonProps, ButtonState, EstimateOptions, type FieldAction, GeneratePasswordOptions, Input, InputOptions, type InputProps, MarqueeOptions, PasswordStrength, type PasswordStrengthProps, PasswordStrengthReport, SearchMatch, SearchOptions, type UseButtonResult, type UseInputResult, type UseMarqueeResult, type UseSearchResult, useButton, useInput, useMarquee, useSearch };
|
|
282
|
+
export { type BreachChecker, type BreachState, type BreachStatus, Button, ButtonOptions, type ButtonProps, ButtonState, EstimateOptions, type FieldAction, GeneratePasswordOptions, Input, InputOptions, type InputProps, MarqueeOptions, PasswordStrength, type PasswordStrengthProps, PasswordStrengthReport, SearchMatch, SearchOptions, type UseButtonResult, type UseInputResult, type UseMarqueeResult, type UseSearchResult, getLinkComponent, setLinkComponent, useButton, useInput, useMarquee, useSearch };
|
package/dist/react/index.js
CHANGED
|
@@ -185,6 +185,15 @@ function useButton(options = {}) {
|
|
|
185
185
|
}
|
|
186
186
|
};
|
|
187
187
|
}
|
|
188
|
+
|
|
189
|
+
// src/react/link.ts
|
|
190
|
+
var linkComponent = null;
|
|
191
|
+
function setLinkComponent(component) {
|
|
192
|
+
linkComponent = component;
|
|
193
|
+
}
|
|
194
|
+
function getLinkComponent() {
|
|
195
|
+
return linkComponent ?? "a";
|
|
196
|
+
}
|
|
188
197
|
var Button = forwardRef(function Button2({
|
|
189
198
|
as,
|
|
190
199
|
children,
|
|
@@ -201,7 +210,7 @@ var Button = forwardRef(function Button2({
|
|
|
201
210
|
}, ref) {
|
|
202
211
|
const button = useButton({ href, disabled, loading, cooldown, shortcut, onPress, onChange });
|
|
203
212
|
const state = button;
|
|
204
|
-
const Tag = as ?? state.element;
|
|
213
|
+
const Tag = as ?? (state.element === "a" ? getLinkComponent() : "button");
|
|
205
214
|
const native = Tag === "button" ? { type } : {};
|
|
206
215
|
const label = typeof children === "function" ? children(state) : children;
|
|
207
216
|
return createElement(
|
|
@@ -456,4 +465,4 @@ function PasswordStrength({
|
|
|
456
465
|
);
|
|
457
466
|
}
|
|
458
467
|
|
|
459
|
-
export { Button, Input, PasswordStrength, useButton, useInput, useMarquee, useSearch };
|
|
468
|
+
export { Button, Input, PasswordStrength, getLinkComponent, setLinkComponent, useButton, useInput, useMarquee, useSearch };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@enigmax/primitives",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.0",
|
|
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",
|
package/registry.json
CHANGED
|
@@ -301,6 +301,7 @@
|
|
|
301
301
|
],
|
|
302
302
|
"react": [
|
|
303
303
|
"Button",
|
|
304
|
+
"setLinkComponent",
|
|
304
305
|
"useButton"
|
|
305
306
|
]
|
|
306
307
|
},
|
|
@@ -324,6 +325,13 @@
|
|
|
324
325
|
"@/core/button": "./button"
|
|
325
326
|
}
|
|
326
327
|
},
|
|
328
|
+
{
|
|
329
|
+
"path": "src/react/link.ts",
|
|
330
|
+
"dest": "button/link.ts",
|
|
331
|
+
"targets": [
|
|
332
|
+
"react"
|
|
333
|
+
]
|
|
334
|
+
},
|
|
327
335
|
{
|
|
328
336
|
"path": "src/react/button.tsx",
|
|
329
337
|
"dest": "button/index.tsx",
|
|
@@ -333,7 +341,8 @@
|
|
|
333
341
|
],
|
|
334
342
|
"rewrite": {
|
|
335
343
|
"@/core/button": "./button",
|
|
336
|
-
"@/react/use-button": "./use-button"
|
|
344
|
+
"@/react/use-button": "./use-button",
|
|
345
|
+
"@/react/link": "./link"
|
|
337
346
|
}
|
|
338
347
|
}
|
|
339
348
|
],
|
package/src/react/button.tsx
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
3
|
import { useButton } from "@/react/use-button";
|
|
4
|
+
import { getLinkComponent } from "@/react/link";
|
|
4
5
|
import type { ButtonOptions, ButtonState } from "@/core/button";
|
|
5
6
|
import { createElement, forwardRef, type ComponentPropsWithoutRef, type ElementType, type ReactNode } from "react";
|
|
6
7
|
|
|
@@ -21,12 +22,8 @@ import { createElement, forwardRef, type ComponentPropsWithoutRef, type ElementT
|
|
|
21
22
|
// reports the button's state - would otherwise clash with the form event of the same name.
|
|
22
23
|
export interface ButtonProps extends ButtonOptions, Omit<ComponentPropsWithoutRef<"button">, "onClick" | "onChange" | "children" | "type"> {
|
|
23
24
|
/**
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
* ```tsx
|
|
28
|
-
* <Button as={Link} href="/settings">Settings</Button>
|
|
29
|
-
* ```
|
|
25
|
+
* Override what to render. You rarely need it: an href already renders whatever
|
|
26
|
+
* `setLinkComponent` registered - your router's Link - and a button otherwise.
|
|
30
27
|
*/
|
|
31
28
|
as?: ElementType;
|
|
32
29
|
/**
|
|
@@ -62,9 +59,11 @@ export const Button = forwardRef<HTMLElement, ButtonProps>(function Button({
|
|
|
62
59
|
const button = useButton({ href, disabled, loading, cooldown, shortcut, onPress, onChange });
|
|
63
60
|
const state: ButtonState = button;
|
|
64
61
|
|
|
65
|
-
//
|
|
66
|
-
//
|
|
67
|
-
|
|
62
|
+
// An href renders the registered link - next/link, react-router's, whatever was passed
|
|
63
|
+
// to setLinkComponent - and a plain <a> when nothing was. The package cannot import a
|
|
64
|
+
// router itself, so registering one is what turns every href into a client navigation
|
|
65
|
+
// without a word at the call site.
|
|
66
|
+
const Tag: ElementType = as ?? (state.element === "a" ? getLinkComponent() : "button");
|
|
68
67
|
|
|
69
68
|
// `type="button"` is the default on purpose. A bare <button> inside a form submits it,
|
|
70
69
|
// so an action button that forgot it posts the form instead of doing its job.
|
package/src/react/index.ts
CHANGED
|
@@ -8,6 +8,7 @@ export { type InputOptions, type InputAction, type InputIcon } from "@/core/inpu
|
|
|
8
8
|
export { type SearchOptions, type SearchMatch, type FuseConstructor } from "@/core/search";
|
|
9
9
|
export { useButton, type UseButtonResult } from "@/react/use-button";
|
|
10
10
|
export { Button, type ButtonProps } from "@/react/button";
|
|
11
|
+
export { setLinkComponent, getLinkComponent } from "@/react/link";
|
|
11
12
|
export { type ButtonOptions, type ButtonState } from "@/core/button";
|
|
12
13
|
export {
|
|
13
14
|
Input,
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import type { ElementType } from "react";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* The component every `href` in this package renders through.
|
|
7
|
+
*
|
|
8
|
+
* The package cannot `import Link from "next/link"`. It is framework-agnostic and Next is
|
|
9
|
+
* not a dependency, so that import would fail to resolve for every consumer who is not on
|
|
10
|
+
* Next - a hard build error in Vite, Astro, Remix and plain React.
|
|
11
|
+
*
|
|
12
|
+
* So it is registered instead, ONCE, and after that an href is a router link everywhere:
|
|
13
|
+
*
|
|
14
|
+
* ```tsx
|
|
15
|
+
* // app/providers.tsx, or wherever your app starts
|
|
16
|
+
* import Link from "next/link";
|
|
17
|
+
* import { setLinkComponent } from "@enigmax/primitives/react";
|
|
18
|
+
*
|
|
19
|
+
* setLinkComponent(Link);
|
|
20
|
+
* ```
|
|
21
|
+
*
|
|
22
|
+
* ```tsx
|
|
23
|
+
* // and from then on, every call site
|
|
24
|
+
* <Button href="/settings">Settings</Button>
|
|
25
|
+
* ```
|
|
26
|
+
*
|
|
27
|
+
* Without it an href renders a plain `<a>`, which is correct everywhere and merely means a
|
|
28
|
+
* full page load under a router. Any router works the same way - react-router's `Link`,
|
|
29
|
+
* TanStack Router's, Astro has none to register.
|
|
30
|
+
*
|
|
31
|
+
* A module-level value rather than a context: it is one component reference for the whole
|
|
32
|
+
* app, identical on every request, so threading a provider through the tree would buy
|
|
33
|
+
* nothing and cost every consumer a wrapper.
|
|
34
|
+
*/
|
|
35
|
+
let linkComponent: ElementType | null = null;
|
|
36
|
+
|
|
37
|
+
/** Register the router's link. Pass null to go back to a plain anchor. */
|
|
38
|
+
export function setLinkComponent(component: ElementType | null): void {
|
|
39
|
+
linkComponent = component;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/** What an href should render as right now. */
|
|
43
|
+
export function getLinkComponent(): ElementType {
|
|
44
|
+
return linkComponent ?? "a";
|
|
45
|
+
}
|