@koine/react 2.0.0-beta.72 → 2.0.0-beta.74

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.
Files changed (107) hide show
  1. package/FaviconTags.d.ts +9 -0
  2. package/FaviconTags.js +5 -0
  3. package/Meta.d.ts +5 -0
  4. package/Meta.js +5 -0
  5. package/NoJs.d.ts +3 -0
  6. package/NoJs.js +7 -0
  7. package/Polymorphic.d.ts +26 -0
  8. package/Polymorphic.js +1 -0
  9. package/calendar/CalendarDaygridCell.js +42 -0
  10. package/calendar/CalendarDaygridNav.js +22 -0
  11. package/calendar/CalendarDaygridTable.js +50 -0
  12. package/calendar/CalendarLegend.js +4 -0
  13. package/calendar/calendar-api-google.js +90 -0
  14. package/calendar/types.js +1 -0
  15. package/calendar/useCalendar.js +175 -0
  16. package/calendar/useDateLocale.js +16 -0
  17. package/calendar/utils.js +172 -0
  18. package/calendar.js +7 -0
  19. package/classed.d.ts +8 -0
  20. package/classed.js +41 -0
  21. package/components/FaviconTags.js +4 -0
  22. package/components/Meta.js +4 -0
  23. package/components/NoJs.js +6 -0
  24. package/createUseMediaQueryWidth.d.ts +6 -0
  25. package/createUseMediaQueryWidth.js +38 -0
  26. package/extendComponent.d.ts +16 -0
  27. package/extendComponent.js +9 -0
  28. package/forms/antispam.js +29 -0
  29. package/forms.js +1 -0
  30. package/hooks/index.js +19 -0
  31. package/hooks/useAsyncFn.js +25 -0
  32. package/hooks/useFirstMountState.js +9 -0
  33. package/hooks/useFixedOffset.js +41 -0
  34. package/hooks/useFocus.js +8 -0
  35. package/hooks/useInterval.js +19 -0
  36. package/hooks/useIsomorphicLayoutEffect.js +3 -0
  37. package/hooks/useKeyUp.js +15 -0
  38. package/hooks/useMeasure.js +118 -0
  39. package/hooks/useMountedState.js +12 -0
  40. package/hooks/useNavigateAway.js +24 -0
  41. package/hooks/usePrevious.js +8 -0
  42. package/hooks/usePreviousRef.js +8 -0
  43. package/hooks/useReveal.js +41 -0
  44. package/hooks/useScrollPosition.js +57 -0
  45. package/hooks/useScrollThreshold.js +25 -0
  46. package/hooks/useScrollTo.js +17 -0
  47. package/hooks/useSmoothScroll.js +31 -0
  48. package/hooks/useSpinDelay.js +35 -0
  49. package/hooks/useTraceUpdate.js +16 -0
  50. package/hooks/useUpdateEffect.js +10 -0
  51. package/hooks/useWindowSize.js +19 -0
  52. package/index.cjs.js +33 -23
  53. package/index.d.ts +28 -3
  54. package/index.esm.js +33 -26
  55. package/index.js +26 -0
  56. package/mergeRefs.d.ts +2 -0
  57. package/mergeRefs.js +13 -0
  58. package/package.json +3 -3
  59. package/types.js +1 -0
  60. package/useAsyncFn.d.ts +24 -0
  61. package/useAsyncFn.js +26 -0
  62. package/useFirstMountState.d.ts +2 -0
  63. package/useFirstMountState.js +10 -0
  64. package/useFixedOffset.d.ts +2 -0
  65. package/useFixedOffset.js +42 -0
  66. package/useFocus.d.ts +2 -0
  67. package/useFocus.js +9 -0
  68. package/useInterval.d.ts +2 -0
  69. package/useInterval.js +20 -0
  70. package/useIsomorphicLayoutEffect.d.ts +3 -0
  71. package/useIsomorphicLayoutEffect.js +4 -0
  72. package/useKeyUp.d.ts +2 -0
  73. package/useKeyUp.js +16 -0
  74. package/useMeasure.d.ts +22 -0
  75. package/useMeasure.js +119 -0
  76. package/useMountedState.d.ts +2 -0
  77. package/useMountedState.js +13 -0
  78. package/useNavigateAway.d.ts +3 -0
  79. package/useNavigateAway.js +25 -0
  80. package/usePrevious.d.ts +2 -0
  81. package/usePrevious.js +9 -0
  82. package/usePreviousRef.d.ts +2 -0
  83. package/usePreviousRef.js +9 -0
  84. package/useReveal.d.ts +13 -0
  85. package/useReveal.js +42 -0
  86. package/useScrollPosition.d.ts +7 -0
  87. package/useScrollPosition.js +58 -0
  88. package/useScrollThreshold.d.ts +2 -0
  89. package/useScrollThreshold.js +26 -0
  90. package/useScrollTo.d.ts +2 -0
  91. package/useScrollTo.js +18 -0
  92. package/useSmoothScroll.d.ts +2 -0
  93. package/useSmoothScroll.js +32 -0
  94. package/useSpinDelay.d.ts +2 -0
  95. package/useSpinDelay.js +36 -0
  96. package/useTraceUpdate.d.ts +2 -0
  97. package/useTraceUpdate.js +17 -0
  98. package/useUpdateEffect.d.ts +3 -0
  99. package/useUpdateEffect.js +11 -0
  100. package/useWindowSize.d.ts +3 -0
  101. package/useWindowSize.js +20 -0
  102. package/utils/Polymorphic.js +1 -0
  103. package/utils/classed.js +40 -0
  104. package/utils/createUseMediaQueryWidth.js +37 -0
  105. package/utils/extendComponent.js +8 -0
  106. package/utils/index.js +4 -0
  107. package/utils/mergeRefs.js +12 -0
