@enigmax/primitives 0.1.2 → 0.2.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/chunk-OKNWKBQI.js +617 -0
- package/dist/index.d.ts +143 -1
- package/dist/index.js +1 -1
- package/dist/react/index.d.ts +53 -3
- package/dist/react/index.js +81 -3
- package/package.json +13 -4
- package/registry.json +137 -7
- package/src/core/input.ts +315 -0
- package/src/core/search.ts +225 -0
- package/src/index.ts +2 -0
- package/src/react/index.ts +4 -0
- package/src/react/use-input.ts +70 -0
- package/src/react/use-search.ts +77 -0
- package/dist/chunk-55J5JEWX.js +0 -288
package/dist/index.d.ts
CHANGED
|
@@ -70,4 +70,146 @@ interface MarqueeInstance {
|
|
|
70
70
|
*/
|
|
71
71
|
declare function createMarquee(lane: HTMLElement, track: HTMLElement, options?: MarqueeOptions): MarqueeInstance;
|
|
72
72
|
|
|
73
|
-
|
|
73
|
+
/**
|
|
74
|
+
* Input affordances: the buttons that live inside a field, with no styling of their own.
|
|
75
|
+
*
|
|
76
|
+
* A password field gets its reveal toggle automatically, because a field the visitor
|
|
77
|
+
* cannot read back is the single most common cause of a failed sign-in. Everything about
|
|
78
|
+
* it is replaceable - the icon, the label, the position, the container, whether it exists
|
|
79
|
+
* at all - and the same mechanism takes any other action you want in there.
|
|
80
|
+
*
|
|
81
|
+
* The details below are the ones the hand-rolled version gets wrong; each is commented
|
|
82
|
+
* with the failure it prevents.
|
|
83
|
+
*/
|
|
84
|
+
/** What an action renders. A string is parsed as HTML, so an inline SVG works. */
|
|
85
|
+
type InputIcon = string | Node;
|
|
86
|
+
interface InputActionState {
|
|
87
|
+
/** The field the action belongs to. */
|
|
88
|
+
input: HTMLInputElement;
|
|
89
|
+
/** True while the password is readable. Always false for a non-password field. */
|
|
90
|
+
revealed: boolean;
|
|
91
|
+
/** The field cannot be acted on: disabled or read-only. */
|
|
92
|
+
locked: boolean;
|
|
93
|
+
}
|
|
94
|
+
interface InputAction {
|
|
95
|
+
/** Stable id. Used for `data-action` and to replace a built-in (e.g. "reveal"). */
|
|
96
|
+
name: string;
|
|
97
|
+
/** Accessible name. Becomes both `aria-label` and `title`. */
|
|
98
|
+
label: string | ((state: InputActionState) => string);
|
|
99
|
+
icon: InputIcon | ((state: InputActionState) => InputIcon);
|
|
100
|
+
/** Runs on click and on Enter/Space, because it is a real button. */
|
|
101
|
+
onSelect: (state: InputActionState) => void;
|
|
102
|
+
/** Renders `aria-pressed`. Omit for actions that are not a toggle. */
|
|
103
|
+
pressed?: (state: InputActionState) => boolean;
|
|
104
|
+
/** Hide the action without removing it, e.g. a clear button on an empty field. */
|
|
105
|
+
visible?: (state: InputActionState) => boolean;
|
|
106
|
+
}
|
|
107
|
+
interface InputOptions {
|
|
108
|
+
/**
|
|
109
|
+
* The password reveal. `false` removes it. An object overrides parts of it - the
|
|
110
|
+
* icons, the labels - without giving up the caret and focus handling.
|
|
111
|
+
*/
|
|
112
|
+
reveal?: boolean | {
|
|
113
|
+
/** Shown while the password is hidden; selecting it reveals. */
|
|
114
|
+
showIcon?: InputIcon;
|
|
115
|
+
/** Shown while the password is readable. */
|
|
116
|
+
hideIcon?: InputIcon;
|
|
117
|
+
showLabel?: string;
|
|
118
|
+
hideLabel?: string;
|
|
119
|
+
};
|
|
120
|
+
/** Extra actions, or a replacement for a built-in when `name` matches. */
|
|
121
|
+
actions?: InputAction[];
|
|
122
|
+
/** Which side the actions mount on. Position them yourself with CSS. */
|
|
123
|
+
position?: "start" | "end";
|
|
124
|
+
/**
|
|
125
|
+
* Mount the actions here instead of in a container created next to the input.
|
|
126
|
+
* Use it when your markup already has a slot for them.
|
|
127
|
+
*/
|
|
128
|
+
container?: HTMLElement;
|
|
129
|
+
/** Called whenever the password's visibility changes. */
|
|
130
|
+
onRevealChange?: (revealed: boolean) => void;
|
|
131
|
+
}
|
|
132
|
+
interface InputInstance {
|
|
133
|
+
readonly revealed: boolean;
|
|
134
|
+
/** Show or hide the password. Toggles when the argument is omitted. */
|
|
135
|
+
reveal(next?: boolean): void;
|
|
136
|
+
/** Re-read the field and re-render the actions. Call after changing it yourself. */
|
|
137
|
+
refresh(): void;
|
|
138
|
+
update(options: Partial<InputOptions>): void;
|
|
139
|
+
destroy(): void;
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Wire a field's in-field actions.
|
|
143
|
+
*
|
|
144
|
+
* @param input The field itself. A `type="password"` field gets the reveal for free.
|
|
145
|
+
*/
|
|
146
|
+
declare function createInput(input: HTMLInputElement, options?: InputOptions): InputInstance;
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Search-as-you-type: debouncing, ordering, cancellation and the field wiring, with the
|
|
150
|
+
* matching left pluggable.
|
|
151
|
+
*
|
|
152
|
+
* Fuse.js is NOT a dependency of this package. Hand it the constructor and you get fuzzy
|
|
153
|
+
* matching configured exactly as if you had called it yourself - `fuseOptions` is passed
|
|
154
|
+
* through untouched. Hand it nothing and a built-in accent-insensitive substring matcher
|
|
155
|
+
* runs instead, so the primitive works with zero dependencies. Hand it a `matcher` and
|
|
156
|
+
* every part of this is replaced by your own.
|
|
157
|
+
*/
|
|
158
|
+
interface SearchMatch<T> {
|
|
159
|
+
item: T;
|
|
160
|
+
/** Lower is better, matching Fuse's convention. 0 is an exact hit. */
|
|
161
|
+
score: number;
|
|
162
|
+
/** Which key matched, when the matcher reports it. */
|
|
163
|
+
key?: string;
|
|
164
|
+
}
|
|
165
|
+
/** The shape of Fuse's constructor, declared here so the package need not depend on it. */
|
|
166
|
+
interface FuseLike<T> {
|
|
167
|
+
search(query: string): {
|
|
168
|
+
item: T;
|
|
169
|
+
score?: number;
|
|
170
|
+
matches?: {
|
|
171
|
+
key?: string;
|
|
172
|
+
}[];
|
|
173
|
+
}[];
|
|
174
|
+
}
|
|
175
|
+
type FuseConstructor = new <T>(items: readonly T[], options?: Record<string, unknown>) => FuseLike<T>;
|
|
176
|
+
interface SearchOptions<T> {
|
|
177
|
+
items?: readonly T[];
|
|
178
|
+
/** Fields to search. Dotted paths work with the built-in matcher and with Fuse. */
|
|
179
|
+
keys?: string[];
|
|
180
|
+
/**
|
|
181
|
+
* Pass Fuse.js's constructor to get fuzzy matching. Omit it for the built-in
|
|
182
|
+
* substring matcher. Ignored when `matcher` is set.
|
|
183
|
+
*/
|
|
184
|
+
fuse?: FuseConstructor;
|
|
185
|
+
/** Handed to Fuse verbatim, so any Fuse option behaves exactly as documented there. */
|
|
186
|
+
fuseOptions?: Record<string, unknown>;
|
|
187
|
+
/** Replaces the engine entirely. Return the results in the order you want them. */
|
|
188
|
+
matcher?: (query: string, items: readonly T[]) => SearchMatch<T>[];
|
|
189
|
+
/** ms to wait after the last keystroke. 0 searches on every one. */
|
|
190
|
+
debounce?: number;
|
|
191
|
+
/** Queries shorter than this return nothing rather than everything. */
|
|
192
|
+
minLength?: number;
|
|
193
|
+
/** Cap the result list. */
|
|
194
|
+
limit?: number;
|
|
195
|
+
/** What an empty query returns. "none" (default) or "all". */
|
|
196
|
+
empty?: "none" | "all";
|
|
197
|
+
onResults?: (results: SearchMatch<T>[], query: string) => void;
|
|
198
|
+
}
|
|
199
|
+
interface SearchInstance<T> {
|
|
200
|
+
readonly query: string;
|
|
201
|
+
readonly results: SearchMatch<T>[];
|
|
202
|
+
/** Debounced. */
|
|
203
|
+
search(query: string): void;
|
|
204
|
+
/** Skips the debounce, e.g. on Enter. */
|
|
205
|
+
searchNow(query: string): SearchMatch<T>[];
|
|
206
|
+
setItems(items: readonly T[]): void;
|
|
207
|
+
update(options: Partial<SearchOptions<T>>): void;
|
|
208
|
+
/** Bind to a field: input events search, Escape clears. Returns an unbind. */
|
|
209
|
+
attach(input: HTMLInputElement): () => void;
|
|
210
|
+
subscribe(listener: (results: SearchMatch<T>[], query: string) => void): () => void;
|
|
211
|
+
destroy(): void;
|
|
212
|
+
}
|
|
213
|
+
declare function createSearch<T>(options?: SearchOptions<T>): SearchInstance<T>;
|
|
214
|
+
|
|
215
|
+
export { type FuseConstructor, type FuseLike, type InputAction, type InputActionState, type InputIcon, type InputInstance, type InputOptions, type MarqueeInstance, type MarqueeOptions, type SearchInstance, type SearchMatch, type SearchOptions, createInput, createMarquee, createSearch };
|
package/dist/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export { createMarquee } from './chunk-
|
|
1
|
+
export { createInput, createMarquee, createSearch } from './chunk-OKNWKBQI.js';
|
package/dist/react/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { RefObject } from 'react';
|
|
2
|
-
import { MarqueeOptions } from '../index.js';
|
|
3
|
-
export { MarqueeInstance } from '../index.js';
|
|
2
|
+
import { MarqueeOptions, InputOptions, SearchMatch, SearchOptions } from '../index.js';
|
|
3
|
+
export { FuseConstructor, InputAction, InputIcon, MarqueeInstance } from '../index.js';
|
|
4
4
|
|
|
5
5
|
interface UseMarqueeResult {
|
|
6
6
|
/** Attach to the clipping viewport. */
|
|
@@ -42,4 +42,54 @@ interface UseMarqueeResult {
|
|
|
42
42
|
*/
|
|
43
43
|
declare function useMarquee(options?: MarqueeOptions): UseMarqueeResult;
|
|
44
44
|
|
|
45
|
-
|
|
45
|
+
interface UseInputResult {
|
|
46
|
+
/** Attach to the `<input>`. */
|
|
47
|
+
inputRef: RefObject<HTMLInputElement | null>;
|
|
48
|
+
/** Attach to your own actions container, or leave it and one is created for you. */
|
|
49
|
+
actionsRef: RefObject<HTMLElement | null>;
|
|
50
|
+
/** True while a password is readable. */
|
|
51
|
+
revealed: boolean;
|
|
52
|
+
reveal: (next?: boolean) => void;
|
|
53
|
+
/** Re-render the actions after you change the field yourself. */
|
|
54
|
+
refresh: () => void;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* In-field actions for an input, with the password reveal wired for free.
|
|
58
|
+
*
|
|
59
|
+
* ```tsx
|
|
60
|
+
* const { inputRef, revealed } = useInput();
|
|
61
|
+
* return <input ref={inputRef} type="password" autoComplete="current-password" />;
|
|
62
|
+
* ```
|
|
63
|
+
*
|
|
64
|
+
* The toggle is a real `<button type="button">`, so it never submits the form, and the
|
|
65
|
+
* caret survives the type switch.
|
|
66
|
+
*/
|
|
67
|
+
declare function useInput(options?: InputOptions): UseInputResult;
|
|
68
|
+
|
|
69
|
+
interface UseSearchResult<T> {
|
|
70
|
+
/** Attach to the search field, or drive it yourself with `search`. */
|
|
71
|
+
inputRef: RefObject<HTMLInputElement | null>;
|
|
72
|
+
query: string;
|
|
73
|
+
results: SearchMatch<T>[];
|
|
74
|
+
/** Debounced. */
|
|
75
|
+
search: (query: string) => void;
|
|
76
|
+
/** Skips the debounce. */
|
|
77
|
+
searchNow: (query: string) => void;
|
|
78
|
+
clear: () => void;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Search-as-you-type over a list.
|
|
82
|
+
*
|
|
83
|
+
* Pass `fuse` (Fuse.js's constructor) for fuzzy matching, `matcher` to replace the
|
|
84
|
+
* engine, or neither for the built-in accent-insensitive substring search.
|
|
85
|
+
*
|
|
86
|
+
* ```tsx
|
|
87
|
+
* import Fuse from "fuse.js";
|
|
88
|
+
*
|
|
89
|
+
* const { inputRef, results } = useSearch({ items: docs, keys: ["title", "body"], fuse: Fuse });
|
|
90
|
+
* return <input ref={inputRef} type="search" placeholder="Search" />;
|
|
91
|
+
* ```
|
|
92
|
+
*/
|
|
93
|
+
declare function useSearch<T>(options?: SearchOptions<T>): UseSearchResult<T>;
|
|
94
|
+
|
|
95
|
+
export { InputOptions, MarqueeOptions, SearchMatch, SearchOptions, type UseInputResult, type UseMarqueeResult, type UseSearchResult, useInput, useMarquee, useSearch };
|
package/dist/react/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { createMarquee } from '../chunk-
|
|
2
|
-
import { useRef, useState, useEffect, useLayoutEffect } from 'react';
|
|
1
|
+
import { createMarquee, createInput, createSearch } from '../chunk-OKNWKBQI.js';
|
|
2
|
+
import { useRef, useState, useMemo, useEffect, useLayoutEffect } from 'react';
|
|
3
3
|
|
|
4
4
|
var useIsomorphicLayoutEffect = typeof window === "undefined" ? useEffect : useLayoutEffect;
|
|
5
5
|
function useMarquee(options = {}) {
|
|
@@ -51,5 +51,83 @@ function useMarquee(options = {}) {
|
|
|
51
51
|
measure: () => instanceRef.current?.measure()
|
|
52
52
|
};
|
|
53
53
|
}
|
|
54
|
+
var useIsomorphicLayoutEffect2 = typeof window === "undefined" ? useEffect : useLayoutEffect;
|
|
55
|
+
function useInput(options = {}) {
|
|
56
|
+
const inputRef = useRef(null);
|
|
57
|
+
const actionsRef = useRef(null);
|
|
58
|
+
const instanceRef = useRef(null);
|
|
59
|
+
const optionsRef = useRef(options);
|
|
60
|
+
optionsRef.current = options;
|
|
61
|
+
const [revealed, setRevealed] = useState(false);
|
|
62
|
+
useIsomorphicLayoutEffect2(() => {
|
|
63
|
+
const input = inputRef.current;
|
|
64
|
+
if (!input) return;
|
|
65
|
+
const instance = createInput(input, {
|
|
66
|
+
...optionsRef.current,
|
|
67
|
+
container: actionsRef.current ?? optionsRef.current.container,
|
|
68
|
+
onRevealChange: (next) => {
|
|
69
|
+
setRevealed(next);
|
|
70
|
+
optionsRef.current.onRevealChange?.(next);
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
instanceRef.current = instance;
|
|
74
|
+
return () => {
|
|
75
|
+
instance.destroy();
|
|
76
|
+
instanceRef.current = null;
|
|
77
|
+
};
|
|
78
|
+
}, []);
|
|
79
|
+
useIsomorphicLayoutEffect2(() => {
|
|
80
|
+
instanceRef.current?.update(options);
|
|
81
|
+
}, [options.reveal, options.actions, options.position]);
|
|
82
|
+
return {
|
|
83
|
+
inputRef,
|
|
84
|
+
actionsRef,
|
|
85
|
+
revealed,
|
|
86
|
+
reveal: (next) => instanceRef.current?.reveal(next),
|
|
87
|
+
refresh: () => instanceRef.current?.refresh()
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
function useSearch(options = {}) {
|
|
91
|
+
const inputRef = useRef(null);
|
|
92
|
+
const instanceRef = useRef(null);
|
|
93
|
+
const optionsRef = useRef(options);
|
|
94
|
+
optionsRef.current = options;
|
|
95
|
+
const [query, setQuery] = useState("");
|
|
96
|
+
const [results, setResults] = useState([]);
|
|
97
|
+
const instance = useMemo(() => {
|
|
98
|
+
const created = createSearch({
|
|
99
|
+
...optionsRef.current,
|
|
100
|
+
onResults: (next, nextQuery) => {
|
|
101
|
+
setResults(next);
|
|
102
|
+
setQuery(nextQuery);
|
|
103
|
+
optionsRef.current.onResults?.(next, nextQuery);
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
instanceRef.current = created;
|
|
107
|
+
return created;
|
|
108
|
+
}, []);
|
|
109
|
+
useEffect(() => () => instance.destroy(), [instance]);
|
|
110
|
+
useEffect(() => {
|
|
111
|
+
instance.setItems(options.items ?? []);
|
|
112
|
+
}, [instance, options.items]);
|
|
113
|
+
useEffect(() => {
|
|
114
|
+
const input = inputRef.current;
|
|
115
|
+
if (!input) return;
|
|
116
|
+
return instance.attach(input);
|
|
117
|
+
}, [instance]);
|
|
118
|
+
return {
|
|
119
|
+
inputRef,
|
|
120
|
+
query,
|
|
121
|
+
results,
|
|
122
|
+
search: (next) => instance.search(next),
|
|
123
|
+
searchNow: (next) => {
|
|
124
|
+
instance.searchNow(next);
|
|
125
|
+
},
|
|
126
|
+
clear: () => {
|
|
127
|
+
if (inputRef.current) inputRef.current.value = "";
|
|
128
|
+
instance.searchNow("");
|
|
129
|
+
}
|
|
130
|
+
};
|
|
131
|
+
}
|
|
54
132
|
|
|
55
|
-
export { useMarquee };
|
|
133
|
+
export { useInput, useMarquee, useSearch };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@enigmax/primitives",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.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",
|
|
@@ -31,11 +31,15 @@
|
|
|
31
31
|
"LICENSE"
|
|
32
32
|
],
|
|
33
33
|
"peerDependencies": {
|
|
34
|
-
"react": ">=18"
|
|
34
|
+
"react": ">=18",
|
|
35
|
+
"fuse.js": ">=6"
|
|
35
36
|
},
|
|
36
37
|
"peerDependenciesMeta": {
|
|
37
38
|
"react": {
|
|
38
39
|
"optional": true
|
|
40
|
+
},
|
|
41
|
+
"fuse.js": {
|
|
42
|
+
"optional": true
|
|
39
43
|
}
|
|
40
44
|
},
|
|
41
45
|
"devDependencies": {
|
|
@@ -43,7 +47,8 @@
|
|
|
43
47
|
"@types/react": "^19.2.0",
|
|
44
48
|
"react": "^19.2.0",
|
|
45
49
|
"tsup": "^8.0.0",
|
|
46
|
-
"typescript": "^5.0.0"
|
|
50
|
+
"typescript": "^5.0.0",
|
|
51
|
+
"fuse.js": "^7.0.0"
|
|
47
52
|
},
|
|
48
53
|
"engines": {
|
|
49
54
|
"node": ">=18"
|
|
@@ -56,7 +61,11 @@
|
|
|
56
61
|
"unstyled",
|
|
57
62
|
"react",
|
|
58
63
|
"vanilla",
|
|
59
|
-
"enigma"
|
|
64
|
+
"enigma",
|
|
65
|
+
"input",
|
|
66
|
+
"password",
|
|
67
|
+
"search",
|
|
68
|
+
"fuse"
|
|
60
69
|
],
|
|
61
70
|
"license": "Apache-2.0",
|
|
62
71
|
"author": "FJRG2007 <fjrg2007@tpeoficial.com>",
|
package/registry.json
CHANGED
|
@@ -7,28 +7,46 @@
|
|
|
7
7
|
"name": "marquee",
|
|
8
8
|
"title": "Draggable infinite marquee",
|
|
9
9
|
"description": "Looping row that takes a speed in px/s, measures its own lap, and can be grabbed and thrown without swallowing the clicks on its items.",
|
|
10
|
-
"targets": [
|
|
10
|
+
"targets": [
|
|
11
|
+
"vanilla",
|
|
12
|
+
"astro",
|
|
13
|
+
"react"
|
|
14
|
+
],
|
|
11
15
|
"entry": {
|
|
12
16
|
"vanilla": "@enigmax/primitives",
|
|
13
17
|
"astro": "@enigmax/primitives",
|
|
14
18
|
"react": "@enigmax/primitives/react"
|
|
15
19
|
},
|
|
16
20
|
"exports": {
|
|
17
|
-
"vanilla": [
|
|
18
|
-
|
|
19
|
-
|
|
21
|
+
"vanilla": [
|
|
22
|
+
"createMarquee"
|
|
23
|
+
],
|
|
24
|
+
"astro": [
|
|
25
|
+
"createMarquee"
|
|
26
|
+
],
|
|
27
|
+
"react": [
|
|
28
|
+
"useMarquee"
|
|
29
|
+
]
|
|
20
30
|
},
|
|
21
31
|
"files": [
|
|
22
32
|
{
|
|
23
33
|
"path": "src/core/marquee.ts",
|
|
24
34
|
"dest": "marquee.ts",
|
|
25
|
-
"targets": [
|
|
35
|
+
"targets": [
|
|
36
|
+
"vanilla",
|
|
37
|
+
"astro",
|
|
38
|
+
"react"
|
|
39
|
+
]
|
|
26
40
|
},
|
|
27
41
|
{
|
|
28
42
|
"path": "src/react/use-marquee.ts",
|
|
29
43
|
"dest": "use-marquee.ts",
|
|
30
|
-
"targets": [
|
|
31
|
-
|
|
44
|
+
"targets": [
|
|
45
|
+
"react"
|
|
46
|
+
],
|
|
47
|
+
"rewrite": {
|
|
48
|
+
"@/core/marquee": "./marquee"
|
|
49
|
+
}
|
|
32
50
|
}
|
|
33
51
|
],
|
|
34
52
|
"styles": false,
|
|
@@ -41,6 +59,118 @@
|
|
|
41
59
|
"[data-enigma-marquee-copy]"
|
|
42
60
|
],
|
|
43
61
|
"docs": "docs/notes/primitives.md#marquee"
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
"name": "input",
|
|
65
|
+
"title": "Input affordances",
|
|
66
|
+
"description": "In-field buttons with no styles of their own. A password field gets its reveal toggle automatically; the icon, label, side and container are all replaceable, and any other action plugs into the same mechanism.",
|
|
67
|
+
"targets": [
|
|
68
|
+
"vanilla",
|
|
69
|
+
"astro",
|
|
70
|
+
"react"
|
|
71
|
+
],
|
|
72
|
+
"entry": {
|
|
73
|
+
"vanilla": "@enigmax/primitives",
|
|
74
|
+
"astro": "@enigmax/primitives",
|
|
75
|
+
"react": "@enigmax/primitives/react"
|
|
76
|
+
},
|
|
77
|
+
"exports": {
|
|
78
|
+
"vanilla": [
|
|
79
|
+
"createInput"
|
|
80
|
+
],
|
|
81
|
+
"astro": [
|
|
82
|
+
"createInput"
|
|
83
|
+
],
|
|
84
|
+
"react": [
|
|
85
|
+
"useInput"
|
|
86
|
+
]
|
|
87
|
+
},
|
|
88
|
+
"files": [
|
|
89
|
+
{
|
|
90
|
+
"path": "src/core/input.ts",
|
|
91
|
+
"dest": "input.ts",
|
|
92
|
+
"targets": [
|
|
93
|
+
"vanilla",
|
|
94
|
+
"astro",
|
|
95
|
+
"react"
|
|
96
|
+
]
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
"path": "src/react/use-input.ts",
|
|
100
|
+
"dest": "use-input.ts",
|
|
101
|
+
"targets": [
|
|
102
|
+
"react"
|
|
103
|
+
],
|
|
104
|
+
"rewrite": {
|
|
105
|
+
"@/core/input": "./input"
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
],
|
|
109
|
+
"styles": false,
|
|
110
|
+
"themeHooks": [
|
|
111
|
+
"[data-enigma-input]",
|
|
112
|
+
"[data-enigma-input][data-enigma-input-reveal=on]",
|
|
113
|
+
"[data-enigma-input-actions]",
|
|
114
|
+
"[data-enigma-input-actions][data-position=start]",
|
|
115
|
+
"[data-enigma-input-action]",
|
|
116
|
+
"[data-enigma-input-action=reveal]"
|
|
117
|
+
],
|
|
118
|
+
"docs": "docs/notes/primitives.md#input"
|
|
119
|
+
},
|
|
120
|
+
{
|
|
121
|
+
"name": "search",
|
|
122
|
+
"title": "Search as you type",
|
|
123
|
+
"description": "Debouncing, ranking, cancellation and the field wiring, with the matching pluggable. Pass Fuse.js for fuzzy search, your own function to replace the engine, or neither for the built-in accent-insensitive substring matcher.",
|
|
124
|
+
"targets": [
|
|
125
|
+
"vanilla",
|
|
126
|
+
"astro",
|
|
127
|
+
"react"
|
|
128
|
+
],
|
|
129
|
+
"entry": {
|
|
130
|
+
"vanilla": "@enigmax/primitives",
|
|
131
|
+
"astro": "@enigmax/primitives",
|
|
132
|
+
"react": "@enigmax/primitives/react"
|
|
133
|
+
},
|
|
134
|
+
"exports": {
|
|
135
|
+
"vanilla": [
|
|
136
|
+
"createSearch"
|
|
137
|
+
],
|
|
138
|
+
"astro": [
|
|
139
|
+
"createSearch"
|
|
140
|
+
],
|
|
141
|
+
"react": [
|
|
142
|
+
"useSearch"
|
|
143
|
+
]
|
|
144
|
+
},
|
|
145
|
+
"files": [
|
|
146
|
+
{
|
|
147
|
+
"path": "src/core/search.ts",
|
|
148
|
+
"dest": "search.ts",
|
|
149
|
+
"targets": [
|
|
150
|
+
"vanilla",
|
|
151
|
+
"astro",
|
|
152
|
+
"react"
|
|
153
|
+
]
|
|
154
|
+
},
|
|
155
|
+
{
|
|
156
|
+
"path": "src/react/use-search.ts",
|
|
157
|
+
"dest": "use-search.ts",
|
|
158
|
+
"targets": [
|
|
159
|
+
"react"
|
|
160
|
+
],
|
|
161
|
+
"rewrite": {
|
|
162
|
+
"@/core/search": "./search"
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
],
|
|
166
|
+
"styles": false,
|
|
167
|
+
"themeHooks": [
|
|
168
|
+
"[data-enigma-search]"
|
|
169
|
+
],
|
|
170
|
+
"optionalDependencies": {
|
|
171
|
+
"fuse.js": "Fuzzy matching. Omit it and a built-in substring matcher is used."
|
|
172
|
+
},
|
|
173
|
+
"docs": "docs/notes/primitives.md#search"
|
|
44
174
|
}
|
|
45
175
|
]
|
|
46
176
|
}
|