preact-missing-hooks 4.7.0 → 4.8.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/Readme.md +52 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/index.modern.mjs +1 -1
- package/dist/index.modern.mjs.map +1 -1
- package/dist/index.module.js +1 -1
- package/dist/index.module.js.map +1 -1
- package/dist/index.umd.js +1 -1
- package/dist/index.umd.js.map +1 -1
- package/dist/react.js +192 -0
- package/dist/useDeviceData.d.ts +82 -0
- package/docs/README.md +1 -0
- package/docs/main.js +35 -0
- package/package.json +9 -3
- package/scripts/ensure-microbundle-patch.cjs +46 -0
- package/src/index.ts +1 -0
- package/src/useDeviceData.ts +285 -0
- package/tests/useDeviceData.test.tsx +213 -0
package/dist/react.js
CHANGED
|
@@ -2161,7 +2161,199 @@ function usePoll(pollFn, options = {}) {
|
|
|
2161
2161
|
return { data, done, error, pollCount, start, stop };
|
|
2162
2162
|
}
|
|
2163
2163
|
|
|
2164
|
+
const SSR_DEVICE_DATA = {
|
|
2165
|
+
userAgent: "",
|
|
2166
|
+
language: "en",
|
|
2167
|
+
languages: ["en"],
|
|
2168
|
+
platform: "",
|
|
2169
|
+
cookieEnabled: false,
|
|
2170
|
+
online: true,
|
|
2171
|
+
maxTouchPoints: 0,
|
|
2172
|
+
vendor: "",
|
|
2173
|
+
touch: false,
|
|
2174
|
+
screen: {
|
|
2175
|
+
width: 0,
|
|
2176
|
+
height: 0,
|
|
2177
|
+
availWidth: 0,
|
|
2178
|
+
availHeight: 0,
|
|
2179
|
+
colorDepth: 24,
|
|
2180
|
+
pixelRatio: 1,
|
|
2181
|
+
},
|
|
2182
|
+
viewport: { width: 0, height: 0 },
|
|
2183
|
+
reducedMotion: false,
|
|
2184
|
+
colorScheme: "no-preference",
|
|
2185
|
+
};
|
|
2186
|
+
function getColorScheme() {
|
|
2187
|
+
if (typeof window === "undefined" || !window.matchMedia) {
|
|
2188
|
+
return "no-preference";
|
|
2189
|
+
}
|
|
2190
|
+
if (window.matchMedia("(prefers-color-scheme: dark)").matches) {
|
|
2191
|
+
return "dark";
|
|
2192
|
+
}
|
|
2193
|
+
if (window.matchMedia("(prefers-color-scheme: light)").matches) {
|
|
2194
|
+
return "light";
|
|
2195
|
+
}
|
|
2196
|
+
return "no-preference";
|
|
2197
|
+
}
|
|
2198
|
+
function getReducedMotion() {
|
|
2199
|
+
if (typeof window === "undefined" || !window.matchMedia) {
|
|
2200
|
+
return false;
|
|
2201
|
+
}
|
|
2202
|
+
return window.matchMedia("(prefers-reduced-motion: reduce)").matches;
|
|
2203
|
+
}
|
|
2204
|
+
/** Reads synchronous device / browser data from Navigator, Screen, and matchMedia. */
|
|
2205
|
+
function getDeviceData() {
|
|
2206
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q;
|
|
2207
|
+
if (typeof navigator === "undefined") {
|
|
2208
|
+
return SSR_DEVICE_DATA;
|
|
2209
|
+
}
|
|
2210
|
+
const nav = navigator;
|
|
2211
|
+
const screen = typeof globalThis.screen !== "undefined" ? globalThis.screen : null;
|
|
2212
|
+
const win = typeof globalThis.window !== "undefined" ? globalThis.window : null;
|
|
2213
|
+
const data = {
|
|
2214
|
+
userAgent: (_a = nav.userAgent) !== null && _a !== void 0 ? _a : "",
|
|
2215
|
+
language: (_b = nav.language) !== null && _b !== void 0 ? _b : "",
|
|
2216
|
+
languages: nav.languages ? [...nav.languages] : [],
|
|
2217
|
+
platform: (_c = nav.platform) !== null && _c !== void 0 ? _c : "",
|
|
2218
|
+
cookieEnabled: Boolean(nav.cookieEnabled),
|
|
2219
|
+
online: Boolean(nav.onLine),
|
|
2220
|
+
maxTouchPoints: (_d = nav.maxTouchPoints) !== null && _d !== void 0 ? _d : 0,
|
|
2221
|
+
vendor: (_e = nav.vendor) !== null && _e !== void 0 ? _e : "",
|
|
2222
|
+
touch: ((_f = nav.maxTouchPoints) !== null && _f !== void 0 ? _f : 0) > 0,
|
|
2223
|
+
screen: {
|
|
2224
|
+
width: (_g = screen === null || screen === void 0 ? void 0 : screen.width) !== null && _g !== void 0 ? _g : 0,
|
|
2225
|
+
height: (_h = screen === null || screen === void 0 ? void 0 : screen.height) !== null && _h !== void 0 ? _h : 0,
|
|
2226
|
+
availWidth: (_j = screen === null || screen === void 0 ? void 0 : screen.availWidth) !== null && _j !== void 0 ? _j : 0,
|
|
2227
|
+
availHeight: (_k = screen === null || screen === void 0 ? void 0 : screen.availHeight) !== null && _k !== void 0 ? _k : 0,
|
|
2228
|
+
colorDepth: (_l = screen === null || screen === void 0 ? void 0 : screen.colorDepth) !== null && _l !== void 0 ? _l : 24,
|
|
2229
|
+
pixelRatio: (_m = win === null || win === void 0 ? void 0 : win.devicePixelRatio) !== null && _m !== void 0 ? _m : 1,
|
|
2230
|
+
},
|
|
2231
|
+
viewport: {
|
|
2232
|
+
width: (_o = win === null || win === void 0 ? void 0 : win.innerWidth) !== null && _o !== void 0 ? _o : 0,
|
|
2233
|
+
height: (_p = win === null || win === void 0 ? void 0 : win.innerHeight) !== null && _p !== void 0 ? _p : 0,
|
|
2234
|
+
},
|
|
2235
|
+
reducedMotion: getReducedMotion(),
|
|
2236
|
+
colorScheme: getColorScheme(),
|
|
2237
|
+
};
|
|
2238
|
+
if (typeof nav.hardwareConcurrency === "number") {
|
|
2239
|
+
data.hardwareConcurrency = nav.hardwareConcurrency;
|
|
2240
|
+
}
|
|
2241
|
+
if (typeof nav.deviceMemory === "number") {
|
|
2242
|
+
data.deviceMemory = nav.deviceMemory;
|
|
2243
|
+
}
|
|
2244
|
+
const uaData = nav.userAgentData;
|
|
2245
|
+
if (uaData) {
|
|
2246
|
+
data.userAgentData = {
|
|
2247
|
+
mobile: Boolean(uaData.mobile),
|
|
2248
|
+
platform: (_q = uaData.platform) !== null && _q !== void 0 ? _q : "",
|
|
2249
|
+
brands: uaData.brands ? [...uaData.brands] : [],
|
|
2250
|
+
};
|
|
2251
|
+
}
|
|
2252
|
+
return data;
|
|
2253
|
+
}
|
|
2254
|
+
function readBattery() {
|
|
2255
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
2256
|
+
if (typeof navigator === "undefined")
|
|
2257
|
+
return undefined;
|
|
2258
|
+
const getBattery = navigator.getBattery;
|
|
2259
|
+
if (!getBattery)
|
|
2260
|
+
return undefined;
|
|
2261
|
+
try {
|
|
2262
|
+
const battery = yield getBattery.call(navigator);
|
|
2263
|
+
return { charging: battery.charging, level: battery.level };
|
|
2264
|
+
}
|
|
2265
|
+
catch (_a) {
|
|
2266
|
+
return undefined;
|
|
2267
|
+
}
|
|
2268
|
+
});
|
|
2269
|
+
}
|
|
2270
|
+
/**
|
|
2271
|
+
* Extracts device and browser data from native Navigator, Screen, window, and
|
|
2272
|
+
* matchMedia APIs. Updates on resize, orientation, online/offline, and
|
|
2273
|
+
* prefers-color-scheme / prefers-reduced-motion changes. Optionally polls the
|
|
2274
|
+
* Battery Status API when available.
|
|
2275
|
+
*
|
|
2276
|
+
* @param options - `includeBattery` (default true), `batteryPollIntervalMs` (default 60000)
|
|
2277
|
+
* @returns Current {@link DeviceData} snapshot
|
|
2278
|
+
*
|
|
2279
|
+
* @example
|
|
2280
|
+
* ```tsx
|
|
2281
|
+
* function DevicePanel() {
|
|
2282
|
+
* const device = useDeviceData();
|
|
2283
|
+
* return (
|
|
2284
|
+
* <dl>
|
|
2285
|
+
* <dt>Language</dt><dd>{device.language}</dd>
|
|
2286
|
+
* <dt>CPUs</dt><dd>{device.hardwareConcurrency ?? '—'}</dd>
|
|
2287
|
+
* <dt>Viewport</dt><dd>{device.viewport.width}×{device.viewport.height}</dd>
|
|
2288
|
+
* <dt>Theme</dt><dd>{device.colorScheme}</dd>
|
|
2289
|
+
* </dl>
|
|
2290
|
+
* );
|
|
2291
|
+
* }
|
|
2292
|
+
* ```
|
|
2293
|
+
*/
|
|
2294
|
+
function useDeviceData(options = {}) {
|
|
2295
|
+
const { includeBattery = true, batteryPollIntervalMs = 60000 } = options;
|
|
2296
|
+
const [data, setData] = react.useState(() => getDeviceData());
|
|
2297
|
+
const refresh = react.useCallback(() => {
|
|
2298
|
+
setData((prev) => {
|
|
2299
|
+
const next = getDeviceData();
|
|
2300
|
+
return prev.battery ? Object.assign(Object.assign({}, next), { battery: prev.battery }) : next;
|
|
2301
|
+
});
|
|
2302
|
+
}, []);
|
|
2303
|
+
react.useEffect(() => {
|
|
2304
|
+
var _a, _b, _c, _d, _e, _f;
|
|
2305
|
+
if (typeof window === "undefined")
|
|
2306
|
+
return;
|
|
2307
|
+
const onResize = () => refresh();
|
|
2308
|
+
window.addEventListener("resize", onResize);
|
|
2309
|
+
window.addEventListener("orientationchange", onResize);
|
|
2310
|
+
window.addEventListener("online", refresh);
|
|
2311
|
+
window.addEventListener("offline", refresh);
|
|
2312
|
+
const reducedMotionMq = (_a = window.matchMedia) === null || _a === void 0 ? void 0 : _a.call(window, "(prefers-reduced-motion: reduce)");
|
|
2313
|
+
const darkMq = (_b = window.matchMedia) === null || _b === void 0 ? void 0 : _b.call(window, "(prefers-color-scheme: dark)");
|
|
2314
|
+
const lightMq = (_c = window.matchMedia) === null || _c === void 0 ? void 0 : _c.call(window, "(prefers-color-scheme: light)");
|
|
2315
|
+
const onMediaChange = () => refresh();
|
|
2316
|
+
(_d = reducedMotionMq === null || reducedMotionMq === void 0 ? void 0 : reducedMotionMq.addEventListener) === null || _d === void 0 ? void 0 : _d.call(reducedMotionMq, "change", onMediaChange);
|
|
2317
|
+
(_e = darkMq === null || darkMq === void 0 ? void 0 : darkMq.addEventListener) === null || _e === void 0 ? void 0 : _e.call(darkMq, "change", onMediaChange);
|
|
2318
|
+
(_f = lightMq === null || lightMq === void 0 ? void 0 : lightMq.addEventListener) === null || _f === void 0 ? void 0 : _f.call(lightMq, "change", onMediaChange);
|
|
2319
|
+
return () => {
|
|
2320
|
+
var _a, _b, _c;
|
|
2321
|
+
window.removeEventListener("resize", onResize);
|
|
2322
|
+
window.removeEventListener("orientationchange", onResize);
|
|
2323
|
+
window.removeEventListener("online", refresh);
|
|
2324
|
+
window.removeEventListener("offline", refresh);
|
|
2325
|
+
(_a = reducedMotionMq === null || reducedMotionMq === void 0 ? void 0 : reducedMotionMq.removeEventListener) === null || _a === void 0 ? void 0 : _a.call(reducedMotionMq, "change", onMediaChange);
|
|
2326
|
+
(_b = darkMq === null || darkMq === void 0 ? void 0 : darkMq.removeEventListener) === null || _b === void 0 ? void 0 : _b.call(darkMq, "change", onMediaChange);
|
|
2327
|
+
(_c = lightMq === null || lightMq === void 0 ? void 0 : lightMq.removeEventListener) === null || _c === void 0 ? void 0 : _c.call(lightMq, "change", onMediaChange);
|
|
2328
|
+
};
|
|
2329
|
+
}, [refresh]);
|
|
2330
|
+
react.useEffect(() => {
|
|
2331
|
+
if (!includeBattery || typeof navigator === "undefined")
|
|
2332
|
+
return;
|
|
2333
|
+
let cancelled = false;
|
|
2334
|
+
let intervalId;
|
|
2335
|
+
const updateBattery = () => __awaiter(this, void 0, void 0, function* () {
|
|
2336
|
+
const battery = yield readBattery();
|
|
2337
|
+
if (cancelled || battery === undefined)
|
|
2338
|
+
return;
|
|
2339
|
+
setData((prev) => (Object.assign(Object.assign({}, prev), { battery })));
|
|
2340
|
+
});
|
|
2341
|
+
void updateBattery();
|
|
2342
|
+
if (batteryPollIntervalMs > 0) {
|
|
2343
|
+
intervalId = setInterval(() => void updateBattery(), batteryPollIntervalMs);
|
|
2344
|
+
}
|
|
2345
|
+
return () => {
|
|
2346
|
+
cancelled = true;
|
|
2347
|
+
if (intervalId !== undefined)
|
|
2348
|
+
clearInterval(intervalId);
|
|
2349
|
+
};
|
|
2350
|
+
}, [includeBattery, batteryPollIntervalMs]);
|
|
2351
|
+
return data;
|
|
2352
|
+
}
|
|
2353
|
+
|
|
2354
|
+
exports.getDeviceData = getDeviceData;
|
|
2164
2355
|
exports.useClipboard = useClipboard;
|
|
2356
|
+
exports.useDeviceData = useDeviceData;
|
|
2165
2357
|
exports.useEventBus = useEventBus;
|
|
2166
2358
|
exports.useIndexedDB = useIndexedDB;
|
|
2167
2359
|
exports.useLLMMetadata = useLLMMetadata;
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/** Parsed Client Hints from `navigator.userAgentData` when available */
|
|
2
|
+
export interface UserAgentDataInfo {
|
|
3
|
+
mobile: boolean;
|
|
4
|
+
platform: string;
|
|
5
|
+
brands: ReadonlyArray<{
|
|
6
|
+
brand: string;
|
|
7
|
+
version: string;
|
|
8
|
+
}>;
|
|
9
|
+
}
|
|
10
|
+
/** Screen and display metrics from `screen` and `window` */
|
|
11
|
+
export interface DeviceScreenInfo {
|
|
12
|
+
width: number;
|
|
13
|
+
height: number;
|
|
14
|
+
availWidth: number;
|
|
15
|
+
availHeight: number;
|
|
16
|
+
colorDepth: number;
|
|
17
|
+
pixelRatio: number;
|
|
18
|
+
}
|
|
19
|
+
/** Viewport size (`window.innerWidth` / `innerHeight`) */
|
|
20
|
+
export interface DeviceViewportInfo {
|
|
21
|
+
width: number;
|
|
22
|
+
height: number;
|
|
23
|
+
}
|
|
24
|
+
/** Battery status from the Battery Status API when available */
|
|
25
|
+
export interface DeviceBatteryInfo {
|
|
26
|
+
charging: boolean;
|
|
27
|
+
level: number;
|
|
28
|
+
}
|
|
29
|
+
/** Snapshot of device / browser data from native Navigator and related APIs */
|
|
30
|
+
export interface DeviceData {
|
|
31
|
+
userAgent: string;
|
|
32
|
+
language: string;
|
|
33
|
+
languages: readonly string[];
|
|
34
|
+
platform: string;
|
|
35
|
+
cookieEnabled: boolean;
|
|
36
|
+
online: boolean;
|
|
37
|
+
hardwareConcurrency?: number;
|
|
38
|
+
/** Approximate device RAM in GB (Chrome / some browsers only) */
|
|
39
|
+
deviceMemory?: number;
|
|
40
|
+
maxTouchPoints: number;
|
|
41
|
+
vendor: string;
|
|
42
|
+
touch: boolean;
|
|
43
|
+
screen: DeviceScreenInfo;
|
|
44
|
+
viewport: DeviceViewportInfo;
|
|
45
|
+
userAgentData?: UserAgentDataInfo;
|
|
46
|
+
reducedMotion: boolean;
|
|
47
|
+
colorScheme: "light" | "dark" | "no-preference";
|
|
48
|
+
battery?: DeviceBatteryInfo;
|
|
49
|
+
}
|
|
50
|
+
export interface UseDeviceDataOptions {
|
|
51
|
+
/** Fetch battery info when the Battery Status API exists (default: true) */
|
|
52
|
+
includeBattery?: boolean;
|
|
53
|
+
/** Battery refresh interval in ms (default: 60000) */
|
|
54
|
+
batteryPollIntervalMs?: number;
|
|
55
|
+
}
|
|
56
|
+
/** Reads synchronous device / browser data from Navigator, Screen, and matchMedia. */
|
|
57
|
+
export declare function getDeviceData(): DeviceData;
|
|
58
|
+
/**
|
|
59
|
+
* Extracts device and browser data from native Navigator, Screen, window, and
|
|
60
|
+
* matchMedia APIs. Updates on resize, orientation, online/offline, and
|
|
61
|
+
* prefers-color-scheme / prefers-reduced-motion changes. Optionally polls the
|
|
62
|
+
* Battery Status API when available.
|
|
63
|
+
*
|
|
64
|
+
* @param options - `includeBattery` (default true), `batteryPollIntervalMs` (default 60000)
|
|
65
|
+
* @returns Current {@link DeviceData} snapshot
|
|
66
|
+
*
|
|
67
|
+
* @example
|
|
68
|
+
* ```tsx
|
|
69
|
+
* function DevicePanel() {
|
|
70
|
+
* const device = useDeviceData();
|
|
71
|
+
* return (
|
|
72
|
+
* <dl>
|
|
73
|
+
* <dt>Language</dt><dd>{device.language}</dd>
|
|
74
|
+
* <dt>CPUs</dt><dd>{device.hardwareConcurrency ?? '—'}</dd>
|
|
75
|
+
* <dt>Viewport</dt><dd>{device.viewport.width}×{device.viewport.height}</dd>
|
|
76
|
+
* <dt>Theme</dt><dd>{device.colorScheme}</dd>
|
|
77
|
+
* </dl>
|
|
78
|
+
* );
|
|
79
|
+
* }
|
|
80
|
+
* ```
|
|
81
|
+
*/
|
|
82
|
+
export declare function useDeviceData(options?: UseDeviceDataOptions): DeviceData;
|
package/docs/README.md
CHANGED
|
@@ -41,6 +41,7 @@ Open `docs/index.html` in a browser that supports ES modules and import maps. Th
|
|
|
41
41
|
| **useWrappedChildren** | Children buttons get injected styles. |
|
|
42
42
|
| **usePreferredTheme** | Shows light / dark / no-preference from system. |
|
|
43
43
|
| **useNetworkState** | Online/offline and connection type. |
|
|
44
|
+
| **useDeviceData** | Live device/browser snapshot: language, CPUs, memory, viewport, screen, touch, color scheme, reduced motion, Client Hints. |
|
|
44
45
|
| **usePrefetch** | Hover or click to prefetch a URL (document or fetch); see prefetched status. |
|
|
45
46
|
| **usePoll** | Poll until done (3 ticks); see poll count and result. Stop button to cancel. |
|
|
46
47
|
| **useClipboard** | Copy and paste; see “Copied!” and pasted text. |
|
package/docs/main.js
CHANGED
|
@@ -23,6 +23,7 @@ const {
|
|
|
23
23
|
useRBAC,
|
|
24
24
|
usePrefetch,
|
|
25
25
|
usePoll,
|
|
26
|
+
useDeviceData,
|
|
26
27
|
} = await import(
|
|
27
28
|
isLocal ? '../dist/index.module.js' : 'https://unpkg.com/preact-missing-hooks/dist/index.module.js'
|
|
28
29
|
);
|
|
@@ -86,6 +87,33 @@ function DemoNetworkState() {
|
|
|
86
87
|
);
|
|
87
88
|
}
|
|
88
89
|
|
|
90
|
+
function DemoDeviceData() {
|
|
91
|
+
const device = useDeviceData({ includeBattery: false });
|
|
92
|
+
const rows = [
|
|
93
|
+
['Language', device.language],
|
|
94
|
+
['Platform', device.platform || device.userAgentData?.platform || '—'],
|
|
95
|
+
['CPUs', device.hardwareConcurrency != null ? String(device.hardwareConcurrency) : '—'],
|
|
96
|
+
['Memory (GB)', device.deviceMemory != null ? String(device.deviceMemory) : '—'],
|
|
97
|
+
['Viewport', device.viewport.width + '×' + device.viewport.height],
|
|
98
|
+
['Screen', device.screen.width + '×' + device.screen.height],
|
|
99
|
+
['Touch', device.touch ? 'yes' : 'no'],
|
|
100
|
+
['Color scheme', device.colorScheme],
|
|
101
|
+
['Reduced motion', device.reducedMotion ? 'yes' : 'no'],
|
|
102
|
+
['Online', device.online ? 'yes' : 'no'],
|
|
103
|
+
];
|
|
104
|
+
if (device.userAgentData?.mobile) {
|
|
105
|
+
rows.push(['Mobile (UA-CH)', 'yes']);
|
|
106
|
+
}
|
|
107
|
+
return h('div', { class: 'status', style: { fontSize: '0.85rem' } },
|
|
108
|
+
rows.map(([label, value]) =>
|
|
109
|
+
h('div', { key: label, style: { marginBottom: '0.25rem' } },
|
|
110
|
+
h('strong', {}, label + ': '),
|
|
111
|
+
value
|
|
112
|
+
)
|
|
113
|
+
)
|
|
114
|
+
);
|
|
115
|
+
}
|
|
116
|
+
|
|
89
117
|
function DemoPrefetch() {
|
|
90
118
|
const { prefetch, isPrefetched } = usePrefetch();
|
|
91
119
|
const [lastUrl, setLastUrl] = useState('');
|
|
@@ -562,6 +590,13 @@ const HOOKS = [
|
|
|
562
590
|
code: `const state = useNetworkState();\n// state.online, state.effectiveType, ...`,
|
|
563
591
|
Live: DemoNetworkState,
|
|
564
592
|
},
|
|
593
|
+
{
|
|
594
|
+
name: 'useDeviceData',
|
|
595
|
+
flow: 'Component → useDeviceData() → Navigator + Screen + matchMedia (+ optional Battery API)',
|
|
596
|
+
summary: 'Extracts device/browser data: language, platform, CPUs, memory, screen, viewport, touch, color scheme, reduced motion, Client Hints, and optional battery.',
|
|
597
|
+
code: `const device = useDeviceData();\n// device.language, device.hardwareConcurrency, device.viewport, device.colorScheme`,
|
|
598
|
+
Live: DemoDeviceData,
|
|
599
|
+
},
|
|
565
600
|
{
|
|
566
601
|
name: 'usePrefetch',
|
|
567
602
|
flow: 'Component → usePrefetch() → prefetch(url, options?) → link rel=prefetch or fetch()',
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "preact-missing-hooks",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.8.0",
|
|
4
4
|
"description": "A lightweight, extendable collection of missing React-like hooks for Preact — plus fresh, powerful new ones designed specifically for modern Preact apps.",
|
|
5
5
|
"author": "Prakhar Dubey",
|
|
6
6
|
"license": "MIT",
|
|
@@ -102,6 +102,11 @@
|
|
|
102
102
|
"import": "./dist/usePoll.module.js",
|
|
103
103
|
"require": "./dist/usePoll.js"
|
|
104
104
|
},
|
|
105
|
+
"./useDeviceData": {
|
|
106
|
+
"types": "./dist/useDeviceData.d.ts",
|
|
107
|
+
"import": "./dist/useDeviceData.module.js",
|
|
108
|
+
"require": "./dist/useDeviceData.js"
|
|
109
|
+
},
|
|
105
110
|
"./react": {
|
|
106
111
|
"types": "./dist/index.d.ts",
|
|
107
112
|
"import": "./dist/react.module.js",
|
|
@@ -109,7 +114,7 @@
|
|
|
109
114
|
}
|
|
110
115
|
},
|
|
111
116
|
"scripts": {
|
|
112
|
-
"build": "microbundle --alias react=preact/compat && npm run build:react && node scripts/generate-entry.cjs",
|
|
117
|
+
"build": "node scripts/ensure-microbundle-patch.cjs && microbundle --alias react=preact/compat && npm run build:react && node scripts/generate-entry.cjs",
|
|
113
118
|
"llm:generate": "hayagriva-llm generate --mode ai --include-src --verbose",
|
|
114
119
|
"build:react": "rollup -c scripts/rollup.react.config.cjs",
|
|
115
120
|
"dev": "microbundle watch",
|
|
@@ -122,7 +127,7 @@
|
|
|
122
127
|
"lint": "eslint src",
|
|
123
128
|
"format": "prettier --write \"src/**/*.{ts,tsx,json,md}\"",
|
|
124
129
|
"format:check": "prettier --check \"src/**/*.{ts,tsx,json,md}\"",
|
|
125
|
-
"prepare": "husky",
|
|
130
|
+
"prepare": "husky && node scripts/ensure-microbundle-patch.cjs",
|
|
126
131
|
"clean:cache": "node -e \"try{require('fs').rmSync('node_modules/.cache',{recursive:true,force:true});console.log('Cache cleared');}catch(e){}\"",
|
|
127
132
|
"size": "npm run clean:cache && npm run build && size-limit"
|
|
128
133
|
},
|
|
@@ -156,6 +161,7 @@
|
|
|
156
161
|
"useClipboard",
|
|
157
162
|
"usePrefetch",
|
|
158
163
|
"usePoll",
|
|
164
|
+
"useDeviceData",
|
|
159
165
|
"useRageClick",
|
|
160
166
|
"rage click",
|
|
161
167
|
"sentry",
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Patches microbundle to pass clean: true to rollup-plugin-typescript2.
|
|
3
|
+
* In rpt2, "clean" disables the RollingCache (noCache), avoiding EPERM rename
|
|
4
|
+
* failures on Windows during UMD/CJS/ESM builds.
|
|
5
|
+
*/
|
|
6
|
+
const fs = require("fs");
|
|
7
|
+
const path = require("path");
|
|
8
|
+
|
|
9
|
+
const cliPath = path.join(
|
|
10
|
+
__dirname,
|
|
11
|
+
"..",
|
|
12
|
+
"node_modules",
|
|
13
|
+
"microbundle",
|
|
14
|
+
"dist",
|
|
15
|
+
"cli.js",
|
|
16
|
+
);
|
|
17
|
+
|
|
18
|
+
if (!fs.existsSync(cliPath)) {
|
|
19
|
+
console.warn(
|
|
20
|
+
"ensure-microbundle-patch: microbundle not installed, skipping patch",
|
|
21
|
+
);
|
|
22
|
+
process.exit(0);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const src = fs.readFileSync(cliPath, "utf8");
|
|
26
|
+
const marker = "clean: true,";
|
|
27
|
+
|
|
28
|
+
if (src.includes(marker)) {
|
|
29
|
+
process.exit(0);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const needle =
|
|
33
|
+
"(useTypescript || emitDeclaration) && typescript__default['default']({";
|
|
34
|
+
const replacement = `${needle} clean: true,`;
|
|
35
|
+
|
|
36
|
+
if (!src.includes(needle)) {
|
|
37
|
+
console.error(
|
|
38
|
+
"ensure-microbundle-patch: microbundle cli.js format changed; update the patch script",
|
|
39
|
+
);
|
|
40
|
+
process.exit(1);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
fs.writeFileSync(cliPath, src.replace(needle, replacement), "utf8");
|
|
44
|
+
console.log(
|
|
45
|
+
"Patched microbundle (rollup-plugin-typescript2 clean:true for Windows EPERM)",
|
|
46
|
+
);
|
package/src/index.ts
CHANGED