@@ -0,0 +1,31 @@
1
+ import { useCallback } from "react";
2
+ import { isNumber } from "@koine/utils";
3
+ import { getOffsetTopSlim, scrollTo } from "@koine/dom";
4
+ import { useFixedOffset } from "./useFixedOffset";
5
+ export let useSmoothScroll = (disregardAutomaticFixedOffset) => {
6
+ const fixedOffset = useFixedOffset();
7
+ const scroll = useCallback((to, customOffset, callback, fallbackTimeout, behavior) => {
8
+ let top = undefined;
9
+ let toIsElement = false;
10
+ if (isNumber(to)) {
11
+ top = to;
12
+ }
13
+ else if (to) {
14
+ const el = document.getElementById(to);
15
+ if (el) {
16
+ top = getOffsetTopSlim(el) - fixedOffset.current;
17
+ toIsElement = true;
18
+ }
19
+ }
20
+ if (isNumber(top)) {
21
+ top =
22
+ top +
23
+ (customOffset || 0) +
24
+ (disregardAutomaticFixedOffset || toIsElement
25
+ ? 0
26
+ : fixedOffset.current);
27
+ scrollTo(top, callback, fallbackTimeout, behavior);
28
+ }
29
+ }, [disregardAutomaticFixedOffset, fixedOffset]);
30
+ return scroll;
31
+ };
@@ -0,0 +1,35 @@
1
+ import { useEffect, useRef, useState } from "react";
2
+ var State;
3
+ (function (State) {
4
+ State[State["IDLE"] = 0] = "IDLE";
5
+ State[State["DELAY"] = 1] = "DELAY";
6
+ State[State["DISPLAY"] = 2] = "DISPLAY";
7
+ State[State["EXPIRE"] = 3] = "EXPIRE";
8
+ })(State || (State = {}));
9
+ export let useSpinDelay = (loading, delay = 500, minDuration = 200) => {
10
+ const [state, setState] = useState(State.IDLE);
11
+ const timeout = useRef();
12
+ useEffect(() => {
13
+ if (loading && state === State.IDLE) {
14
+ clearTimeout(timeout.current);
15
+ timeout.current = setTimeout(() => {
16
+ if (!loading) {
17
+ return setState(State.IDLE);
18
+ }
19
+ timeout.current = setTimeout(() => {
20
+ setState(State.EXPIRE);
21
+ }, minDuration);
22
+ setState(State.DISPLAY);
23
+ }, delay);
24
+ setState(State.DELAY);
25
+ }
26
+ if (!loading && state !== State.DISPLAY) {
27
+ clearTimeout(timeout.current);
28
+ setState(State.IDLE);
29
+ }
30
+ }, [loading, state, delay, minDuration]);
31
+ useEffect(() => {
32
+ return () => clearTimeout(timeout.current);
33
+ }, []);
34
+ return state === State.DISPLAY || state === State.EXPIRE;
35
+ };
@@ -0,0 +1,16 @@
1
+ import { useEffect, useRef } from "react";
2
+ export let useTraceUpdate = (props) => {
3
+ const prev = useRef(props);
4
+ useEffect(() => {
5
+ const changedProps = Object.entries(props).reduce((ps, [k, v]) => {
6
+ if (prev.current[k] !== v) {
7
+ ps[k] = [prev.current[k], v];
8
+ }
9
+ return ps;
10
+ }, {});
11
+ if (Object.keys(changedProps).length > 0) {
12
+ console.info("[@koine/react:useTraceUpdate] changed props:", changedProps);
13
+ }
14
+ prev.current = props;
15
+ });
16
+ };
@@ -0,0 +1,10 @@
1
+ import { useEffect } from "react";
2
+ import { useFirstMountState } from "./useFirstMountState";
3
+ export let useUpdateEffect = (effect, deps) => {
4
+ const isFirstMount = useFirstMountState();
5
+ useEffect(() => {
6
+ if (!isFirstMount) {
7
+ return effect();
8
+ }
9
+ }, deps);
10
+ };
@@ -0,0 +1,19 @@
1
+ import { useEffect, useState } from "react";
2
+ import { debounce } from "@koine/utils";
3
+ import { listenResize, listenResizeDebounced } from "@koine/dom";
4
+ export let useWindowSize = (wait, immediate) => {
5
+ const [width, widthSet] = useState(0);
6
+ const [height, heightSet] = useState(0);
7
+ useEffect(() => {
8
+ const updateSize = () => {
9
+ widthSet(window.innerWidth);
10
+ heightSet(window.innerHeight);
11
+ };
12
+ const listener = wait
13
+ ? listenResizeDebounced(0, updateSize, wait, immediate)
14
+ : listenResize(updateSize);
15
+ updateSize();
16
+ return listener;
17
+ }, [wait, immediate]);
18
+ return [width, height];
19
+ };
package/index.cjs.js CHANGED
@@ -4,54 +4,64 @@ Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
5
  var react = require('react');
6
6
  var utils = require('@koine/utils');
7
+ var jsxRuntime = require('react/jsx-runtime');
7
8
  var dom = require('@koine/dom');
8
9
 
9
- let useMountedState=()=>{let u=react.useRef(!1),n=react.useCallback(()=>u.current,[]);return react.useEffect(()=>(u.current=!0,()=>{u.current=!1;}),[]),n};
10
+ let classed=r=>{let s=r.type||r;return function(r,...a){return react.forwardRef(function(e,n){let o=a.map((t,s)=>{let a="";return "function"==typeof t?a=t(e):void 0!==t&&(a=t.toString()),r[s]+a}).join(""),l="string"==typeof s,i=l?{}:e;if(l)for(let t in e)t.startsWith("$")||(i[t]=e[t]);let c=o||r[0];return c=(c.match(/class="([^"]*)/)?.[1]||c)+(e?.className?" "+e?.className:""),react.createElement(s,{...i,className:c||void 0,ref:n})})}};
10
11
 
11
- let useAsyncFn=(o,l=[],u={loading:!1})=>{let a=react.useRef(0),i=useMountedState(),[d,c]=react.useState(u),g=react.useCallback((...r)=>{let t=++a.current;return d.loading||c(r=>({...r,loading:!0})),o(...r).then(r=>(i()&&t===a.current&&c({value:r,loading:!1}),r),r=>(i()&&t===a.current&&c({error:r,loading:!1}),r))},l);return [d,g]};
12
+ let useIsomorphicLayoutEffect=utils.isBrowser?react.useLayoutEffect:react.useEffect;
12
13
 
13
- let useFirstMountState=()=>{let t=react.useRef(!0);return t.current?(t.current=!1,!0):t.current};
14
+ let createUseMediaQueryWidth=n=>{let a=utils.getMediaQueryWidthResolvers(n);return function(t,n){let[o,s]=t.substring(1).split("-");utils.isUndefined(s)&&(s=o),utils.isUndefined(o)&&(o="min");let[d,m]=s.split("_"),u=a[o](d,m),[c,l]=react.useState(utils.isUndefined(n)?null:n);return useIsomorphicLayoutEffect(()=>{let e=window.matchMedia(u),t=e=>{l(e.matches);};return (l(e.matches),e.addEventListener)?(e.addEventListener("change",t),()=>{e.removeEventListener("change",t);}):(e.addListener(t),()=>{e.removeListener(t);})},[u]),c}};
14
15
 
15
- let useIsomorphicLayoutEffect=utils.isBrowser?react.useLayoutEffect:react.useEffect;
16
+ let extendComponent=(t,o)=>Object.assign(o=>react.createElement(t,o),{...o,defaultProps:o});
16
17
 
17
- let n$1=e=>{dom.injectCss("useFixedOffset",`html{scroll-padding-top: ${e}px}`);};let useFixedOffset=i=>{let c=react.useRef(0);return useIsomorphicLayoutEffect(()=>{let e=()=>{let e=dom.calculateFixedOffset();c.current=e,n$1(e);};if(e(),!ResizeObserver)return dom.listenResizeDebounced(0,e);{let e=new ResizeObserver(e=>{let r=0;e.forEach(e=>{r+=e.contentRect.height;}),c.current=r,utils.debounce(()=>n$1(r),400,!0)();});return dom.$each(i||"[data-fixed]",t=>{e&&e.observe(t);}),()=>{e?.disconnect();}}},[i]),c};
18
+ let FaviconTags=({name:a,color:t,safariTabColor:o,tileColor:c,themeColor:l})=>jsxRuntime.jsxs(jsxRuntime.Fragment,{children:[jsxRuntime.jsx("link",{rel:"shortcut icon",href:"/favicon.ico",type:"image/x-icon"}),jsxRuntime.jsx("link",{rel:"apple-touch-icon",sizes:"180x180",href:"/apple-touch-icon.png"}),jsxRuntime.jsx("link",{rel:"icon",type:"image/png",sizes:"32x32",href:"/favicon-32x32.png"}),jsxRuntime.jsx("link",{rel:"icon",type:"image/png",sizes:"16x16",href:"/favicon-16x16.png"}),jsxRuntime.jsx("link",{rel:"manifest",href:"/site.webmanifest"}),jsxRuntime.jsx("link",{rel:"mask-icon",href:"/safari-pinned-tab.svg",color:o||t}),jsxRuntime.jsx("meta",{name:"apple-mobile-web-app-title",content:a}),jsxRuntime.jsx("meta",{name:"application-name",content:a}),jsxRuntime.jsx("meta",{name:"msapplication-TileColor",content:c||t}),jsxRuntime.jsx("meta",{name:"theme-color",content:l||t})]});
18
19
 
19
- let useFocus=()=>{let e=react.useRef(null);return [e,()=>{e.current&&e.current.focus();}]};
20
+ let mergeRefs=e=>r=>{e.forEach(e=>{"function"==typeof e?e(r):null!=e&&(e.current=r);});};
20
21
 
21
- let useInterval=(n,l,u=[])=>{let o=react.useRef();react.useEffect(()=>{o.current=n;},[n,...u]),react.useEffect(()=>{if(null!==l){let r=setInterval(function(){o.current&&o.current();},l);return ()=>clearInterval(r)}return utils.noop},[l]);};
22
+ let Meta=({zoom:t})=>jsxRuntime.jsx("meta",{name:"viewport",content:`width=device-width, initial-scale=1, maximum-scale=1${t?"":", user-scalable=0"}`});
22
23
 
