@reykjavik/hanna-react 0.10.103 → 0.10.104
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/AccordionList.js +2 -2
- package/Alert.d.ts +2 -2
- package/Alert.js +1 -0
- package/AutosuggestSearch.d.ts +40 -0
- package/AutosuggestSearch.js +70 -0
- package/BasicTable.d.ts +24 -4
- package/BasicTable.js +20 -19
- package/BreadCrumbs.d.ts +2 -2
- package/CHANGELOG.md +34 -0
- package/ContactBubble.d.ts +4 -3
- package/ContactBubble.js +7 -4
- package/Datepicker.d.ts +8 -3
- package/Datepicker.js +36 -14
- package/FileInput.d.ts +2 -1
- package/FileInput.js +2 -2
- package/FormField.js +2 -2
- package/Gallery.d.ts +2 -1
- package/Gallery.js +5 -0
- package/Layout.d.ts +4 -3
- package/Layout.js +0 -3
- package/MainMenu/_PrimaryPanel.d.ts +3 -4
- package/MainMenu/_PrimaryPanel.js +1 -1
- package/MainMenu.d.ts +6 -4
- package/MainMenu.js +8 -16
- package/Multiselect.d.ts +2 -1
- package/Multiselect.js +4 -3
- package/NameCard.d.ts +2 -1
- package/NameCard.js +7 -0
- package/Pagination.d.ts +2 -2
- package/ReadSpeakerPlayer.js +13 -5
- package/SearchInput.d.ts +24 -2
- package/SearchInput.js +13 -3
- package/SearchResults.d.ts +2 -1
- package/SearchResults.js +10 -2
- package/ShareButtons.d.ts +3 -2
- package/SiteSearchAutocomplete.d.ts +11 -11
- package/SiteSearchAutocomplete.js +21 -7
- package/SiteSearchCurtain.js +2 -2
- package/SiteSearchInput.d.ts +19 -10
- package/SiteSearchInput.js +9 -6
- package/Tooltip.js +4 -3
- package/VerticalTabsTOC.js +2 -2
- package/_abstract/_ScrollWrapper.d.ts +10 -0
- package/_abstract/_ScrollWrapper.js +21 -0
- package/_abstract/_Table.d.ts +71 -0
- package/_abstract/_Table.js +55 -0
- package/_abstract/_TogglerGroup.js +2 -2
- package/_abstract/_TogglerInput.js +2 -2
- package/_mixed_export_resolution_/ReactDatepicker.d.ts +3 -0
- package/esm/AccordionList.js +1 -1
- package/esm/Alert.d.ts +2 -2
- package/esm/Alert.js +1 -0
- package/esm/AutosuggestSearch.d.ts +40 -0
- package/esm/AutosuggestSearch.js +66 -0
- package/esm/BasicTable.d.ts +24 -4
- package/esm/BasicTable.js +19 -18
- package/esm/BreadCrumbs.d.ts +2 -2
- package/esm/ContactBubble.d.ts +4 -3
- package/esm/ContactBubble.js +6 -3
- package/esm/Datepicker.d.ts +8 -3
- package/esm/Datepicker.js +35 -13
- package/esm/FileInput.d.ts +2 -1
- package/esm/FileInput.js +1 -1
- package/esm/FormField.js +1 -1
- package/esm/Gallery.d.ts +2 -1
- package/esm/Gallery.js +5 -0
- package/esm/Layout.d.ts +4 -3
- package/esm/Layout.js +0 -3
- package/esm/MainMenu/_PrimaryPanel.d.ts +3 -4
- package/esm/MainMenu/_PrimaryPanel.js +1 -1
- package/esm/MainMenu.d.ts +6 -4
- package/esm/MainMenu.js +8 -16
- package/esm/Multiselect.d.ts +2 -1
- package/esm/Multiselect.js +2 -1
- package/esm/NameCard.d.ts +2 -1
- package/esm/NameCard.js +7 -0
- package/esm/Pagination.d.ts +2 -2
- package/esm/ReadSpeakerPlayer.js +13 -5
- package/esm/SearchInput.d.ts +24 -2
- package/esm/SearchInput.js +13 -3
- package/esm/SearchResults.d.ts +2 -1
- package/esm/SearchResults.js +9 -1
- package/esm/ShareButtons.d.ts +3 -2
- package/esm/SiteSearchAutocomplete.d.ts +11 -11
- package/esm/SiteSearchAutocomplete.js +21 -7
- package/esm/SiteSearchCurtain.js +1 -1
- package/esm/SiteSearchInput.d.ts +19 -10
- package/esm/SiteSearchInput.js +8 -6
- package/esm/Tooltip.js +2 -1
- package/esm/VerticalTabsTOC.js +1 -1
- package/esm/_abstract/_ScrollWrapper.d.ts +10 -0
- package/esm/_abstract/_ScrollWrapper.js +16 -0
- package/esm/_abstract/_Table.d.ts +71 -0
- package/esm/_abstract/_Table.js +51 -0
- package/esm/_abstract/_TogglerGroup.js +1 -1
- package/esm/_abstract/_TogglerInput.js +1 -1
- package/esm/_mixed_export_resolution_/ReactDatepicker.d.ts +3 -0
- package/esm/index.d.ts +1 -0
- package/esm/utils/browserSide.d.ts +119 -1
- package/esm/utils/browserSide.js +152 -1
- package/esm/utils/config.d.ts +1 -14
- package/esm/utils/config.js +0 -2
- package/esm/utils/useCallbackOnEsc.d.ts +6 -0
- package/esm/utils/useCallbackOnEsc.js +25 -0
- package/esm/utils/useDomid.d.ts +8 -0
- package/esm/utils/useDomid.js +17 -0
- package/esm/utils/useLaggedState.d.ts +18 -0
- package/esm/utils/useLaggedState.js +84 -0
- package/esm/utils/useOnClickOutside.d.ts +9 -0
- package/esm/utils/useOnClickOutside.js +32 -0
- package/esm/utils/useScrollEdgeDetect.d.ts +15 -0
- package/esm/utils/useScrollEdgeDetect.js +45 -0
- package/esm/utils/useShortState.d.ts +2 -0
- package/esm/utils/useShortState.js +34 -0
- package/esm/utils.d.ts +1 -0
- package/esm/utils.js +1 -0
- package/index.d.ts +1 -0
- package/package.json +6 -2
- package/utils/browserSide.d.ts +119 -1
- package/utils/browserSide.js +156 -4
- package/utils/config.d.ts +1 -14
- package/utils/config.js +1 -4
- package/utils/useCallbackOnEsc.d.ts +6 -0
- package/utils/useCallbackOnEsc.js +29 -0
- package/utils/useDomid.d.ts +8 -0
- package/utils/useDomid.js +21 -0
- package/utils/useLaggedState.d.ts +18 -0
- package/utils/useLaggedState.js +88 -0
- package/utils/useOnClickOutside.d.ts +9 -0
- package/utils/useOnClickOutside.js +35 -0
- package/utils/useScrollEdgeDetect.d.ts +15 -0
- package/utils/useScrollEdgeDetect.js +50 -0
- package/utils/useShortState.d.ts +2 -0
- package/utils/useShortState.js +38 -0
- package/utils.d.ts +1 -0
- package/utils.js +1 -0
package/utils/browserSide.js
CHANGED
|
@@ -1,6 +1,158 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
3
|
+
exports.setDefaultSSR = exports.useIsBrowserSide = exports.useIsServerSide = void 0;
|
|
4
|
+
const react_1 = require("react");
|
|
5
|
+
let alreadyBrowserSide = false;
|
|
6
|
+
const defaultSSRSupport = true;
|
|
7
|
+
/**
|
|
8
|
+
* The default value use for the optional `ssrSupport` parameter
|
|
9
|
+
* on the `useIsBRowserSide` and `useIsServerSide` hooks.`
|
|
10
|
+
*/
|
|
11
|
+
let DEFAULT_SSR_SUPPORT = defaultSSRSupport;
|
|
12
|
+
/**
|
|
13
|
+
* Low-level useState wrapper that initializes the state to one value
|
|
14
|
+
* during initial render and then updates it to another value
|
|
15
|
+
* once the component has been mounted.
|
|
16
|
+
*
|
|
17
|
+
* After that it's just a normal [value, setValue] pair.
|
|
18
|
+
*
|
|
19
|
+
* NOTE: The optional `ssrSupport` parameter is ignored after the initial render
|
|
20
|
+
*/
|
|
21
|
+
const useClientState = (serverState, clientState,
|
|
22
|
+
/**
|
|
23
|
+
* Indicates whether server-side rendering is supported or not.
|
|
24
|
+
*
|
|
25
|
+
* The `ssr-only` value is useful for cases where you need
|
|
26
|
+
* to demo the server-rendered version in a browser.
|
|
27
|
+
*/
|
|
28
|
+
ssrSupport = DEFAULT_SSR_SUPPORT) => {
|
|
29
|
+
const stateTuple = (0, react_1.useState)(() => (ssrSupport === 'ssr-only'
|
|
30
|
+
? serverState
|
|
31
|
+
: ssrSupport && !alreadyBrowserSide
|
|
32
|
+
? serverState
|
|
33
|
+
: clientState) // TODO: Remove this type assertion once @types/react and typescript have been updated
|
|
34
|
+
);
|
|
35
|
+
(0, react_1.useEffect)(() => {
|
|
36
|
+
alreadyBrowserSide = true;
|
|
37
|
+
if (ssrSupport !== 'ssr-only') {
|
|
38
|
+
stateTuple[1](clientState);
|
|
39
|
+
}
|
|
40
|
+
}, []);
|
|
41
|
+
return stateTuple;
|
|
42
|
+
};
|
|
43
|
+
/**
|
|
44
|
+
* Returns `true` if `useEffect` has not executed yet.
|
|
45
|
+
*
|
|
46
|
+
* This signals that we're in "server-side rendering" mode
|
|
47
|
+
* and it's not yet appropriate to do JS-driven UI enhancements.
|
|
48
|
+
*
|
|
49
|
+
* ```js
|
|
50
|
+
* const Knob = (props) => {
|
|
51
|
+
* const [visible, setVisible] = useState(false);
|
|
52
|
+
* const isServer = useIsServerSide();
|
|
53
|
+
* const handleClick = () => {
|
|
54
|
+
* setVisible(!visible);
|
|
55
|
+
* props.onClick && props.onClick(!visible);
|
|
56
|
+
* };
|
|
57
|
+
*
|
|
58
|
+
* if (isServer) {
|
|
59
|
+
* return <span className="Knob">{props.label}</span>
|
|
60
|
+
* }
|
|
61
|
+
* return (
|
|
62
|
+
* <button className="Knob" aria-pressed={visible} onClick={handleClick}>
|
|
63
|
+
* {props.label}
|
|
64
|
+
* </button>
|
|
65
|
+
* );
|
|
66
|
+
* }
|
|
67
|
+
* ```
|
|
68
|
+
*
|
|
69
|
+
* SSR support mode can optionally be set to:
|
|
70
|
+
*
|
|
71
|
+
* - `true` (the default) enables the serve-side phase (returns `true` then `undefined`).
|
|
72
|
+
* - `false` disables (skips) the serve-side phase (always returns `undefined`).
|
|
73
|
+
* - `"ssr-only"` disables (skips) the browser-side phase (always returns `true`).
|
|
74
|
+
*
|
|
75
|
+
* NOTE: The `ssrSupport` parameter is ignored after the initial render.
|
|
76
|
+
*/
|
|
77
|
+
const useIsServerSide = (ssrSupport) =>
|
|
78
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
|
79
|
+
useClientState(true, false, ssrSupport)[0] || undefined;
|
|
80
|
+
exports.useIsServerSide = useIsServerSide;
|
|
81
|
+
/**
|
|
82
|
+
* Returns `true` when `useEffect` has executed.
|
|
83
|
+
*
|
|
84
|
+
* This signals the time to apply Progressive Enhancement.
|
|
85
|
+
*
|
|
86
|
+
* ```js
|
|
87
|
+
* const Knob = (props) => {
|
|
88
|
+
* const [visible, setVisible] = useState(false);
|
|
89
|
+
* const isBrowser = useIsBrowserSide();
|
|
90
|
+
* const handleClick = () => {
|
|
91
|
+
* setVisible(!visible);
|
|
92
|
+
* props.onClick && props.onClick(!visible);
|
|
93
|
+
* };
|
|
94
|
+
*
|
|
95
|
+
* if (isBrowser) {
|
|
96
|
+
* return (
|
|
97
|
+
* <button className="Knob" aria-pressed={visible} onClick={handleClick}>
|
|
98
|
+
* {props.label}
|
|
99
|
+
* </button>
|
|
100
|
+
* );
|
|
101
|
+
* }
|
|
102
|
+
* return <span className="Knob">{props.label}</span>
|
|
103
|
+
* }
|
|
104
|
+
* ```
|
|
105
|
+
*
|
|
106
|
+
* SSR support mode can optionally be set to:
|
|
107
|
+
*
|
|
108
|
+
* - `true` (the default) enables the serve-side phase (returns `true` then `undefined`).
|
|
109
|
+
* - `false` disables (skips) the serve-side phase (always returns `true`).
|
|
110
|
+
* - `"ssr-only"` disables (skips) the browser-side phase (always returns `undefined`).
|
|
111
|
+
*
|
|
112
|
+
* NOTE: The `ssrSupport` parameter is ignored after the initial render.
|
|
113
|
+
*/
|
|
114
|
+
const useIsBrowserSide = (ssrSupport) =>
|
|
115
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
|
116
|
+
useClientState(false, true, ssrSupport)[0] || undefined;
|
|
117
|
+
exports.useIsBrowserSide = useIsBrowserSide;
|
|
118
|
+
// ---------------------------------------------------------------------------
|
|
119
|
+
const _history = [];
|
|
120
|
+
/**
|
|
121
|
+
* Allows you to set a the default SSRSupport value for the `useIsBRowserSide`
|
|
122
|
+
* and `useIsServerSide` hooks.
|
|
123
|
+
*
|
|
124
|
+
* Example use:
|
|
125
|
+
*
|
|
126
|
+
* ```js
|
|
127
|
+
* setDefaultSSR(false);
|
|
128
|
+
* ```
|
|
129
|
+
*
|
|
130
|
+
* The values are pushed to a simple stack, and if you want to revert
|
|
131
|
+
* a temporarily set value, use the `setDefaultSSR.pop()` method
|
|
132
|
+
* to go back to the previous value. Example:
|
|
133
|
+
*
|
|
134
|
+
* ```js
|
|
135
|
+
* setDefaultSSR('ssr-only');
|
|
136
|
+
* // ...render some components...
|
|
137
|
+
* setDefaultSSR.pop(); // go back to the previous state
|
|
138
|
+
* ```
|
|
139
|
+
*
|
|
140
|
+
* You explicitly switch to using the library's default by passing `undefined`
|
|
141
|
+
* as an argument — like so:
|
|
142
|
+
*
|
|
143
|
+
* ```js
|
|
144
|
+
* setDefaultSSR(undefined);
|
|
145
|
+
* ```
|
|
146
|
+
*/
|
|
147
|
+
const setDefaultSSR = (ssrSupport) => {
|
|
148
|
+
DEFAULT_SSR_SUPPORT = ssrSupport != null ? ssrSupport : defaultSSRSupport;
|
|
149
|
+
_history.unshift(DEFAULT_SSR_SUPPORT);
|
|
150
|
+
};
|
|
151
|
+
exports.setDefaultSSR = setDefaultSSR;
|
|
152
|
+
/**
|
|
153
|
+
* Unsets the last pushed defaultSSR value
|
|
154
|
+
*/
|
|
155
|
+
exports.setDefaultSSR.pop = () => {
|
|
156
|
+
_history.shift();
|
|
157
|
+
DEFAULT_SSR_SUPPORT = _history[0] != null ? _history[0] : defaultSSRSupport;
|
|
158
|
+
};
|
package/utils/config.d.ts
CHANGED
|
@@ -1,14 +1 @@
|
|
|
1
|
-
|
|
2
|
-
export type { LinkRenderer } from '../_abstract/_Link.js';
|
|
3
|
-
export { setLinkRenderer } from '../_abstract/_Link.js';
|
|
4
|
-
export { setDefaultSSR } from '@hugsmidjan/react/hooks';
|
|
5
|
-
export type SSRSupportProps = {
|
|
6
|
-
/**
|
|
7
|
-
* Indicates whether server-side rendering is supported or not.
|
|
8
|
-
*
|
|
9
|
-
* The `ssr-only` value is useful for cases where you need
|
|
10
|
-
* to demo the server-rendered version in a browser.
|
|
11
|
-
*/
|
|
12
|
-
ssr?: SSRSupport;
|
|
13
|
-
};
|
|
14
|
-
export type { SSRSupport };
|
|
1
|
+
export { type LinkRenderer, setLinkRenderer } from '../_abstract/_Link.js';
|
package/utils/config.js
CHANGED
|
@@ -1,8 +1,5 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.setLinkRenderer = void 0;
|
|
4
4
|
var _Link_js_1 = require("../_abstract/_Link.js");
|
|
5
5
|
Object.defineProperty(exports, "setLinkRenderer", { enumerable: true, get: function () { return _Link_js_1.setLinkRenderer; } });
|
|
6
|
-
// ---------------------------------------------------------------------------
|
|
7
|
-
var hooks_1 = require("@hugsmidjan/react/hooks");
|
|
8
|
-
Object.defineProperty(exports, "setDefaultSSR", { enumerable: true, get: function () { return hooks_1.setDefaultSSR; } });
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.useCallbackOnEsc = void 0;
|
|
4
|
+
const react_1 = require("react");
|
|
5
|
+
/**
|
|
6
|
+
* Performs a callback whenever the user hits the ESC key.
|
|
7
|
+
*
|
|
8
|
+
* Pass `undefined` to remove the event listener
|
|
9
|
+
*/
|
|
10
|
+
const useCallbackOnEsc = (callback) => {
|
|
11
|
+
const cb = (0, react_1.useRef)(callback);
|
|
12
|
+
const active = !!callback;
|
|
13
|
+
cb.current = callback;
|
|
14
|
+
(0, react_1.useEffect)(() => {
|
|
15
|
+
if (!active) {
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
const callbackOnEsc = (e) => {
|
|
19
|
+
if (e.key === 'Escape') {
|
|
20
|
+
cb.current && cb.current();
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
document.addEventListener('keydown', callbackOnEsc);
|
|
24
|
+
return () => {
|
|
25
|
+
document.removeEventListener('keydown', callbackOnEsc);
|
|
26
|
+
};
|
|
27
|
+
}, [active]);
|
|
28
|
+
};
|
|
29
|
+
exports.useCallbackOnEsc = useCallbackOnEsc;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Returns a stable, unique ID string.
|
|
3
|
+
*
|
|
4
|
+
* Uses useId from React@18 when available, but falls back on a custom id
|
|
5
|
+
* generator. (The custom generator causes angry hydration warnings in dev
|
|
6
|
+
* mode).
|
|
7
|
+
*/
|
|
8
|
+
export declare const useDomid: (staticId?: string) => string;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.useDomid = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const React = tslib_1.__importStar(require("react"));
|
|
6
|
+
const domid_1 = tslib_1.__importDefault(require("@hugsmidjan/qj/domid"));
|
|
7
|
+
// @ts-expect-error (transparently feature-detect useId hook, which is introduced in React@18)
|
|
8
|
+
const useId = React.useId;
|
|
9
|
+
/**
|
|
10
|
+
* Returns a stable, unique ID string.
|
|
11
|
+
*
|
|
12
|
+
* Uses useId from React@18 when available, but falls back on a custom id
|
|
13
|
+
* generator. (The custom generator causes angry hydration warnings in dev
|
|
14
|
+
* mode).
|
|
15
|
+
*/
|
|
16
|
+
exports.useDomid = useId
|
|
17
|
+
? (staticId) => {
|
|
18
|
+
const id = useId();
|
|
19
|
+
return staticId || id;
|
|
20
|
+
}
|
|
21
|
+
: (staticId) => React.useRef(staticId || (0, domid_1.default)()).current;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A `useState` alternative with in-built support for delayed (debounced) effect.
|
|
3
|
+
*
|
|
4
|
+
* This is especially useful when emulating "focusin"/"focusout" events,
|
|
5
|
+
* and a less jittery 'onMouseEnter'/'onMouseLeave' behavior.
|
|
6
|
+
*
|
|
7
|
+
* The returned `setState` function accepts an optional `customDelay` parameter.
|
|
8
|
+
*
|
|
9
|
+
* An explicitly falsy delay (`0` | `false` | `null`) results in a
|
|
10
|
+
* immediate (normal) `setState` invocation, whereas any other value uses
|
|
11
|
+
* `setTimeout` to delay the update.
|
|
12
|
+
*
|
|
13
|
+
* Each `setState` call automatically cancels any pending scheduled update.
|
|
14
|
+
*
|
|
15
|
+
* You can also use the `setState.cancel()` helper to to cancel the last
|
|
16
|
+
* scheduled update, without explicitly setting a new value.
|
|
17
|
+
*/
|
|
18
|
+
export declare const useLaggedState: <S>(initialState: S | (() => S), defaultDelay?: number, thenState?: S | (() => S) | undefined) => [currentState: S, setState: (newState: S | ((prevState: S, upcomingState: S) => S), customDelay?: number | false) => void, nextState: S, isTransitioning: true | undefined];
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.useLaggedState = void 0;
|
|
4
|
+
const react_1 = require("react");
|
|
5
|
+
// ---------------------------------------------------------------------------
|
|
6
|
+
/**
|
|
7
|
+
* A `useState` alternative with in-built support for delayed (debounced) effect.
|
|
8
|
+
*
|
|
9
|
+
* This is especially useful when emulating "focusin"/"focusout" events,
|
|
10
|
+
* and a less jittery 'onMouseEnter'/'onMouseLeave' behavior.
|
|
11
|
+
*
|
|
12
|
+
* The returned `setState` function accepts an optional `customDelay` parameter.
|
|
13
|
+
*
|
|
14
|
+
* An explicitly falsy delay (`0` | `false` | `null`) results in a
|
|
15
|
+
* immediate (normal) `setState` invocation, whereas any other value uses
|
|
16
|
+
* `setTimeout` to delay the update.
|
|
17
|
+
*
|
|
18
|
+
* Each `setState` call automatically cancels any pending scheduled update.
|
|
19
|
+
*
|
|
20
|
+
* You can also use the `setState.cancel()` helper to to cancel the last
|
|
21
|
+
* scheduled update, without explicitly setting a new value.
|
|
22
|
+
*/
|
|
23
|
+
const useLaggedState = (initialState,
|
|
24
|
+
/**
|
|
25
|
+
* Default delay in milliseconds. A value of `0` results in a
|
|
26
|
+
* immediate (normal) setState invocation.
|
|
27
|
+
*
|
|
28
|
+
* NOTE: The `defaultDelay` parameter is ignored after the initial render.
|
|
29
|
+
*/
|
|
30
|
+
defaultDelay = 0,
|
|
31
|
+
/**
|
|
32
|
+
* A state that should be automatically transitioned to after the initial mounting.
|
|
33
|
+
*
|
|
34
|
+
* Syntatic sugar equivalent to the following:
|
|
35
|
+
*
|
|
36
|
+
* ```js
|
|
37
|
+
* const [value, _, setValue] = useLaggedState(initialState, defaultDelay);
|
|
38
|
+
* useEffect(() => {
|
|
39
|
+
* setValue(thenState, defaultDelay);
|
|
40
|
+
* }, [])
|
|
41
|
+
* ```
|
|
42
|
+
*/
|
|
43
|
+
thenState) => {
|
|
44
|
+
const timeout = (0, react_1.useRef)();
|
|
45
|
+
const [[currentState, nextState], setLocalState] = (0, react_1.useState)(() => {
|
|
46
|
+
const initial = typeof initialState === 'function' ? initialState() : initialState;
|
|
47
|
+
return [initial, initial];
|
|
48
|
+
});
|
|
49
|
+
const setState = (0, react_1.useMemo)(() => {
|
|
50
|
+
const _setter = (newState, customDelay) => {
|
|
51
|
+
timeout.current && clearTimeout(timeout.current);
|
|
52
|
+
const delay = customDelay !== undefined ? customDelay : defaultDelay;
|
|
53
|
+
setLocalState((prevState) => {
|
|
54
|
+
const [current, upcoming] = prevState;
|
|
55
|
+
const newValue = typeof newState === 'function'
|
|
56
|
+
? newState(current, upcoming)
|
|
57
|
+
: newState;
|
|
58
|
+
if (!delay || newValue === current) {
|
|
59
|
+
// Instant update!
|
|
60
|
+
return newValue === current && newValue === upcoming
|
|
61
|
+
? prevState
|
|
62
|
+
: [newValue, newValue];
|
|
63
|
+
}
|
|
64
|
+
// Debounced update!
|
|
65
|
+
timeout.current = setTimeout(() => setLocalState([newValue, newValue]), delay);
|
|
66
|
+
return [current, newValue];
|
|
67
|
+
});
|
|
68
|
+
};
|
|
69
|
+
_setter.cancel = () => {
|
|
70
|
+
_setter((prevState) => prevState, null);
|
|
71
|
+
};
|
|
72
|
+
return _setter;
|
|
73
|
+
},
|
|
74
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
75
|
+
[
|
|
76
|
+
// defaultDelay,
|
|
77
|
+
]);
|
|
78
|
+
(0, react_1.useEffect)(() => {
|
|
79
|
+
thenState !== undefined && setState(thenState);
|
|
80
|
+
return () => {
|
|
81
|
+
timeout.current && clearTimeout(timeout.current);
|
|
82
|
+
};
|
|
83
|
+
}, [] // eslint-disable-line react-hooks/exhaustive-deps
|
|
84
|
+
);
|
|
85
|
+
const isTransitioning = currentState !== nextState || undefined;
|
|
86
|
+
return [currentState, setState, nextState, isTransitioning];
|
|
87
|
+
};
|
|
88
|
+
exports.useLaggedState = useLaggedState;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { MutableRefObject, RefObject } from 'react';
|
|
2
|
+
type Ref<E extends HTMLElement> = MutableRefObject<E> | RefObject<E>;
|
|
3
|
+
/**
|
|
4
|
+
*
|
|
5
|
+
* @param ref single or array of refs to check for click outside
|
|
6
|
+
* @param handler callback to run when clicked outside of the ref
|
|
7
|
+
*/
|
|
8
|
+
declare const useOnClickOutside: <E extends HTMLElement>(ref: Ref<E> | Ref<E>[], handler: (event: globalThis.MouseEvent | globalThis.TouchEvent) => void) => void;
|
|
9
|
+
export { useOnClickOutside };
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.useOnClickOutside = void 0;
|
|
4
|
+
const react_1 = require("react");
|
|
5
|
+
/**
|
|
6
|
+
*
|
|
7
|
+
* @param ref single or array of refs to check for click outside
|
|
8
|
+
* @param handler callback to run when clicked outside of the ref
|
|
9
|
+
*/
|
|
10
|
+
const useOnClickOutside = (ref, handler) => {
|
|
11
|
+
const refs = Array.isArray(ref) ? ref : [ref];
|
|
12
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
13
|
+
const stableRefs = (0, react_1.useMemo)(() => refs, refs);
|
|
14
|
+
(0, react_1.useEffect)(() => {
|
|
15
|
+
const listener = (event) => {
|
|
16
|
+
const shouldTrigger = !stableRefs.some((r) => {
|
|
17
|
+
const node = r.current;
|
|
18
|
+
if (!node) {
|
|
19
|
+
return false;
|
|
20
|
+
}
|
|
21
|
+
return node.contains(event.target);
|
|
22
|
+
});
|
|
23
|
+
if (shouldTrigger) {
|
|
24
|
+
handler(event);
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
document.addEventListener('mousedown', listener);
|
|
28
|
+
document.addEventListener('touchstart', listener);
|
|
29
|
+
return () => {
|
|
30
|
+
document.removeEventListener('mousedown', listener);
|
|
31
|
+
document.removeEventListener('touchstart', listener);
|
|
32
|
+
};
|
|
33
|
+
}, [handler, stableRefs]);
|
|
34
|
+
};
|
|
35
|
+
exports.useOnClickOutside = useOnClickOutside;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { RefObject } from 'react';
|
|
2
|
+
type ScrollAxis = 'horizontal' | 'vertical';
|
|
3
|
+
type AtState = {
|
|
4
|
+
start: boolean;
|
|
5
|
+
end: boolean;
|
|
6
|
+
};
|
|
7
|
+
export type ScrollEdgeDetectOptions<RefElm extends HTMLElement = HTMLElement> = {
|
|
8
|
+
axis: ScrollAxis;
|
|
9
|
+
/** **NOTE:** Make sure this function is stable to avoid unnecessary re-runs */
|
|
10
|
+
getElm?: (elm: RefElm | null | undefined) => HTMLElement | undefined | null | false;
|
|
11
|
+
/** Initial `at` status */
|
|
12
|
+
startAt?: AtState;
|
|
13
|
+
};
|
|
14
|
+
export declare const useScrollEdgeDetect: <RefElm extends HTMLElement = HTMLElement>(options: ScrollAxis | ScrollEdgeDetectOptions<RefElm>, scrollerRef?: RefObject<RefElm> | undefined) => [scrollElmRef: RefObject<RefElm>, at: AtState];
|
|
15
|
+
export {};
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.useScrollEdgeDetect = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const react_1 = require("react");
|
|
6
|
+
const throttle_1 = tslib_1.__importDefault(require("@hugsmidjan/qj/throttle"));
|
|
7
|
+
const tolerance = 8; // px
|
|
8
|
+
const throttleMs = 100;
|
|
9
|
+
const useScrollEdgeDetect = (options, scrollerRef) => {
|
|
10
|
+
const opts = typeof options === 'string' ? { axis: options } : options;
|
|
11
|
+
const _scrollerRef = (0, react_1.useRef)(null);
|
|
12
|
+
scrollerRef = scrollerRef || _scrollerRef;
|
|
13
|
+
const [at, setAt] = (0, react_1.useState)(opts.startAt || { start: true, end: true });
|
|
14
|
+
const scrollerRefElm = scrollerRef.current;
|
|
15
|
+
const { getElm, axis } = opts;
|
|
16
|
+
(0, react_1.useEffect)(() => {
|
|
17
|
+
const scrollerElm = scrollerRefElm && getElm ? getElm(scrollerRefElm) : scrollerRefElm;
|
|
18
|
+
if (!(scrollerElm instanceof HTMLElement)) {
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
const checkScroll = (0, throttle_1.default)(() => setAt((at) => {
|
|
22
|
+
let scroll, offsetSize, totalSize;
|
|
23
|
+
if (axis === 'horizontal') {
|
|
24
|
+
scroll = scrollerElm.scrollLeft;
|
|
25
|
+
offsetSize = scrollerElm.offsetWidth;
|
|
26
|
+
totalSize = scrollerElm.scrollWidth;
|
|
27
|
+
}
|
|
28
|
+
else {
|
|
29
|
+
scroll = scrollerElm.scrollTop;
|
|
30
|
+
offsetSize = scrollerElm.offsetHeight;
|
|
31
|
+
totalSize = scrollerElm.scrollHeight;
|
|
32
|
+
}
|
|
33
|
+
const start = scroll < tolerance;
|
|
34
|
+
const end = totalSize - (offsetSize + scroll) < tolerance;
|
|
35
|
+
if (at.start === start && at.end === end) {
|
|
36
|
+
return at;
|
|
37
|
+
}
|
|
38
|
+
return { start, end };
|
|
39
|
+
}), throttleMs);
|
|
40
|
+
scrollerElm.addEventListener('scroll', checkScroll);
|
|
41
|
+
window.addEventListener('resize', checkScroll);
|
|
42
|
+
checkScroll();
|
|
43
|
+
return () => {
|
|
44
|
+
scrollerElm.removeEventListener('scroll', checkScroll);
|
|
45
|
+
window.removeEventListener('resize', checkScroll);
|
|
46
|
+
};
|
|
47
|
+
}, [scrollerRefElm, getElm, axis]);
|
|
48
|
+
return [scrollerRef, at];
|
|
49
|
+
};
|
|
50
|
+
exports.useScrollEdgeDetect = useScrollEdgeDetect;
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
/** State variable that always snaps back to `undefined` after `duration` milliseconds. */
|
|
2
|
+
export declare const useShortState: <S>(initialState?: S | (() => S) | undefined, defaultDuration?: number) => readonly [S | undefined, (newState: S | (() => S), duration?: number) => void];
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.useShortState = void 0;
|
|
4
|
+
const react_1 = require("react");
|
|
5
|
+
const DEFAULT_DURATION = 0;
|
|
6
|
+
// TODO: Add function signtures allowing either zero args, or 2.
|
|
7
|
+
/** State variable that always snaps back to `undefined` after `duration` milliseconds. */
|
|
8
|
+
const useShortState = (
|
|
9
|
+
/** Initial temporary state that then gets reverted back
|
|
10
|
+
* to `undefined` after `duration` milliseconds
|
|
11
|
+
* */
|
|
12
|
+
initialState,
|
|
13
|
+
/** Default duration, can be overridden on a case-by-case basis
|
|
14
|
+
* by passing a custom duration to the `setState` function
|
|
15
|
+
* */
|
|
16
|
+
defaultDuration = DEFAULT_DURATION) => {
|
|
17
|
+
const [state, _setState] = (0, react_1.useState)(initialState);
|
|
18
|
+
const timeout = (0, react_1.useRef)();
|
|
19
|
+
const cancelTimeout = () => {
|
|
20
|
+
timeout.current && clearTimeout(timeout.current);
|
|
21
|
+
};
|
|
22
|
+
const setState = (0, react_1.useRef)((newState, duration = defaultDuration) => {
|
|
23
|
+
_setState(newState);
|
|
24
|
+
cancelTimeout();
|
|
25
|
+
timeout.current = setTimeout(() => {
|
|
26
|
+
timeout.current = null;
|
|
27
|
+
_setState(undefined);
|
|
28
|
+
}, duration);
|
|
29
|
+
}).current;
|
|
30
|
+
(0, react_1.useEffect)(() => {
|
|
31
|
+
if (initialState !== undefined) {
|
|
32
|
+
setState(initialState, defaultDuration);
|
|
33
|
+
}
|
|
34
|
+
return cancelTimeout;
|
|
35
|
+
}, []);
|
|
36
|
+
return [state, setState];
|
|
37
|
+
};
|
|
38
|
+
exports.useShortState = useShortState;
|
package/utils.d.ts
CHANGED
|
@@ -3,6 +3,7 @@ export * from './utils/browserSide.js';
|
|
|
3
3
|
export * from './utils/config.js';
|
|
4
4
|
export { HannaUIState, useHannaUIState } from './utils/HannaUIState.js';
|
|
5
5
|
export * from './utils/useDidChange.js';
|
|
6
|
+
export * from './utils/useDomid.js';
|
|
6
7
|
export * from './utils/useFormatMonitor.js';
|
|
7
8
|
export * from './utils/useGetSVGtext.js';
|
|
8
9
|
export * from './utils/useMenuToggling.js';
|
package/utils.js
CHANGED
|
@@ -8,6 +8,7 @@ var HannaUIState_js_1 = require("./utils/HannaUIState.js");
|
|
|
8
8
|
Object.defineProperty(exports, "HannaUIState", { enumerable: true, get: function () { return HannaUIState_js_1.HannaUIState; } });
|
|
9
9
|
Object.defineProperty(exports, "useHannaUIState", { enumerable: true, get: function () { return HannaUIState_js_1.useHannaUIState; } });
|
|
10
10
|
tslib_1.__exportStar(require("./utils/useDidChange.js"), exports);
|
|
11
|
+
tslib_1.__exportStar(require("./utils/useDomid.js"), exports);
|
|
11
12
|
tslib_1.__exportStar(require("./utils/useFormatMonitor.js"), exports);
|
|
12
13
|
tslib_1.__exportStar(require("./utils/useGetSVGtext.js"), exports);
|
|
13
14
|
tslib_1.__exportStar(require("./utils/useMenuToggling.js"), exports);
|