react-simplikit 0.0.0-canary-20260210142111
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 +133 -0
- package/dist/components/ImpressionArea/index.cjs +292 -0
- package/dist/components/ImpressionArea/index.d.cts +47 -0
- package/dist/components/Separated/index.cjs +41 -0
- package/dist/components/Separated/index.d.cts +38 -0
- package/dist/components/SwitchCase/index.cjs +36 -0
- package/dist/components/SwitchCase/index.d.cts +46 -0
- package/dist/hooks/useAsyncEffect/index.cjs +44 -0
- package/dist/hooks/useAsyncEffect/index.d.cts +25 -0
- package/dist/hooks/useBooleanState/index.cjs +46 -0
- package/dist/hooks/useBooleanState/index.d.cts +19 -0
- package/dist/hooks/useCallbackOncePerRender/index.cjs +60 -0
- package/dist/hooks/useCallbackOncePerRender/index.d.cts +40 -0
- package/dist/hooks/useConditionalEffect/index.cjs +51 -0
- package/dist/hooks/useConditionalEffect/index.d.cts +43 -0
- package/dist/hooks/useControlledState/index.cjs +57 -0
- package/dist/hooks/useControlledState/index.d.cts +51 -0
- package/dist/hooks/useCounter/index.cjs +72 -0
- package/dist/hooks/useCounter/index.d.cts +52 -0
- package/dist/hooks/useDebounce/index.cjs +124 -0
- package/dist/hooks/useDebounce/index.d.cts +48 -0
- package/dist/hooks/useDebouncedCallback/index.cjs +145 -0
- package/dist/hooks/useDebouncedCallback/index.d.cts +32 -0
- package/dist/hooks/useDoubleClick/index.cjs +76 -0
- package/dist/hooks/useDoubleClick/index.d.cts +46 -0
- package/dist/hooks/useGeolocation/index.cjs +154 -0
- package/dist/hooks/useGeolocation/index.d.cts +110 -0
- package/dist/hooks/useImpressionRef/index.cjs +255 -0
- package/dist/hooks/useImpressionRef/index.d.cts +42 -0
- package/dist/hooks/useInputState/index.cjs +46 -0
- package/dist/hooks/useInputState/index.d.cts +23 -0
- package/dist/hooks/useIntersectionObserver/index.cjs +92 -0
- package/dist/hooks/useIntersectionObserver/index.d.cts +39 -0
- package/dist/hooks/useInterval/index.cjs +65 -0
- package/dist/hooks/useInterval/index.d.cts +37 -0
- package/dist/hooks/useIsomorphicLayoutEffect/index.cjs +35 -0
- package/dist/hooks/useIsomorphicLayoutEffect/index.d.cts +25 -0
- package/dist/hooks/useLoading/index.cjs +62 -0
- package/dist/hooks/useLoading/index.d.cts +36 -0
- package/dist/hooks/useLongPress/index.cjs +124 -0
- package/dist/hooks/useLongPress/index.d.cts +74 -0
- package/dist/hooks/useMap/index.cjs +78 -0
- package/dist/hooks/useMap/index.d.cts +46 -0
- package/dist/hooks/useOutsideClickEffect/index.cjs +71 -0
- package/dist/hooks/useOutsideClickEffect/index.d.cts +31 -0
- package/dist/hooks/usePreservedCallback/index.cjs +42 -0
- package/dist/hooks/usePreservedCallback/index.d.cts +30 -0
- package/dist/hooks/usePreservedReference/index.cjs +45 -0
- package/dist/hooks/usePreservedReference/index.d.cts +44 -0
- package/dist/hooks/usePrevious/index.cjs +48 -0
- package/dist/hooks/usePrevious/index.d.cts +21 -0
- package/dist/hooks/useRefEffect/index.cjs +69 -0
- package/dist/hooks/useRefEffect/index.d.cts +31 -0
- package/dist/hooks/useStorageState/index.cjs +196 -0
- package/dist/hooks/useStorageState/index.d.cts +61 -0
- package/dist/hooks/useThrottle/index.cjs +148 -0
- package/dist/hooks/useThrottle/index.d.cts +48 -0
- package/dist/hooks/useTimeout/index.cjs +54 -0
- package/dist/hooks/useTimeout/index.d.cts +30 -0
- package/dist/hooks/useToggle/index.cjs +37 -0
- package/dist/hooks/useToggle/index.d.cts +30 -0
- package/dist/hooks/useVisibilityEvent/index.cjs +47 -0
- package/dist/hooks/useVisibilityEvent/index.d.cts +31 -0
- package/dist/index.cjs +1229 -0
- package/dist/index.d.cts +36 -0
- package/dist/utils/buildContext/index.cjs +56 -0
- package/dist/utils/buildContext/index.d.cts +38 -0
- package/dist/utils/mergeProps/index.cjs +71 -0
- package/dist/utils/mergeProps/index.d.cts +26 -0
- package/dist/utils/mergeRefs/index.cjs +46 -0
- package/dist/utils/mergeRefs/index.d.cts +39 -0
- package/esm/components/ImpressionArea/index.d.ts +47 -0
- package/esm/components/ImpressionArea/index.js +266 -0
- package/esm/components/Separated/index.d.ts +38 -0
- package/esm/components/Separated/index.js +15 -0
- package/esm/components/SwitchCase/index.d.ts +46 -0
- package/esm/components/SwitchCase/index.js +10 -0
- package/esm/hooks/useAsyncEffect/index.d.ts +25 -0
- package/esm/hooks/useAsyncEffect/index.js +18 -0
- package/esm/hooks/useBooleanState/index.d.ts +19 -0
- package/esm/hooks/useBooleanState/index.js +20 -0
- package/esm/hooks/useCallbackOncePerRender/index.d.ts +40 -0
- package/esm/hooks/useCallbackOncePerRender/index.js +34 -0
- package/esm/hooks/useConditionalEffect/index.d.ts +43 -0
- package/esm/hooks/useConditionalEffect/index.js +25 -0
- package/esm/hooks/useControlledState/index.d.ts +51 -0
- package/esm/hooks/useControlledState/index.js +31 -0
- package/esm/hooks/useCounter/index.d.ts +52 -0
- package/esm/hooks/useCounter/index.js +46 -0
- package/esm/hooks/useDebounce/index.d.ts +48 -0
- package/esm/hooks/useDebounce/index.js +98 -0
- package/esm/hooks/useDebouncedCallback/index.d.ts +32 -0
- package/esm/hooks/useDebouncedCallback/index.js +119 -0
- package/esm/hooks/useDoubleClick/index.d.ts +46 -0
- package/esm/hooks/useDoubleClick/index.js +50 -0
- package/esm/hooks/useGeolocation/index.d.ts +110 -0
- package/esm/hooks/useGeolocation/index.js +128 -0
- package/esm/hooks/useImpressionRef/index.d.ts +42 -0
- package/esm/hooks/useImpressionRef/index.js +229 -0
- package/esm/hooks/useInputState/index.d.ts +23 -0
- package/esm/hooks/useInputState/index.js +20 -0
- package/esm/hooks/useIntersectionObserver/index.d.ts +39 -0
- package/esm/hooks/useIntersectionObserver/index.js +66 -0
- package/esm/hooks/useInterval/index.d.ts +37 -0
- package/esm/hooks/useInterval/index.js +39 -0
- package/esm/hooks/useIsomorphicLayoutEffect/index.d.ts +25 -0
- package/esm/hooks/useIsomorphicLayoutEffect/index.js +9 -0
- package/esm/hooks/useLoading/index.d.ts +36 -0
- package/esm/hooks/useLoading/index.js +36 -0
- package/esm/hooks/useLongPress/index.d.ts +74 -0
- package/esm/hooks/useLongPress/index.js +98 -0
- package/esm/hooks/useMap/index.d.ts +46 -0
- package/esm/hooks/useMap/index.js +52 -0
- package/esm/hooks/useOutsideClickEffect/index.d.ts +31 -0
- package/esm/hooks/useOutsideClickEffect/index.js +45 -0
- package/esm/hooks/usePreservedCallback/index.d.ts +30 -0
- package/esm/hooks/usePreservedCallback/index.js +16 -0
- package/esm/hooks/usePreservedReference/index.d.ts +44 -0
- package/esm/hooks/usePreservedReference/index.js +19 -0
- package/esm/hooks/usePrevious/index.d.ts +21 -0
- package/esm/hooks/usePrevious/index.js +22 -0
- package/esm/hooks/useRefEffect/index.d.ts +31 -0
- package/esm/hooks/useRefEffect/index.js +43 -0
- package/esm/hooks/useStorageState/index.d.ts +61 -0
- package/esm/hooks/useStorageState/index.js +170 -0
- package/esm/hooks/useThrottle/index.d.ts +48 -0
- package/esm/hooks/useThrottle/index.js +122 -0
- package/esm/hooks/useTimeout/index.d.ts +30 -0
- package/esm/hooks/useTimeout/index.js +28 -0
- package/esm/hooks/useToggle/index.d.ts +30 -0
- package/esm/hooks/useToggle/index.js +11 -0
- package/esm/hooks/useVisibilityEvent/index.d.ts +31 -0
- package/esm/hooks/useVisibilityEvent/index.js +21 -0
- package/esm/index.d.ts +36 -0
- package/esm/index.js +1170 -0
- package/esm/utils/buildContext/index.d.ts +38 -0
- package/esm/utils/buildContext/index.js +30 -0
- package/esm/utils/mergeProps/index.d.ts +26 -0
- package/esm/utils/mergeProps/index.js +45 -0
- package/esm/utils/mergeRefs/index.d.ts +39 -0
- package/esm/utils/mergeRefs/index.js +20 -0
- package/package.json +97 -0
package/README.md
ADDED
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
# react-simplikit
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/react-simplikit)
|
|
4
|
+
[](https://github.com/toss/react-simplikit/blob/main/LICENSE)
|
|
5
|
+
[](https://codecov.io/gh/toss/react-simplikit)
|
|
6
|
+
|
|
7
|
+
English | [한국어](./README-ko_kr.md)
|
|
8
|
+
|
|
9
|
+
A lightweight, zero-dependency React utilities library providing hooks, components, and utilities.
|
|
10
|
+
|
|
11
|
+
## Features
|
|
12
|
+
|
|
13
|
+
- **Zero dependencies** - Extremely lightweight
|
|
14
|
+
- **100% TypeScript** - Full type safety
|
|
15
|
+
- **100% Test coverage** - Reliable and stable
|
|
16
|
+
- **SSR-safe** - Works with Next.js and other SSR frameworks
|
|
17
|
+
- **Tree-shakeable** - Only bundle what you use
|
|
18
|
+
|
|
19
|
+
## Library Direction
|
|
20
|
+
|
|
21
|
+
**react-simplikit is now maintained as a Universal Hook Library providing only pure state/logic hooks.**
|
|
22
|
+
|
|
23
|
+
We are repositioning react-simplikit to focus exclusively on **platform-independent hooks** that work seamlessly across web and mobile (React Native, etc.).
|
|
24
|
+
|
|
25
|
+
### What's Maintained: Pure State/Logic Hooks
|
|
26
|
+
|
|
27
|
+
Hooks that don't depend on specific platform APIs will continue to be actively maintained:
|
|
28
|
+
|
|
29
|
+
- State management hooks like `useToggle`, `useBooleanState`, `useCounter`
|
|
30
|
+
- Lifecycle hooks like `usePrevious`, `useMount`
|
|
31
|
+
- Utility hooks like `useDebounce`, `useThrottle`
|
|
32
|
+
- **Backward compatibility (BC) is preserved** for these existing pure logic hooks
|
|
33
|
+
|
|
34
|
+
### What's Deprecated: Browser/Platform-Dependent Hooks
|
|
35
|
+
|
|
36
|
+
The following hooks that strongly depend on browser-specific APIs are now deprecated:
|
|
37
|
+
|
|
38
|
+
- `useGeolocation` - depends on `navigator.geolocation`
|
|
39
|
+
- `useStorageState` - depends on `localStorage`/`sessionStorage`
|
|
40
|
+
- `useIntersectionObserver` - depends on `IntersectionObserver` API
|
|
41
|
+
- `useImpressionRef` - depends on `IntersectionObserver` + Visibility API
|
|
42
|
+
- `useDoubleClick`, `useLongPress` - depend on DOM events + `window.setTimeout`
|
|
43
|
+
- `useOutsideClickEffect` - depends on DOM events + `document`
|
|
44
|
+
- `useVisibilityEvent` - depends on `document.visibilityState`
|
|
45
|
+
|
|
46
|
+
These hooks:
|
|
47
|
+
|
|
48
|
+
- Will not receive new features or major enhancements
|
|
49
|
+
- Are marked as `@deprecated` in documentation
|
|
50
|
+
- May be removed in future major versions
|
|
51
|
+
|
|
52
|
+
### Package Status
|
|
53
|
+
|
|
54
|
+
- react-simplikit will **not be archived**
|
|
55
|
+
- Pure state/logic hooks will continue to be maintained
|
|
56
|
+
- Critical bug fixes and minimal maintenance will continue
|
|
57
|
+
- No new browser/platform-dependent hooks will be added
|
|
58
|
+
|
|
59
|
+
## Installation
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
npm install react-simplikit
|
|
63
|
+
# or
|
|
64
|
+
yarn add react-simplikit
|
|
65
|
+
# or
|
|
66
|
+
pnpm add react-simplikit
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## Quick Start
|
|
70
|
+
|
|
71
|
+
```tsx
|
|
72
|
+
import { useState, useEffect } from 'react';
|
|
73
|
+
import { useDebounce } from 'react-simplikit';
|
|
74
|
+
|
|
75
|
+
function SearchInput() {
|
|
76
|
+
const [query, setQuery] = useState('');
|
|
77
|
+
const debouncedQuery = useDebounce(query, 300);
|
|
78
|
+
|
|
79
|
+
useEffect(() => {
|
|
80
|
+
if (debouncedQuery) {
|
|
81
|
+
searchAPI(debouncedQuery);
|
|
82
|
+
}
|
|
83
|
+
}, [debouncedQuery]);
|
|
84
|
+
|
|
85
|
+
return <input value={query} onChange={e => setQuery(e.target.value)} />;
|
|
86
|
+
}
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
## What's Included
|
|
90
|
+
|
|
91
|
+
### Hooks
|
|
92
|
+
|
|
93
|
+
| Hook | Description |
|
|
94
|
+
| ------------------------- | --------------------------------------------------- |
|
|
95
|
+
| `useBooleanState` | Manage boolean state with handlers |
|
|
96
|
+
| `useDebounce` | Debounce a value |
|
|
97
|
+
| `useDebouncedCallback` | Debounce a callback function |
|
|
98
|
+
| `useInterval` | Set up intervals declaratively |
|
|
99
|
+
| `useIntersectionObserver` | Observe element visibility |
|
|
100
|
+
| `usePreservedCallback` | Stable callback reference |
|
|
101
|
+
| `usePreservedReference` | Stable object reference |
|
|
102
|
+
| ... | [See all hooks](https://react-simplikit.slash.page) |
|
|
103
|
+
|
|
104
|
+
### Components
|
|
105
|
+
|
|
106
|
+
| Component | Description |
|
|
107
|
+
| ---------------- | --------------------------------- |
|
|
108
|
+
| `SwitchCase` | Declarative switch-case rendering |
|
|
109
|
+
| `Separated` | Render items with separators |
|
|
110
|
+
| `ImpressionArea` | Track element impressions |
|
|
111
|
+
|
|
112
|
+
### Utilities
|
|
113
|
+
|
|
114
|
+
| Utility | Description |
|
|
115
|
+
| -------- | ----------------- |
|
|
116
|
+
| `assert` | Runtime assertion |
|
|
117
|
+
| `noop` | Empty function |
|
|
118
|
+
|
|
119
|
+
## Documentation
|
|
120
|
+
|
|
121
|
+
Visit [react-simplikit.slash.page](https://react-simplikit.slash.page) for full documentation.
|
|
122
|
+
|
|
123
|
+
## Related Packages
|
|
124
|
+
|
|
125
|
+
- [@react-simplikit/mobile](https://www.npmjs.com/package/@react-simplikit/mobile) - Mobile web utilities
|
|
126
|
+
|
|
127
|
+
## Contributing
|
|
128
|
+
|
|
129
|
+
We welcome contributions! Please see our [Contributing Guide](https://github.com/toss/react-simplikit/blob/main/CONTRIBUTING.md).
|
|
130
|
+
|
|
131
|
+
## License
|
|
132
|
+
|
|
133
|
+
MIT © Viva Republica, Inc. See [LICENSE](https://github.com/toss/react-simplikit/blob/main/LICENSE) for details.
|
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
"use strict";
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
+
var __export = (target, all) => {
|
|
8
|
+
for (var name in all)
|
|
9
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
10
|
+
};
|
|
11
|
+
var __copyProps = (to, from, except, desc) => {
|
|
12
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
13
|
+
for (let key of __getOwnPropNames(from))
|
|
14
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
15
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
16
|
+
}
|
|
17
|
+
return to;
|
|
18
|
+
};
|
|
19
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
20
|
+
|
|
21
|
+
// src/components/ImpressionArea/index.ts
|
|
22
|
+
var ImpressionArea_exports = {};
|
|
23
|
+
__export(ImpressionArea_exports, {
|
|
24
|
+
ImpressionArea: () => ImpressionArea
|
|
25
|
+
});
|
|
26
|
+
module.exports = __toCommonJS(ImpressionArea_exports);
|
|
27
|
+
|
|
28
|
+
// src/components/ImpressionArea/ImpressionArea.tsx
|
|
29
|
+
var import_react7 = require("react");
|
|
30
|
+
|
|
31
|
+
// src/hooks/useImpressionRef/useImpressionRef.ts
|
|
32
|
+
var import_react6 = require("react");
|
|
33
|
+
|
|
34
|
+
// src/hooks/useDebouncedCallback/useDebouncedCallback.ts
|
|
35
|
+
var import_react2 = require("react");
|
|
36
|
+
|
|
37
|
+
// src/hooks/useDebounce/debounce.ts
|
|
38
|
+
function debounce(func, debounceMs, { edges = ["leading", "trailing"] } = {}) {
|
|
39
|
+
let pendingThis = void 0;
|
|
40
|
+
let pendingArgs = null;
|
|
41
|
+
const leading = edges != null && edges.includes("leading");
|
|
42
|
+
const trailing = edges == null || edges.includes("trailing");
|
|
43
|
+
const invoke = () => {
|
|
44
|
+
if (pendingArgs !== null) {
|
|
45
|
+
func.apply(pendingThis, pendingArgs);
|
|
46
|
+
pendingThis = void 0;
|
|
47
|
+
pendingArgs = null;
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
const onTimerEnd = () => {
|
|
51
|
+
if (trailing) {
|
|
52
|
+
invoke();
|
|
53
|
+
}
|
|
54
|
+
cancel();
|
|
55
|
+
};
|
|
56
|
+
let timeoutId = null;
|
|
57
|
+
const schedule = () => {
|
|
58
|
+
if (timeoutId != null) {
|
|
59
|
+
clearTimeout(timeoutId);
|
|
60
|
+
}
|
|
61
|
+
timeoutId = setTimeout(() => {
|
|
62
|
+
timeoutId = null;
|
|
63
|
+
onTimerEnd();
|
|
64
|
+
}, debounceMs);
|
|
65
|
+
};
|
|
66
|
+
const cancelTimer = () => {
|
|
67
|
+
if (timeoutId !== null) {
|
|
68
|
+
clearTimeout(timeoutId);
|
|
69
|
+
timeoutId = null;
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
const cancel = () => {
|
|
73
|
+
cancelTimer();
|
|
74
|
+
pendingThis = void 0;
|
|
75
|
+
pendingArgs = null;
|
|
76
|
+
};
|
|
77
|
+
const debounced = function(...args) {
|
|
78
|
+
pendingThis = this;
|
|
79
|
+
pendingArgs = args;
|
|
80
|
+
const isFirstCall = timeoutId == null;
|
|
81
|
+
schedule();
|
|
82
|
+
if (leading && isFirstCall) {
|
|
83
|
+
invoke();
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
debounced.cancel = cancel;
|
|
87
|
+
return debounced;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// src/hooks/usePreservedCallback/usePreservedCallback.ts
|
|
91
|
+
var import_react = require("react");
|
|
92
|
+
function usePreservedCallback(callback) {
|
|
93
|
+
const callbackRef = (0, import_react.useRef)(callback);
|
|
94
|
+
(0, import_react.useEffect)(() => {
|
|
95
|
+
callbackRef.current = callback;
|
|
96
|
+
}, [callback]);
|
|
97
|
+
return (0, import_react.useCallback)((...args) => {
|
|
98
|
+
return callbackRef.current(...args);
|
|
99
|
+
}, []);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// src/hooks/useDebouncedCallback/useDebouncedCallback.ts
|
|
103
|
+
function useDebouncedCallback({
|
|
104
|
+
onChange,
|
|
105
|
+
timeThreshold,
|
|
106
|
+
leading = false,
|
|
107
|
+
trailing = true
|
|
108
|
+
}) {
|
|
109
|
+
const handleChange = usePreservedCallback(onChange);
|
|
110
|
+
const ref = (0, import_react2.useRef)({ value: false, clearPreviousDebounce: () => {
|
|
111
|
+
} });
|
|
112
|
+
(0, import_react2.useEffect)(() => {
|
|
113
|
+
const current = ref.current;
|
|
114
|
+
return () => {
|
|
115
|
+
current.clearPreviousDebounce();
|
|
116
|
+
};
|
|
117
|
+
}, []);
|
|
118
|
+
const edges = (0, import_react2.useMemo)(() => {
|
|
119
|
+
const _edges = [];
|
|
120
|
+
if (leading) {
|
|
121
|
+
_edges.push("leading");
|
|
122
|
+
}
|
|
123
|
+
if (trailing) {
|
|
124
|
+
_edges.push("trailing");
|
|
125
|
+
}
|
|
126
|
+
return _edges;
|
|
127
|
+
}, [leading, trailing]);
|
|
128
|
+
return (0, import_react2.useCallback)(
|
|
129
|
+
(nextValue) => {
|
|
130
|
+
if (nextValue === ref.current.value) {
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
const debounced = debounce(
|
|
134
|
+
() => {
|
|
135
|
+
handleChange(nextValue);
|
|
136
|
+
ref.current.value = nextValue;
|
|
137
|
+
},
|
|
138
|
+
timeThreshold,
|
|
139
|
+
{ edges }
|
|
140
|
+
);
|
|
141
|
+
ref.current.clearPreviousDebounce();
|
|
142
|
+
debounced();
|
|
143
|
+
ref.current.clearPreviousDebounce = debounced.cancel;
|
|
144
|
+
},
|
|
145
|
+
[handleChange, timeThreshold, edges]
|
|
146
|
+
);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// src/hooks/useIntersectionObserver/useIntersectionObserver.ts
|
|
150
|
+
var import_react4 = require("react");
|
|
151
|
+
|
|
152
|
+
// src/hooks/useRefEffect/useRefEffect.ts
|
|
153
|
+
var import_react3 = require("react");
|
|
154
|
+
function useRefEffect(callback, deps) {
|
|
155
|
+
const preservedCallback = usePreservedCallback(callback);
|
|
156
|
+
const cleanupCallbackRef = (0, import_react3.useRef)(() => {
|
|
157
|
+
});
|
|
158
|
+
const effect = (0, import_react3.useCallback)(
|
|
159
|
+
(element) => {
|
|
160
|
+
cleanupCallbackRef.current();
|
|
161
|
+
cleanupCallbackRef.current = () => {
|
|
162
|
+
};
|
|
163
|
+
if (element == null) {
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
const cleanup = preservedCallback(element);
|
|
167
|
+
if (typeof cleanup === "function") {
|
|
168
|
+
cleanupCallbackRef.current = cleanup;
|
|
169
|
+
}
|
|
170
|
+
},
|
|
171
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
172
|
+
[preservedCallback, ...deps]
|
|
173
|
+
);
|
|
174
|
+
return effect;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// src/hooks/useIntersectionObserver/useIntersectionObserver.ts
|
|
178
|
+
function useIntersectionObserver(callback, options) {
|
|
179
|
+
const preservedCallback = usePreservedCallback(callback);
|
|
180
|
+
const observer = (0, import_react4.useMemo)(() => {
|
|
181
|
+
if (typeof IntersectionObserver === "undefined") {
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
return new IntersectionObserver(([entry]) => {
|
|
185
|
+
preservedCallback(entry);
|
|
186
|
+
}, options);
|
|
187
|
+
}, [preservedCallback, options]);
|
|
188
|
+
return useRefEffect(
|
|
189
|
+
(element) => {
|
|
190
|
+
observer?.observe(element);
|
|
191
|
+
return () => {
|
|
192
|
+
observer?.unobserve(element);
|
|
193
|
+
};
|
|
194
|
+
},
|
|
195
|
+
[preservedCallback, options]
|
|
196
|
+
);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// src/hooks/useVisibilityEvent/useVisibilityEvent.ts
|
|
200
|
+
var import_react5 = require("react");
|
|
201
|
+
function useVisibilityEvent(callback, options = {}) {
|
|
202
|
+
const handleVisibilityChange = (0, import_react5.useCallback)(() => {
|
|
203
|
+
callback(document.visibilityState);
|
|
204
|
+
}, [callback]);
|
|
205
|
+
(0, import_react5.useEffect)(() => {
|
|
206
|
+
if (options?.immediate ?? false) {
|
|
207
|
+
handleVisibilityChange();
|
|
208
|
+
}
|
|
209
|
+
document.addEventListener("visibilitychange", handleVisibilityChange);
|
|
210
|
+
return () => {
|
|
211
|
+
document.removeEventListener("visibilitychange", handleVisibilityChange);
|
|
212
|
+
};
|
|
213
|
+
}, [handleVisibilityChange, options?.immediate]);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
// src/hooks/useImpressionRef/useImpressionRef.ts
|
|
217
|
+
function useImpressionRef({
|
|
218
|
+
onImpressionStart = () => {
|
|
219
|
+
},
|
|
220
|
+
onImpressionEnd = () => {
|
|
221
|
+
},
|
|
222
|
+
rootMargin,
|
|
223
|
+
areaThreshold = 0,
|
|
224
|
+
timeThreshold = 0
|
|
225
|
+
}) {
|
|
226
|
+
const impressionStartHandler = usePreservedCallback(onImpressionStart);
|
|
227
|
+
const impressionEndHandler = usePreservedCallback(onImpressionEnd);
|
|
228
|
+
const isIntersectingRef = (0, import_react6.useRef)(false);
|
|
229
|
+
const impressionEventHandler = useDebouncedCallback({
|
|
230
|
+
timeThreshold,
|
|
231
|
+
onChange: (impressed) => {
|
|
232
|
+
(impressed ? impressionStartHandler : impressionEndHandler)();
|
|
233
|
+
},
|
|
234
|
+
leading: true
|
|
235
|
+
});
|
|
236
|
+
useVisibilityEvent((documentVisible) => {
|
|
237
|
+
if (!isIntersectingRef.current) {
|
|
238
|
+
return;
|
|
239
|
+
}
|
|
240
|
+
impressionEventHandler(documentVisible === "visible");
|
|
241
|
+
});
|
|
242
|
+
return useIntersectionObserver(
|
|
243
|
+
(entry) => {
|
|
244
|
+
if (document.visibilityState === "hidden") {
|
|
245
|
+
return;
|
|
246
|
+
}
|
|
247
|
+
const currentRatio = entry.intersectionRatio;
|
|
248
|
+
const isIntersecting = areaThreshold === 0 ? entry.isIntersecting : currentRatio >= areaThreshold;
|
|
249
|
+
isIntersectingRef.current = isIntersecting;
|
|
250
|
+
impressionEventHandler(isIntersecting);
|
|
251
|
+
},
|
|
252
|
+
{ rootMargin, threshold: areaThreshold }
|
|
253
|
+
);
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
// src/utils/mergeRefs/mergeRefs.ts
|
|
257
|
+
function mergeRefs(...refs) {
|
|
258
|
+
return (value) => {
|
|
259
|
+
for (const ref of refs) {
|
|
260
|
+
if (ref == null) {
|
|
261
|
+
continue;
|
|
262
|
+
}
|
|
263
|
+
if (typeof ref === "function") {
|
|
264
|
+
ref(value);
|
|
265
|
+
continue;
|
|
266
|
+
}
|
|
267
|
+
ref.current = value;
|
|
268
|
+
}
|
|
269
|
+
};
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
// src/components/ImpressionArea/ImpressionArea.tsx
|
|
273
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
274
|
+
var ImpressionArea = (0, import_react7.forwardRef)(ImpressionAreaImpl);
|
|
275
|
+
function ImpressionAreaImpl({ as, rootMargin, areaThreshold, timeThreshold, onImpressionStart, onImpressionEnd, ...props }, ref) {
|
|
276
|
+
const Component = as ?? "div";
|
|
277
|
+
const impressionRef = useImpressionRef({
|
|
278
|
+
onImpressionStart,
|
|
279
|
+
onImpressionEnd,
|
|
280
|
+
areaThreshold,
|
|
281
|
+
timeThreshold,
|
|
282
|
+
rootMargin
|
|
283
|
+
});
|
|
284
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Component, { ref: mergeRefs(ref, impressionRef), ...props });
|
|
285
|
+
}
|
|
286
|
+
Object.assign(ImpressionArea, {
|
|
287
|
+
displayName: "ImpressionArea"
|
|
288
|
+
});
|
|
289
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
290
|
+
0 && (module.exports = {
|
|
291
|
+
ImpressionArea
|
|
292
|
+
});
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { ElementType, ReactNode, Ref } from 'react';
|
|
2
|
+
import { UseImpressionRefOptions } from '../../hooks/useImpressionRef/index.cjs';
|
|
3
|
+
|
|
4
|
+
type Element<T extends ElementType, InstrinsicElements = T extends keyof React.JSX.IntrinsicElements ? React.JSX.IntrinsicElements[T] : HTMLElement> = InstrinsicElements extends React.ClassAttributes<infer E extends HTMLElement> ? E : HTMLElement;
|
|
5
|
+
type Props<Tag extends ElementType> = React.ComponentPropsWithoutRef<Tag> & UseImpressionRefOptions & {
|
|
6
|
+
as?: Tag;
|
|
7
|
+
children?: ReactNode;
|
|
8
|
+
className?: string;
|
|
9
|
+
};
|
|
10
|
+
/**
|
|
11
|
+
* @description
|
|
12
|
+
* `ImpressionArea` is a component that measures the time a specific DOM element is visible on the screen
|
|
13
|
+
* and executes callbacks when the element enters or exits the viewport. This component uses the `useImpressionRef`
|
|
14
|
+
* hook to track the element's visibility.
|
|
15
|
+
*
|
|
16
|
+
* @template {ElementType} T - The HTML tag to render. Defaults to `div`.
|
|
17
|
+
* @param {T} [as='div'] - The HTML tag to render. Defaults to `div`.
|
|
18
|
+
* @param {string} [rootMargin] - Margin to adjust the detection area.
|
|
19
|
+
* @param {number} [areaThreshold] - Minimum ratio of the element that must be visible (0 to 1).
|
|
20
|
+
* @param {number} [timeThreshold] - Minimum time the element must be visible (in milliseconds).
|
|
21
|
+
* @param {() => void} [onImpressionStart] - Callback function executed when the element enters the view.
|
|
22
|
+
* @param {() => void} [onImpressionEnd] - Callback function executed when the element exits the view.
|
|
23
|
+
* @param {Ref<Element<T>>} [ref] - Reference to the element.
|
|
24
|
+
* @param {React.ReactNode} [children] - Child elements to be rendered inside the component.
|
|
25
|
+
* @param {string} [className] - Additional class names for styling.
|
|
26
|
+
*
|
|
27
|
+
* @returns {JSX.Element} A React component that tracks the visibility of its child elements.
|
|
28
|
+
*
|
|
29
|
+
* @example
|
|
30
|
+
* function App() {
|
|
31
|
+
* return (
|
|
32
|
+
* <ImpressionArea
|
|
33
|
+
* onImpressionStart={() => console.log('Element entered view')}
|
|
34
|
+
* onImpressionEnd={() => console.log('Element exited view')}
|
|
35
|
+
* timeThreshold={1000}
|
|
36
|
+
* areaThreshold={0.5}
|
|
37
|
+
* >
|
|
38
|
+
* <div>Track me!</div>
|
|
39
|
+
* </ImpressionArea>
|
|
40
|
+
* );
|
|
41
|
+
* }
|
|
42
|
+
*/
|
|
43
|
+
declare const ImpressionArea: <T extends ElementType = "div">(props: Props<T> & {
|
|
44
|
+
ref?: Ref<Element<T>>;
|
|
45
|
+
}) => React.ReactElement;
|
|
46
|
+
|
|
47
|
+
export { ImpressionArea };
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
"use strict";
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
+
var __export = (target, all) => {
|
|
8
|
+
for (var name in all)
|
|
9
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
10
|
+
};
|
|
11
|
+
var __copyProps = (to, from, except, desc) => {
|
|
12
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
13
|
+
for (let key of __getOwnPropNames(from))
|
|
14
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
15
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
16
|
+
}
|
|
17
|
+
return to;
|
|
18
|
+
};
|
|
19
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
20
|
+
|
|
21
|
+
// src/components/Separated/index.ts
|
|
22
|
+
var Separated_exports = {};
|
|
23
|
+
__export(Separated_exports, {
|
|
24
|
+
Separated: () => Separated
|
|
25
|
+
});
|
|
26
|
+
module.exports = __toCommonJS(Separated_exports);
|
|
27
|
+
|
|
28
|
+
// src/components/Separated/Separated.tsx
|
|
29
|
+
var import_react = require("react");
|
|
30
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
31
|
+
function Separated({ children, by: separator }) {
|
|
32
|
+
const childrenArray = import_react.Children.toArray(children).filter(import_react.isValidElement);
|
|
33
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, { children: childrenArray.map((child, i, { length }) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react.Fragment, { children: [
|
|
34
|
+
child,
|
|
35
|
+
i + 1 !== length && separator
|
|
36
|
+
] }, i)) });
|
|
37
|
+
}
|
|
38
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
39
|
+
0 && (module.exports = {
|
|
40
|
+
Separated
|
|
41
|
+
});
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import { ReactNode } from 'react';
|
|
3
|
+
|
|
4
|
+
type Props = {
|
|
5
|
+
by: ReactNode;
|
|
6
|
+
children: ReactNode;
|
|
7
|
+
};
|
|
8
|
+
/**
|
|
9
|
+
* @description
|
|
10
|
+
* `Separated` is a component that inserts a specified component between each child element.
|
|
11
|
+
* It is useful for adding separators, spacing, or other repeating elements in lists.
|
|
12
|
+
*
|
|
13
|
+
* @param {React.ReactNode} children - The child elements to render.
|
|
14
|
+
* Only valid React elements (`React.isValidElement`) will be rendered.
|
|
15
|
+
* @param {React.ReactNode} by - The component to insert between child elements.
|
|
16
|
+
*
|
|
17
|
+
* @returns {JSX.Element} A React component that separates children with a specified separator.
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* function App() {
|
|
21
|
+
* return (
|
|
22
|
+
* <Separated by={<Border type="padding24" />}>
|
|
23
|
+
* {['hello', 'react', 'world'].map(item => (
|
|
24
|
+
* <div key={item}>{item}</div>
|
|
25
|
+
* ))}
|
|
26
|
+
* </Separated>
|
|
27
|
+
* );
|
|
28
|
+
* // Expected output:
|
|
29
|
+
* // <div>hello</div>
|
|
30
|
+
* // <Border type="padding24" />
|
|
31
|
+
* // <div>react</div>
|
|
32
|
+
* // <Border type="padding24" />
|
|
33
|
+
* // <div>world</div>
|
|
34
|
+
* }
|
|
35
|
+
*/
|
|
36
|
+
declare function Separated({ children, by: separator }: Props): react_jsx_runtime.JSX.Element;
|
|
37
|
+
|
|
38
|
+
export { Separated };
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
"use strict";
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
+
var __export = (target, all) => {
|
|
8
|
+
for (var name in all)
|
|
9
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
10
|
+
};
|
|
11
|
+
var __copyProps = (to, from, except, desc) => {
|
|
12
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
13
|
+
for (let key of __getOwnPropNames(from))
|
|
14
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
15
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
16
|
+
}
|
|
17
|
+
return to;
|
|
18
|
+
};
|
|
19
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
20
|
+
|
|
21
|
+
// src/components/SwitchCase/index.ts
|
|
22
|
+
var SwitchCase_exports = {};
|
|
23
|
+
__export(SwitchCase_exports, {
|
|
24
|
+
SwitchCase: () => SwitchCase
|
|
25
|
+
});
|
|
26
|
+
module.exports = __toCommonJS(SwitchCase_exports);
|
|
27
|
+
|
|
28
|
+
// src/components/SwitchCase/SwitchCase.tsx
|
|
29
|
+
function SwitchCase({ value, caseBy, defaultComponent = () => null }) {
|
|
30
|
+
const stringifiedValue = String(value);
|
|
31
|
+
return (caseBy[stringifiedValue] ?? defaultComponent)();
|
|
32
|
+
}
|
|
33
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
34
|
+
0 && (module.exports = {
|
|
35
|
+
SwitchCase
|
|
36
|
+
});
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { ReactElement } from 'react';
|
|
2
|
+
|
|
3
|
+
type StringifiedValue<T> = (T extends boolean ? 'true' | 'false' : never) | (T extends number ? `${T}` : never) | (T extends string ? T : never);
|
|
4
|
+
type Props<Case> = {
|
|
5
|
+
value: Case;
|
|
6
|
+
caseBy: Partial<{
|
|
7
|
+
[P in StringifiedValue<Case>]: () => ReactElement | null;
|
|
8
|
+
}>;
|
|
9
|
+
defaultComponent?: () => ReactElement | null;
|
|
10
|
+
};
|
|
11
|
+
/**
|
|
12
|
+
* @description
|
|
13
|
+
* `SwitchCase` is a component that allows you to declaratively render components based on a given value,
|
|
14
|
+
* similar to a `switch-case` statement. It is useful when you need to conditionally render different
|
|
15
|
+
* components depending on a specific state.
|
|
16
|
+
*
|
|
17
|
+
* @param {Case} value - The value to compare against.
|
|
18
|
+
* The component associated with the matching key in `caseBy` will be rendered.
|
|
19
|
+
* @param {Partial<{ [P in StringifiedValue<Case>]: () => ReactElement | null }>} caseBy - An object that maps values to
|
|
20
|
+
* components to render. The keys represent possible values, and the values are functions returning
|
|
21
|
+
* the corresponding components.
|
|
22
|
+
* @param {() => ReactElement | null} [defaultComponent] - The component to render if `value` does not match
|
|
23
|
+
* any key in `caseBy`.
|
|
24
|
+
*
|
|
25
|
+
* @returns {ReactElement | null} A React component that conditionally renders based on cases.
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* function App() {
|
|
29
|
+
* return (
|
|
30
|
+
* <SwitchCase
|
|
31
|
+
* value={status}
|
|
32
|
+
* // Renders TypeA, TypeB, or TypeC based on the status value.
|
|
33
|
+
* caseBy={{
|
|
34
|
+
* a: () => <TypeA />,
|
|
35
|
+
* b: () => <TypeB />,
|
|
36
|
+
* c: () => <TypeC />,
|
|
37
|
+
* }}
|
|
38
|
+
* // Renders Default when the status value does not match any case.
|
|
39
|
+
* defaultComponent={() => <Default />}
|
|
40
|
+
* />
|
|
41
|
+
* );
|
|
42
|
+
* }
|
|
43
|
+
*/
|
|
44
|
+
declare function SwitchCase<Case>({ value, caseBy, defaultComponent }: Props<Case>): ReactElement | null;
|
|
45
|
+
|
|
46
|
+
export { SwitchCase };
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
"use strict";
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
+
var __export = (target, all) => {
|
|
8
|
+
for (var name in all)
|
|
9
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
10
|
+
};
|
|
11
|
+
var __copyProps = (to, from, except, desc) => {
|
|
12
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
13
|
+
for (let key of __getOwnPropNames(from))
|
|
14
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
15
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
16
|
+
}
|
|
17
|
+
return to;
|
|
18
|
+
};
|
|
19
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
20
|
+
|
|
21
|
+
// src/hooks/useAsyncEffect/index.ts
|
|
22
|
+
var useAsyncEffect_exports = {};
|
|
23
|
+
__export(useAsyncEffect_exports, {
|
|
24
|
+
useAsyncEffect: () => useAsyncEffect
|
|
25
|
+
});
|
|
26
|
+
module.exports = __toCommonJS(useAsyncEffect_exports);
|
|
27
|
+
|
|
28
|
+
// src/hooks/useAsyncEffect/useAsyncEffect.ts
|
|
29
|
+
var import_react = require("react");
|
|
30
|
+
function useAsyncEffect(effect, deps) {
|
|
31
|
+
(0, import_react.useEffect)(() => {
|
|
32
|
+
let cleanup;
|
|
33
|
+
effect().then((result) => {
|
|
34
|
+
cleanup = result;
|
|
35
|
+
});
|
|
36
|
+
return () => {
|
|
37
|
+
cleanup?.();
|
|
38
|
+
};
|
|
39
|
+
}, deps);
|
|
40
|
+
}
|
|
41
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
42
|
+
0 && (module.exports = {
|
|
43
|
+
useAsyncEffect
|
|
44
|
+
});
|