23
- let useKeyUp=(o,r=[])=>{react.useEffect(()=>dom.on(window,"keyup",e=>{e.ctrlKey||e.altKey||e.shiftKey||e.metaKey||o(e);}),[o,...r]);};
24
+ let NoJs=t=>jsxRuntime.jsx("script",{id:"no-js",dangerouslySetInnerHTML:{__html:'document.querySelector("html").className=document.querySelector("html").className.replace(/no-js/,"") + "js";'}});
24
25
 
25
- let e$1;let f=e=>{let t=[];if(!e||e===document.body)return t;let{overflow:r,overflowX:n,overflowY:l}=window.getComputedStyle(e);return [r,n,l].some(e=>"auto"===e||"scroll"===e)&&t.push(e),[...t,...f(e.parentElement)]},h=["x","y","top","bottom","left","right","width","height"],p=(e,t)=>h.every(r=>e[r]===t[r]);let useMeasure=h=>{let{scroll:d=!1}=h||{},[a,b]=react.useState({left:0,top:0,width:0,height:0,bottom:0,right:0,x:0,y:0}),g=react.useRef([null,null,null,a]),v=react.useRef(!1);react.useEffect(()=>(v.current=!0,()=>void(v.current=!1)),[]);let[w,,y]=react.useMemo(()=>{let e=(...e)=>{let[t,,,r]=g.current;if(!t)return;let n=t.getBoundingClientRect();Object.freeze(n),v.current&&!p(r,n)&&(g.current[3]=n,b(n));},t=utils.debounce(e);return [e,t,t]},[b]);function x(){let[,e,t]=g.current;e&&(e.forEach(e=>dom.off(e,"scroll",y)),g.current[1]=null),t&&(t.disconnect(),g.current[2]=null);}function z(){let[t,r]=g.current;t&&!e$1&&ResizeObserver&&(e$1=new ResizeObserver(y),g.current[2]=e$1,e$1.observe(t),d&&r&&r.forEach(e=>dom.on(e,"scroll",y,{capture:!0,passive:!0})));}return react.useEffect(()=>d?dom.listenScrollDebounced(0,w,100):utils.noop,[d,w]),react.useEffect(()=>dom.listenResizeDebounced(0,w,100),[w]),react.useEffect(()=>{x(),z();},[d]),react.useEffect(()=>(w(),x),[]),[e=>{e&&e!==g.current[0]&&(x(),g.current[0]=e,g.current[1]=f(e),z());},a,w]};
26
+ let useMountedState=()=>{let u=react.useRef(!1),n=react.useCallback(()=>u.current,[]);return react.useEffect(()=>(u.current=!0,()=>{u.current=!1;}),[]),n};
26
27
 
27
- let useNavigateAway=o=>{let n=react.useRef();react.useEffect(()=>{n.current=e=>{let r=o(e);return (r&&e.preventDefault(),"string"==typeof r)?e.returnValue=r:e.defaultPrevented?e.returnValue="":void 0};},[o]),react.useEffect(()=>dom.on(window,"beforeunload",e=>n.current?.(e)),[]);};
28
+ let useAsyncFn=(o,u=[],l={loading:!1})=>{let a=react.useRef(0),d=useMountedState(),[i,c]=react.useState(l),g=react.useCallback((...e)=>{let t=++a.current;return i.loading||c(e=>({...e,loading:!0})),o(...e).then(e=>(d()&&t===a.current&&c({value:e,loading:!1}),e),e=>(d()&&t===a.current&&c({error:e,loading:!1}),e))},u);return [i,g]};
28
29
 
29
- let usePrevious=(r,t)=>{let[o,u]=react.useState([r,t]);return o[1]!==r&&u([o[1],r]),o[0]};
30
+ let useFirstMountState=()=>{let r=react.useRef(!0);return r.current?(r.current=!1,!0):r.current};
30
31
 
31
- let usePreviousRef=t=>{let u=react.useRef();return react.useEffect(()=>{u.current=t;}),u.current};
32
+ let n$1=e=>{dom.injectCss("useFixedOffset",`html{scroll-padding-top: ${e}px}`);};let useFixedOffset=i=>{let l=react.useRef(0);return useIsomorphicLayoutEffect(()=>{let e=()=>{let e=dom.calculateFixedOffset();l.current=e,n$1(e);};if(e(),!ResizeObserver)return dom.listenResizeDebounced(0,e);{let e=new ResizeObserver(e=>{let r=0;e.forEach(e=>{r+=e.contentRect.height;}),l.current=r,utils.debounce(()=>n$1(r),400,!0)();});return dom.$each(i||"[data-fixed]",t=>{e&&e.observe(t);}),()=>{e?.disconnect();}}},[i]),l};
32
33
 
33
- let l={x:0,y:0},n=r=>r?.getBoundingClientRect(),u=(r,e)=>{if(!utils.isBrowser)return l;if(!e)return {x:window.scrollX,y:window.scrollY};let o=n(r?.current||document.body),u=n(e.current);return o?u?{x:(u.x||0)-(o.x||0),y:(u.y||0)-(o.y||0)}:{x:o.left,y:o.top}:l};let useScrollPosition=(l,n=[],i,c,m)=>{let f=react.useRef(u(null,c)),s=null,y=()=>{let r=u(i,c);l(r,f.current),f.current=r,s=null;};useIsomorphicLayoutEffect(()=>{if(!utils.isBrowser)return;let r=dom.listenScroll(()=>{m?null===s&&(s=window.setTimeout(y,m)):y();},c?.current);return ()=>{r(),s&&clearTimeout(s);}},n);};
34
+ let useFocus=()=>{let r=react.useRef(null);return [r,()=>{r.current&&r.current.focus();}]};
34
35
 
35
- let useScrollThreshold=(i,m)=>{let[n,f]=react.useState(!1),u=react.useCallback(()=>{if(i){let r=window.scrollY,o=r<i,e=r>i;f(e),m&&m(o,e);}},[i,m]);return react.useEffect(()=>{if(i){let r=dom.listenScroll(u);return u(),r}return utils.noop},[i,u]),n};
36
+ let useInterval=(n,l,u=[])=>{let o=react.useRef();react.useEffect(()=>{o.current=n;},[n,...u]),react.useEffect(()=>{if(null!==l){let r=setInterval(function(){o.current&&o.current();},l);return ()=>clearInterval(r)}return utils.noop},[l]);};
36
37
 
37
- let useSmoothScroll=i=>{let l=useFixedOffset();return react.useCallback((e,m,f,n,u)=>{let c;let p=!1;if(utils.isNumber(e))c=e;else if(e){let t=document.getElementById(e);t&&(c=dom.getOffsetTopSlim(t)-l.current,p=!0);}utils.isNumber(c)&&dom.scrollTo(c=c+(m||0)+(i||p?0:l.current),f,n,u);},[i,l])};
38
+ let useKeyUp=(o,r=[])=>{react.useEffect(()=>dom.on(window,"keyup",e=>{e.ctrlKey||e.altKey||e.shiftKey||e.metaKey||o(e);}),[o,...r]);};
38
39
 
39
- var e,r;(r=e||(e={}))[r.IDLE=0]="IDLE",r[r.DELAY=1]="DELAY",r[r.DISPLAY=2]="DISPLAY",r[r.EXPIRE=3]="EXPIRE";let useSpinDelay=(e,r=500,i=200)=>{let[n,o]=react.useState(0),E=react.useRef();return react.useEffect(()=>{e&&0===n&&(clearTimeout(E.current),E.current=setTimeout(()=>{if(!e)return o(0);E.current=setTimeout(()=>{o(3);},i),o(2);},r),o(1)),e||2===n||(clearTimeout(E.current),o(0));},[e,n,r,i]),react.useEffect(()=>()=>clearTimeout(E.current),[]),2===n||3===n};
40
+ let e;let m=e=>{let t=[];if(!e||e===document.body)return t;let{overflow:r,overflowX:n,overflowY:u}=window.getComputedStyle(e);return [r,n,u].some(e=>"auto"===e||"scroll"===e)&&t.push(e),[...t,...m(e.parentElement)]},p=["x","y","top","bottom","left","right","width","height"],d=(e,t)=>p.every(r=>e[r]===t[r]);let useMeasure=p=>{let{scroll:h=!1}=p||{},[a,b]=react.useState({left:0,top:0,width:0,height:0,bottom:0,right:0,x:0,y:0}),g=react.useRef([null,null,null,a]),v=react.useRef(!1);react.useEffect(()=>(v.current=!0,()=>void(v.current=!1)),[]);let[w,,y]=react.useMemo(()=>{let e=(...e)=>{let[t,,,r]=g.current;if(!t)return;let n=t.getBoundingClientRect();Object.freeze(n),v.current&&!d(r,n)&&(g.current[3]=n,b(n));},t=utils.debounce(e);return [e,t,t]},[b]);function x(){let[,e,t]=g.current;e&&(e.forEach(e=>dom.off(e,"scroll",y)),g.current[1]=null),t&&(t.disconnect(),g.current[2]=null);}function z(){let[t,r]=g.current;t&&!e&&ResizeObserver&&(e=new ResizeObserver(y),g.current[2]=e,e.observe(t),h&&r&&r.forEach(e=>dom.on(e,"scroll",y,{capture:!0,passive:!0})));}return react.useEffect(()=>h?dom.listenScrollDebounced(0,w,100):utils.noop,[h,w]),react.useEffect(()=>dom.listenResizeDebounced(0,w,100),[w]),react.useEffect(()=>{x(),z();},[h]),react.useEffect(()=>(w(),x),[]),[e=>{e&&e!==g.current[0]&&(x(),g.current[0]=e,g.current[1]=m(e),z());},a,w]};
40
41
 
41
- let useTraceUpdate=t=>{let c=react.useRef(t);react.useEffect(()=>{let e=Object.entries(t).reduce((e,[r,t])=>(c.current[r]!==t&&(e[r]=[c.current[r],t]),e),{});Object.keys(e).length>0&&console.info("[@koine/react:useTraceUpdate] changed props:",e),c.current=t;});};
42
+ let useNavigateAway=a=>{let o=react.useRef();react.useEffect(()=>{o.current=e=>{let t=a(e);return (t&&e.preventDefault(),"string"==typeof t)?e.returnValue=t:e.defaultPrevented?e.returnValue="":void 0};},[a]),react.useEffect(()=>dom.on(window,"beforeunload",e=>o.current?.(e)),[]);};
42
43
 
43
- let useUpdateEffect=(r,o)=>{let f=useFirstMountState();react.useEffect(()=>{if(!f)return r()},o);};
44
+ let usePrevious=(r,t)=>{let[o,u]=react.useState([r,t]);return o[1]!==r&&u([o[1],r]),o[0]};
44
45
 
45
- let useWindowSize=(n,o)=>{let[d,m]=react.useState(0),[w,l]=react.useState(0);return react.useEffect(()=>{let e=()=>{m(window.innerWidth),l(window.innerHeight);},r=n?dom.listenResizeDebounced(0,e,n,o):dom.listenResize(e);return e(),r},[n,o]),[d,w]};
46
+ let usePreviousRef=t=>{let u=react.useRef();return react.useEffect(()=>{u.current=t;}),u.current};
46
47
 
47
- let classed=r=>{let n=r.type||r;return function(r,...o){return react.forwardRef(function(e,s){let a=o.map((t,n)=>{let o="";return "function"==typeof t?o=t(e):void 0!==t&&(o=t.toString()),r[n]+o}).join(""),i="string"==typeof n,l=i?{}:e;if(i)for(let t in e)t.startsWith("$")||(l[t]=e[t]);let c=a||r[0];return c=(c.match(/class="([^"]*)/)?.[1]||c)+(e?.className?" "+e?.className:""),react.createElement(n,{...l,className:c||void 0,ref:s})})}};
48
+ let l={x:0,y:0},n=t=>t?.getBoundingClientRect(),u=(t,e)=>{if(!utils.isBrowser)return l;if(!e)return {x:window.scrollX,y:window.scrollY};let o=n(t?.current||document.body),u=n(e.current);return o?u?{x:(u.x||0)-(o.x||0),y:(u.y||0)-(o.y||0)}:{x:o.left,y:o.top}:l};let useScrollPosition=(l,n=[],i,c,m)=>{let f=react.useRef(u(null,c)),s=null,d=()=>{let t=u(i,c);l(t,f.current),f.current=t,s=null;};useIsomorphicLayoutEffect(()=>{if(!utils.isBrowser)return;let t=dom.listenScroll(()=>{m?null===s&&(s=window.setTimeout(d,m)):d();},c?.current);return ()=>{t(),s&&clearTimeout(s);}},n);};
48
49
 
49
- let createUseMediaQueryWidth=i=>{let o=utils.getMediaQueryWidthResolvers(i);return function(t,i){let[s,a]=t.substring(1).split("-");utils.isUndefined(a)&&(a=s),utils.isUndefined(s)&&(s="min");let[m,d]=a.split("_"),l=o[s](m,d),[c,u]=react.useState(utils.isUndefined(i)?null:i);return useIsomorphicLayoutEffect(()=>{let e=window.matchMedia(l),t=e=>{u(e.matches);};return (u(e.matches),e.addEventListener)?(e.addEventListener("change",t),()=>{e.removeEventListener("change",t);}):(e.addListener(t),()=>{e.removeListener(t);})},[l]),c}};
50
+ let useScrollThreshold=(i,m)=>{let[u,f]=react.useState(!1),n=react.useCallback(()=>{if(i){let r=window.scrollY,e=r<i,o=r>i;f(o),m&&m(e,o);}},[i,m]);return react.useEffect(()=>{if(i){let r=dom.listenScroll(n);return n(),r}return utils.noop},[i,n]),u};
50
51
 
51
- let extendComponent=(t,o)=>Object.assign(o=>react.createElement(t,o),{...o,defaultProps:o});
52
+ let useSmoothScroll=m=>{let i=useFixedOffset();return react.useCallback((e,l,f,u,n)=>{let c;let p=!1;if(utils.isNumber(e))c=e;else if(e){let t=document.getElementById(e);t&&(c=dom.getOffsetTopSlim(t)-i.current,p=!0);}utils.isNumber(c)&&dom.scrollTo(c=c+(l||0)+(m||p?0:i.current),f,u,n);},[m,i])};
52
53
 
53
- let mergeRefs=e=>r=>{e.forEach(e=>{"function"==typeof e?e(r):null!=e&&(e.current=r);});};
54
+ let useSpinDelay=(u,c=500,i=200)=>{let[n,o]=react.useState(0),l=react.useRef();return react.useEffect(()=>{u&&0===n&&(clearTimeout(l.current),l.current=setTimeout(()=>{if(!u)return o(0);l.current=setTimeout(()=>{o(3);},i),o(2);},c),o(1)),u||2===n||(clearTimeout(l.current),o(0));},[u,n,c,i]),react.useEffect(()=>()=>clearTimeout(l.current),[]),2===n||3===n};
55
+
56
+ let useTraceUpdate=r=>{let c=react.useRef(r);react.useEffect(()=>{let e=Object.entries(r).reduce((e,[t,r])=>(c.current[t]!==r&&(e[t]=[c.current[t],r]),e),{});Object.keys(e).length>0&&console.info("[@koine/react:useTraceUpdate] changed props:",e),c.current=r;});};
57
+
58
+ let useUpdateEffect=(r,f)=>{let o=useFirstMountState();react.useEffect(()=>{if(!o)return r()},f);};
59
+
60
+ let useWindowSize=(o,n)=>{let[d,w]=react.useState(0),[m,u]=react.useState(0);return react.useEffect(()=>{let e=()=>{w(window.innerWidth),u(window.innerHeight);},i=o?dom.listenResizeDebounced(0,e,o,n):dom.listenResize(e);return e(),i},[o,n]),[d,m]};
54
61
 
62
+ exports.FaviconTags = FaviconTags;
63
+ exports.Meta = Meta;
64
+ exports.NoJs = NoJs;
55
65
  exports.classed = classed;
56
66
  exports.createUseMediaQueryWidth = createUseMediaQueryWidth;
57
67
  exports.extendComponent = extendComponent;
package/index.d.ts CHANGED
@@ -1,3 +1,28 @@
1
- export * from "./hooks";
2
- export * from "./utils";
3
- export * from "./types";
1
+ export { classed } from "./classed";
2
+ export { createUseMediaQueryWidth, type MediaQuerWidthDef, type MediaQueryWidth, } from "./createUseMediaQueryWidth";
3
+ export { type ExtendableComponent, type OverridableComponents, type WithComponents, extendComponent, } from "./extendComponent";
4
+ export { FaviconTags, type FaviconTagsProps } from "./FaviconTags";
5
+ export { mergeRefs } from "./mergeRefs";
6
+ export { Meta, type MetaProps } from "./Meta";
7
+ export { NoJs, type NoJsProps } from "./NoJs";
8
+ export type { Polymorphic } from "./Polymorphic";
9
+ export { useAsyncFn, type UseAsyncFnReturn, type UseAsyncState, } from "./useAsyncFn";
10
+ export { useFirstMountState } from "./useFirstMountState";
11
+ export { useFixedOffset } from "./useFixedOffset";
12
+ export { useFocus } from "./useFocus";
13
+ export { useInterval } from "./useInterval";
14
+ export { useIsomorphicLayoutEffect } from "./useIsomorphicLayoutEffect";
15
+ export { useKeyUp } from "./useKeyUp";
16
+ export { useMeasure, type UseMeasureOptions, type UseMeasureReturn, } from "./useMeasure";
17
+ export { useMountedState } from "./useMountedState";
18
+ export { useNavigateAway, type UseNavigateAwayHandler, } from "./useNavigateAway";
19
+ export { usePrevious } from "./usePrevious";
20
+ export { usePreviousRef } from "./usePreviousRef";
21
+ export { useScrollPosition } from "./useScrollPosition";
22
+ export { useScrollThreshold } from "./useScrollThreshold";
23
+ export { useSmoothScroll } from "./useSmoothScroll";
24
+ export { useSpinDelay } from "./useSpinDelay";
25
+ export { useTraceUpdate } from "./useTraceUpdate";
26
+ export { useUpdateEffect } from "./useUpdateEffect";
27
+ export { useWindowSize } from "./useWindowSize";
28
+ export type { KoineComponentProps, KoineComponent } from "./types";
package/index.esm.js CHANGED
@@ -1,51 +1,58 @@
1
- import { useRef, useCallback, useEffect, useState, useLayoutEffect, useMemo, forwardRef, createElement } from 'react';
2
- import { isBrowser, debounce, noop, isNumber, getMediaQueryWidthResolvers, isUndefined } from '@koine/utils';
1
+ import { forwardRef, createElement, useLayoutEffect, useEffect, useState, useRef, useCallback, useMemo } from 'react';
2
+ import { isBrowser, getMediaQueryWidthResolvers, isUndefined, debounce, noop, isNumber } from '@koine/utils';
3
+ import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
3
4
  import { listenResizeDebounced, $each, calculateFixedOffset, injectCss, on, listenScrollDebounced, off, listenScroll, getOffsetTopSlim, scrollTo, listenResize } from '@koine/dom';
4
5
 
5
- let useMountedState=()=>{let u=useRef(!1),n=useCallback(()=>u.current,[]);return useEffect(()=>(u.current=!0,()=>{u.current=!1;}),[]),n};
6
+ let classed=r=>{let s=r.type||r;return function(r,...a){return forwardRef(function(e,n){let o=a.map((t,s)=>{let a="";return "function"==typeof t?a=t(e):void 0!==t&&(a=t.toString()),r[s]+a}).join(""),l="string"==typeof s,i=l?{}:e;if(l)for(let t in e)t.startsWith("$")||(i[t]=e[t]);let c=o||r[0];return c=(c.match(/class="([^"]*)/)?.[1]||c)+(e?.className?" "+e?.className:""),createElement(s,{...i,className:c||void 0,ref:n})})}};
6
7
 
7
- let useAsyncFn=(o,l=[],u={loading:!1})=>{let a=useRef(0),i=useMountedState(),[d,c]=useState(u),g=useCallback((...r)=>{let t=++a.current;return d.loading||c(r=>({...r,loading:!0})),o(...r).then(r=>(i()&&t===a.current&&c({value:r,loading:!1}),r),r=>(i()&&t===a.current&&c({error:r,loading:!1}),r))},l);return [d,g]};
8
+ let useIsomorphicLayoutEffect=isBrowser?useLayoutEffect:useEffect;
8
9
 
9
- let useFirstMountState=()=>{let t=useRef(!0);return t.current?(t.current=!1,!0):t.current};
10
+ let createUseMediaQueryWidth=n=>{let a=getMediaQueryWidthResolvers(n);return function(t,n){let[o,s]=t.substring(1).split("-");isUndefined(s)&&(s=o),isUndefined(o)&&(o="min");let[d,m]=s.split("_"),u=a[o](d,m),[c,l]=useState(isUndefined(n)?null:n);return useIsomorphicLayoutEffect(()=>{let e=window.matchMedia(u),t=e=>{l(e.matches);};return (l(e.matches),e.addEventListener)?(e.addEventListener("change",t),()=>{e.removeEventListener("change",t);}):(e.addListener(t),()=>{e.removeListener(t);})},[u]),c}};
10
11
 
11
- let useIsomorphicLayoutEffect=isBrowser?useLayoutEffect:useEffect;
12
+ let extendComponent=(t,o)=>Object.assign(o=>createElement(t,o),{...o,defaultProps:o});
12
13
 
13
- let n$1=e=>{injectCss("useFixedOffset",`html{scroll-padding-top: ${e}px}`);};let useFixedOffset=i=>{let c=useRef(0);return useIsomorphicLayoutEffect(()=>{let e=()=>{let e=calculateFixedOffset();c.current=e,n$1(e);};if(e(),!ResizeObserver)return listenResizeDebounced(0,e);{let e=new ResizeObserver(e=>{let r=0;e.forEach(e=>{r+=e.contentRect.height;}),c.current=r,debounce(()=>n$1(r),400,!0)();});return $each(i||"[data-fixed]",t=>{e&&e.observe(t);}),()=>{e?.disconnect();}}},[i]),c};
14
+ let FaviconTags=({name:a,color:t,safariTabColor:o,tileColor:c,themeColor:l})=>jsxs(Fragment,{children:[jsx("link",{rel:"shortcut icon",href:"/favicon.ico",type:"image/x-icon"}),jsx("link",{rel:"apple-touch-icon",sizes:"180x180",href:"/apple-touch-icon.png"}),jsx("link",{rel:"icon",type:"image/png",sizes:"32x32",href:"/favicon-32x32.png"}),jsx("link",{rel:"icon",type:"image/png",sizes:"16x16",href:"/favicon-16x16.png"}),jsx("link",{rel:"manifest",href:"/site.webmanifest"}),jsx("link",{rel:"mask-icon",href:"/safari-pinned-tab.svg",color:o||t}),jsx("meta",{name:"apple-mobile-web-app-title",content:a}),jsx("meta",{name:"application-name",content:a}),jsx("meta",{name:"msapplication-TileColor",content:c||t}),jsx("meta",{name:"theme-color",content:l||t})]});
14
15
 
15
- let useFocus=()=>{let e=useRef(null);return [e,()=>{e.current&&e.current.focus();}]};
16
+ let mergeRefs=e=>r=>{e.forEach(e=>{"function"==typeof e?e(r):null!=e&&(e.current=r);});};
16
17
 
17
- let useInterval=(n,l,u=[])=>{let o=useRef();useEffect(()=>{o.current=n;},[n,...u]),useEffect(()=>{if(null!==l){let r=setInterval(function(){o.current&&o.current();},l);return ()=>clearInterval(r)}return noop},[l]);};
18
+ let Meta=({zoom:t})=>jsx("meta",{name:"viewport",content:`width=device-width, initial-scale=1, maximum-scale=1${t?"":", user-scalable=0"}`});
18
19
 
19
- let useKeyUp=(o,r=[])=>{useEffect(()=>on(window,"keyup",e=>{e.ctrlKey||e.altKey||e.shiftKey||e.metaKey||o(e);}),[o,...r]);};
20
+ let NoJs=t=>jsx("script",{id:"no-js",dangerouslySetInnerHTML:{__html:'document.querySelector("html").className=document.querySelector("html").className.replace(/no-js/,"") + "js";'}});
20
21
 
21
- let e$1;let f=e=>{let t=[];if(!e||e===document.body)return t;let{overflow:r,overflowX:n,overflowY:l}=window.getComputedStyle(e);return [r,n,l].some(e=>"auto"===e||"scroll"===e)&&t.push(e),[...t,...f(e.parentElement)]},h=["x","y","top","bottom","left","right","width","height"],p=(e,t)=>h.every(r=>e[r]===t[r]);let useMeasure=h=>{let{scroll:d=!1}=h||{},[a,b]=useState({left:0,top:0,width:0,height:0,bottom:0,right:0,x:0,y:0}),g=useRef([null,null,null,a]),v=useRef(!1);useEffect(()=>(v.current=!0,()=>void(v.current=!1)),[]);let[w,,y]=useMemo(()=>{let e=(...e)=>{let[t,,,r]=g.current;if(!t)return;let n=t.getBoundingClientRect();Object.freeze(n),v.current&&!p(r,n)&&(g.current[3]=n,b(n));},t=debounce(e);return [e,t,t]},[b]);function x(){let[,e,t]=g.current;e&&(e.forEach(e=>off(e,"scroll",y)),g.current[1]=null),t&&(t.disconnect(),g.current[2]=null);}function z(){let[t,r]=g.current;t&&!e$1&&ResizeObserver&&(e$1=new ResizeObserver(y),g.current[2]=e$1,e$1.observe(t),d&&r&&r.forEach(e=>on(e,"scroll",y,{capture:!0,passive:!0})));}return useEffect(()=>d?listenScrollDebounced(0,w,100):noop,[d,w]),useEffect(()=>listenResizeDebounced(0,w,100),[w]),useEffect(()=>{x(),z();},[d]),useEffect(()=>(w(),x),[]),[e=>{e&&e!==g.current[0]&&(x(),g.current[0]=e,g.current[1]=f(e),z());},a,w]};
22
+ let useMountedState=()=>{let u=useRef(!1),n=useCallback(()=>u.current,[]);return useEffect(()=>(u.current=!0,()=>{u.current=!1;}),[]),n};
22
23
 
23
- let useNavigateAway=o=>{let n=useRef();useEffect(()=>{n.current=e=>{let r=o(e);return (r&&e.preventDefault(),"string"==typeof r)?e.returnValue=r:e.defaultPrevented?e.returnValue="":void 0};},[o]),useEffect(()=>on(window,"beforeunload",e=>n.current?.(e)),[]);};
24
+ let useAsyncFn=(o,u=[],l={loading:!1})=>{let a=useRef(0),d=useMountedState(),[i,c]=useState(l),g=useCallback((...e)=>{let t=++a.current;return i.loading||c(e=>({...e,loading:!0})),o(...e).then(e=>(d()&&t===a.current&&c({value:e,loading:!1}),e),e=>(d()&&t===a.current&&c({error:e,loading:!1}),e))},u);return [i,g]};
24
25
 
25
- let usePrevious=(r,t)=>{let[o,u]=useState([r,t]);return o[1]!==r&&u([o[1],r]),o[0]};
26
+ let useFirstMountState=()=>{let r=useRef(!0);return r.current?(r.current=!1,!0):r.current};
26
27
 
27
- let usePreviousRef=t=>{let u=useRef();return useEffect(()=>{u.current=t;}),u.current};
28
+ let n$1=e=>{injectCss("useFixedOffset",`html{scroll-padding-top: ${e}px}`);};let useFixedOffset=i=>{let l=useRef(0);return useIsomorphicLayoutEffect(()=>{let e=()=>{let e=calculateFixedOffset();l.current=e,n$1(e);};if(e(),!ResizeObserver)return listenResizeDebounced(0,e);{let e=new ResizeObserver(e=>{let r=0;e.forEach(e=>{r+=e.contentRect.height;}),l.current=r,debounce(()=>n$1(r),400,!0)();});return $each(i||"[data-fixed]",t=>{e&&e.observe(t);}),()=>{e?.disconnect();}}},[i]),l};
28
29
 
29
- let l={x:0,y:0},n=r=>r?.getBoundingClientRect(),u=(r,e)=>{if(!isBrowser)return l;if(!e)return {x:window.scrollX,y:window.scrollY};let o=n(r?.current||document.body),u=n(e.current);return o?u?{x:(u.x||0)-(o.x||0),y:(u.y||0)-(o.y||0)}:{x:o.left,y:o.top}:l};let useScrollPosition=(l,n=[],i,c,m)=>{let f=useRef(u(null,c)),s=null,y=()=>{let r=u(i,c);l(r,f.current),f.current=r,s=null;};useIsomorphicLayoutEffect(()=>{if(!isBrowser)return;let r=listenScroll(()=>{m?null===s&&(s=window.setTimeout(y,m)):y();},c?.current);return ()=>{r(),s&&clearTimeout(s);}},n);};
30
+ let useFocus=()=>{let r=useRef(null);return [r,()=>{r.current&&r.current.focus();}]};
30
31
 
31
- let useScrollThreshold=(i,m)=>{let[n,f]=useState(!1),u=useCallback(()=>{if(i){let r=window.scrollY,o=r<i,e=r>i;f(e),m&&m(o,e);}},[i,m]);return useEffect(()=>{if(i){let r=listenScroll(u);return u(),r}return noop},[i,u]),n};
32
+ let useInterval=(n,l,u=[])=>{let o=useRef();useEffect(()=>{o.current=n;},[n,...u]),useEffect(()=>{if(null!==l){let r=setInterval(function(){o.current&&o.current();},l);return ()=>clearInterval(r)}return noop},[l]);};
32
33
 
33
- let useSmoothScroll=i=>{let l=useFixedOffset();return useCallback((e,m,f,n,u)=>{let c;let p=!1;if(isNumber(e))c=e;else if(e){let t=document.getElementById(e);t&&(c=getOffsetTopSlim(t)-l.current,p=!0);}isNumber(c)&&scrollTo(c=c+(m||0)+(i||p?0:l.current),f,n,u);},[i,l])};
34
+ let useKeyUp=(o,r=[])=>{useEffect(()=>on(window,"keyup",e=>{e.ctrlKey||e.altKey||e.shiftKey||e.metaKey||o(e);}),[o,...r]);};
34
35
 
35
- var e,r;(r=e||(e={}))[r.IDLE=0]="IDLE",r[r.DELAY=1]="DELAY",r[r.DISPLAY=2]="DISPLAY",r[r.EXPIRE=3]="EXPIRE";let useSpinDelay=(e,r=500,i=200)=>{let[n,o]=useState(0),E=useRef();return useEffect(()=>{e&&0===n&&(clearTimeout(E.current),E.current=setTimeout(()=>{if(!e)return o(0);E.current=setTimeout(()=>{o(3);},i),o(2);},r),o(1)),e||2===n||(clearTimeout(E.current),o(0));},[e,n,r,i]),useEffect(()=>()=>clearTimeout(E.current),[]),2===n||3===n};
36
+ let e;let m=e=>{let t=[];if(!e||e===document.body)return t;let{overflow:r,overflowX:n,overflowY:u}=window.getComputedStyle(e);return [r,n,u].some(e=>"auto"===e||"scroll"===e)&&t.push(e),[...t,...m(e.parentElement)]},p=["x","y","top","bottom","left","right","width","height"],d=(e,t)=>p.every(r=>e[r]===t[r]);let useMeasure=p=>{let{scroll:h=!1}=p||{},[a,b]=useState({left:0,top:0,width:0,height:0,bottom:0,right:0,x:0,y:0}),g=useRef([null,null,null,a]),v=useRef(!1);useEffect(()=>(v.current=!0,()=>void(v.current=!1)),[]);let[w,,y]=useMemo(()=>{let e=(...e)=>{let[t,,,r]=g.current;if(!t)return;let n=t.getBoundingClientRect();Object.freeze(n),v.current&&!d(r,n)&&(g.current[3]=n,b(n));},t=debounce(e);return [e,t,t]},[b]);function x(){let[,e,t]=g.current;e&&(e.forEach(e=>off(e,"scroll",y)),g.current[1]=null),t&&(t.disconnect(),g.current[2]=null);}function z(){let[t,r]=g.current;t&&!e&&ResizeObserver&&(e=new ResizeObserver(y),g.current[2]=e,e.observe(t),h&&r&&r.forEach(e=>on(e,"scroll",y,{capture:!0,passive:!0})));}return useEffect(()=>h?listenScrollDebounced(0,w,100):noop,[h,w]),useEffect(()=>listenResizeDebounced(0,w,100),[w]),useEffect(()=>{x(),z();},[h]),useEffect(()=>(w(),x),[]),[e=>{e&&e!==g.current[0]&&(x(),g.current[0]=e,g.current[1]=m(e),z());},a,w]};
36
37
 
37
- let useTraceUpdate=t=>{let c=useRef(t);useEffect(()=>{let e=Object.entries(t).reduce((e,[r,t])=>(c.current[r]!==t&&(e[r]=[c.current[r],t]),e),{});Object.keys(e).length>0&&console.info("[@koine/react:useTraceUpdate] changed props:",e),c.current=t;});};
38
+ let useNavigateAway=a=>{let o=useRef();useEffect(()=>{o.current=e=>{let t=a(e);return (t&&e.preventDefault(),"string"==typeof t)?e.returnValue=t:e.defaultPrevented?e.returnValue="":void 0};},[a]),useEffect(()=>on(window,"beforeunload",e=>o.current?.(e)),[]);};
38
39
 
39
- let useUpdateEffect=(r,o)=>{let f=useFirstMountState();useEffect(()=>{if(!f)return r()},o);};
40
+ let usePrevious=(r,t)=>{let[o,u]=useState([r,t]);return o[1]!==r&&u([o[1],r]),o[0]};
40
41
 
41
- let useWindowSize=(n,o)=>{let[d,m]=useState(0),[w,l]=useState(0);return useEffect(()=>{let e=()=>{m(window.innerWidth),l(window.innerHeight);},r=n?listenResizeDebounced(0,e,n,o):listenResize(e);return e(),r},[n,o]),[d,w]};
42
+ let usePreviousRef=t=>{let u=useRef();return useEffect(()=>{u.current=t;}),u.current};
42
43
 
43
- let classed=r=>{let n=r.type||r;return function(r,...o){return forwardRef(function(e,s){let a=o.map((t,n)=>{let o="";return "function"==typeof t?o=t(e):void 0!==t&&(o=t.toString()),r[n]+o}).join(""),i="string"==typeof n,l=i?{}:e;if(i)for(let t in e)t.startsWith("$")||(l[t]=e[t]);let c=a||r[0];return c=(c.match(/class="([^"]*)/)?.[1]||c)+(e?.className?" "+e?.className:""),createElement(n,{...l,className:c||void 0,ref:s})})}};
44
+ let l={x:0,y:0},n=t=>t?.getBoundingClientRect(),u=(t,e)=>{if(!isBrowser)return l;if(!e)return {x:window.scrollX,y:window.scrollY};let o=n(t?.current||document.body),u=n(e.current);return o?u?{x:(u.x||0)-(o.x||0),y:(u.y||0)-(o.y||0)}:{x:o.left,y:o.top}:l};let useScrollPosition=(l,n=[],i,c,m)=>{let f=useRef(u(null,c)),s=null,d=()=>{let t=u(i,c);l(t,f.current),f.current=t,s=null;};useIsomorphicLayoutEffect(()=>{if(!isBrowser)return;let t=listenScroll(()=>{m?null===s&&(s=window.setTimeout(d,m)):d();},c?.current);return ()=>{t(),s&&clearTimeout(s);}},n);};
44
45
 
45
- let createUseMediaQueryWidth=i=>{let o=getMediaQueryWidthResolvers(i);return function(t,i){let[s,a]=t.substring(1).split("-");isUndefined(a)&&(a=s),isUndefined(s)&&(s="min");let[m,d]=a.split("_"),l=o[s](m,d),[c,u]=useState(isUndefined(i)?null:i);return useIsomorphicLayoutEffect(()=>{let e=window.matchMedia(l),t=e=>{u(e.matches);};return (u(e.matches),e.addEventListener)?(e.addEventListener("change",t),()=>{e.removeEventListener("change",t);}):(e.addListener(t),()=>{e.removeListener(t);})},[l]),c}};
46
+ let useScrollThreshold=(i,m)=>{let[u,f]=useState(!1),n=useCallback(()=>{if(i){let r=window.scrollY,e=r<i,o=r>i;f(o),m&&m(e,o);}},[i,m]);return useEffect(()=>{if(i){let r=listenScroll(n);return n(),r}return noop},[i,n]),u};
46
47
 
47
- let extendComponent=(t,o)=>Object.assign(o=>createElement(t,o),{...o,defaultProps:o});
48
+ let useSmoothScroll=m=>{let i=useFixedOffset();return useCallback((e,l,f,u,n)=>{let c;let p=!1;if(isNumber(e))c=e;else if(e){let t=document.getElementById(e);t&&(c=getOffsetTopSlim(t)-i.current,p=!0);}isNumber(c)&&scrollTo(c=c+(l||0)+(m||p?0:i.current),f,u,n);},[m,i])};
48
49
 
49
- let mergeRefs=e=>r=>{e.forEach(e=>{"function"==typeof e?e(r):null!=e&&(e.current=r);});};
50
+ let useSpinDelay=(u,c=500,i=200)=>{let[n,o]=useState(0),l=useRef();return useEffect(()=>{u&&0===n&&(clearTimeout(l.current),l.current=setTimeout(()=>{if(!u)return o(0);l.current=setTimeout(()=>{o(3);},i),o(2);},c),o(1)),u||2===n||(clearTimeout(l.current),o(0));},[u,n,c,i]),useEffect(()=>()=>clearTimeout(l.current),[]),2===n||3===n};
51
+
52
+ let useTraceUpdate=r=>{let c=useRef(r);useEffect(()=>{let e=Object.entries(r).reduce((e,[t,r])=>(c.current[t]!==r&&(e[t]=[c.current[t],r]),e),{});Object.keys(e).length>0&&console.info("[@koine/react:useTraceUpdate] changed props:",e),c.current=r;});};
53
+
54
+ let useUpdateEffect=(r,f)=>{let o=useFirstMountState();useEffect(()=>{if(!o)return r()},f);};
55
+
56
+ let useWindowSize=(o,n)=>{let[d,w]=useState(0),[m,u]=useState(0);return useEffect(()=>{let e=()=>{w(window.innerWidth),u(window.innerHeight);},i=o?listenResizeDebounced(0,e,o,n):listenResize(e);return e(),i},[o,n]),[d,m]};
50
57
 
51
- export { classed, createUseMediaQueryWidth, extendComponent, mergeRefs, useAsyncFn, useFirstMountState, useFixedOffset, useFocus, useInterval, useIsomorphicLayoutEffect, useKeyUp, useMeasure, useMountedState, useNavigateAway, usePrevious, usePreviousRef, useScrollPosition, useScrollThreshold, useSmoothScroll, useSpinDelay, useTraceUpdate, useUpdateEffect, useWindowSize };
58
+ export { FaviconTags, Meta, NoJs, classed, createUseMediaQueryWidth, extendComponent, mergeRefs, useAsyncFn, useFirstMountState, useFixedOffset, useFocus, useInterval, useIsomorphicLayoutEffect, useKeyUp, useMeasure, useMountedState, useNavigateAway, usePrevious, usePreviousRef, useScrollPosition, useScrollThreshold, useSmoothScroll, useSpinDelay, useTraceUpdate, useUpdateEffect, useWindowSize };
package/index.js ADDED
@@ -0,0 +1,26 @@
1
+ export { classed } from "./classed";
2
+ export { createUseMediaQueryWidth, } from "./createUseMediaQueryWidth";
3
+ export { extendComponent, } from "./extendComponent";
4
+ export { FaviconTags } from "./FaviconTags";
5
+ export { mergeRefs } from "./mergeRefs";
6
+ export { Meta } from "./Meta";
7
+ export { NoJs } from "./NoJs";
8
+ export { useAsyncFn, } from "./useAsyncFn";
9
+ export { useFirstMountState } from "./useFirstMountState";
10
+ export { useFixedOffset } from "./useFixedOffset";
11
+ export { useFocus } from "./useFocus";
12
+ export { useInterval } from "./useInterval";
13
+ export { useIsomorphicLayoutEffect } from "./useIsomorphicLayoutEffect";
14
+ export { useKeyUp } from "./useKeyUp";
15
+ export { useMeasure, } from "./useMeasure";
16
+ export { useMountedState } from "./useMountedState";
17
+ export { useNavigateAway, } from "./useNavigateAway";
18
+ export { usePrevious } from "./usePrevious";
19
+ export { usePreviousRef } from "./usePreviousRef";
20
+ export { useScrollPosition } from "./useScrollPosition";
21
+ export { useScrollThreshold } from "./useScrollThreshold";
22
+ export { useSmoothScroll } from "./useSmoothScroll";
23
+ export { useSpinDelay } from "./useSpinDelay";
24
+ export { useTraceUpdate } from "./useTraceUpdate";
25
+ export { useUpdateEffect } from "./useUpdateEffect";
26
+ export { useWindowSize } from "./useWindowSize";
package/mergeRefs.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ export declare let mergeRefs: <T = Element>(refs: (import("react").MutableRefObject<T> | import("react").LegacyRef<T>)[]) => (instance: T | null) => void;
2
+ export default mergeRefs;
package/mergeRefs.js ADDED
@@ -0,0 +1,13 @@
1
+ export let mergeRefs = (refs) => {
2
+ return (value) => {
3
+ refs.forEach((ref) => {
4
+ if (typeof ref === "function") {
5
+ ref(value);
6
+ }
7
+ else if (ref != null) {
8
+ ref.current = value;
9
+ }
10
+ });
11
+ };
12
+ };
13
+ export default mergeRefs;
package/package.json CHANGED
@@ -2,8 +2,8 @@
2
2
  "name": "@koine/react",
3
3
  "sideEffects": false,
4
4
  "dependencies": {
5
- "@koine/dom": "2.0.0-beta.72",
6
- "@koine/utils": "2.0.0-beta.72"
5
+ "@koine/dom": "2.0.0-beta.74",
6
+ "@koine/utils": "2.0.0-beta.74"
7
7
  },
8
8
  "peerDependencies": {
9
9
  "@kuus/yup": "1.0.0-beta.7",
@@ -45,5 +45,5 @@
45
45
  },
46
46
  "module": "./index.esm.js",
47
47
  "main": "./index.cjs.js",
48
- "version": "2.0.0-beta.72"
48
+ "version": "2.0.0-beta.74"
49
49
  }
package/types.js ADDED
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,24 @@
1
+ import React from "react";
2
+ type PromiseType<P extends Promise<any>> = P extends Promise<infer T> ? T : never;
3
+ type FunctionReturningPromise = (...args: any[]) => Promise<any>;
4
+ export type UseAsyncState<T> = {
5
+ loading: boolean;
6
+ error?: undefined;
7
+ value?: undefined;
8
+ } | {
9
+ loading: true;
10
+ error?: Error | undefined;
11
+ value?: T;
12
+ } | {
13
+ loading: false;
14
+ error: Error;
15
+ value?: undefined;
16
+ } | {
17
+ loading: false;
18
+ error?: undefined;
19
+ value: T;
20
+ };
21
+ type StateFromFunctionReturningPromise<T extends FunctionReturningPromise> = UseAsyncState<PromiseType<ReturnType<T>>>;
22
+ export type UseAsyncFnReturn<T extends FunctionReturningPromise = FunctionReturningPromise> = [StateFromFunctionReturningPromise<T>, T];
23
+ export declare let useAsyncFn: <T extends FunctionReturningPromise>(fn: T, deps?: React.DependencyList, initialState?: StateFromFunctionReturningPromise<T>) => UseAsyncFnReturn<T>;
24
+ export default useAsyncFn;
package/useAsyncFn.js ADDED
@@ -0,0 +1,26 @@
1
+ import React, { useCallback, useRef, useState } from "react";
2
+ import { useMountedState } from "./useMountedState";
3
+ export let useAsyncFn = (fn, deps = [], initialState = { loading: false }) => {
4
+ const lastCallId = useRef(0);
5
+ const isMounted = useMountedState();
6
+ const [state, set] = useState(initialState);
7
+ const callback = useCallback((...args) => {
8
+ const callId = ++lastCallId.current;
9
+ if (!state.loading) {
10
+ set((prevState) => ({ ...prevState, loading: true }));
11
+ }
12
+ return fn(...args).then((value) => {
13
+ isMounted() &&
14
+ callId === lastCallId.current &&
15
+ set({ value, loading: false });
16
+ return value;
17
+ }, (error) => {
18
+ isMounted() &&
19
+ callId === lastCallId.current &&
20
+ set({ error, loading: false });
21
+ return error;
22
+ });
23
+ }, deps);
24
+ return [state, callback];
25
+ };
26
+ export default useAsyncFn;
@@ -0,0 +1,2 @@
1
+ export declare let useFirstMountState: () => boolean;
2
+ export default useFirstMountState;
@@ -0,0 +1,10 @@
1
+ import { useRef } from "react";
2
+ export let useFirstMountState = () => {
3
+ const isFirst = useRef(true);
4
+ if (isFirst.current) {
5
+ isFirst.current = false;
6
+ return true;
7
+ }
8
+ return isFirst.current;
9
+ };
10
+ export default useFirstMountState;
@@ -0,0 +1,2 @@
1
+ export declare let useFixedOffset: (selector?: string) => import("react").MutableRefObject<number>;
2
+ export default useFixedOffset;
@@ -0,0 +1,42 @@
1
+ import { useRef } from "react";
2
+ import { debounce } from "@koine/utils";
3
+ import { $each, calculateFixedOffset, injectCss, listenResizeDebounced, } from "@koine/dom";
4
+ import { useIsomorphicLayoutEffect } from "./useIsomorphicLayoutEffect";
5
+ const inject = (value) => {
6
+ injectCss("useFixedOffset", `html{scroll-padding-top: ${value}px}`);
7
+ };
8
+ export let useFixedOffset = (selector) => {
9
+ const fixedOffset = useRef(0);
10
+ useIsomorphicLayoutEffect(() => {
11
+ const update = () => {
12
+ const newFixedOffset = calculateFixedOffset();
13
+ fixedOffset.current = newFixedOffset;
14
+ inject(newFixedOffset);
15
+ };
16
+ update();
17
+ if (ResizeObserver) {
18
+ const observer = new ResizeObserver((entries) => {
19
+ let newFixedOffset = 0;
20
+ entries.forEach((entry) => {
21
+ newFixedOffset += entry.contentRect.height;
22
+ });
23
+ fixedOffset.current = newFixedOffset;
24
+ const updateOnResize = debounce(() => inject(newFixedOffset), 400, true);
25
+ updateOnResize();
26
+ });
27
+ $each(selector || "[data-fixed]", ($el) => {
28
+ if (observer)
29
+ observer.observe($el);
30
+ });
31
+ return () => {
32
+ observer?.disconnect();
33
+ };
34
+ }
35
+ else {
36
+ const listener = listenResizeDebounced(0, update);
37
+ return listener;
38
+ }
39
+ }, [selector]);
40
+ return fixedOffset;
41
+ };
42
+ export default useFixedOffset;
package/useFocus.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ export declare let useFocus: () => (import("react").RefObject<HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement> | (() => void))[];
2
+ export default useFocus;
package/useFocus.js ADDED
@@ -0,0 +1,9 @@
1
+ import { useRef } from "react";
2
+ export let useFocus = () => {
3
+ const elementRef = useRef(null);
4
+ const setFocus = () => {
5
+ elementRef.current && elementRef.current.focus();
6
+ };
7
+ return [elementRef, setFocus];
8
+ };
9
+ export default useFocus;
@@ -0,0 +1,2 @@
1
+ export declare let useInterval: <T extends () => unknown>(callback: T, delay: number, deps?: unknown[]) => void;
2
+ export default useInterval;