@rpcbase/client 0.283.0 → 0.285.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. package/dist/RootProvider/index.d.ts +7 -0
  2. package/dist/RootProvider/index.d.ts.map +1 -0
  3. package/dist/RootProvider/index.js +8 -0
  4. package/dist/apiClient/getServerApiClient.d.ts +10 -0
  5. package/dist/apiClient/getServerApiClient.d.ts.map +1 -0
  6. package/dist/apiClient/getServerApiClient.js +97 -0
  7. package/dist/apiClient/index.d.ts +16 -0
  8. package/dist/apiClient/index.d.ts.map +1 -0
  9. package/dist/apiClient/index.js +50 -0
  10. package/dist/cleanupURL.d.ts +2 -0
  11. package/dist/cleanupURL.d.ts.map +1 -0
  12. package/dist/cleanupURL.js +37 -0
  13. package/dist/getFeatureFlag.d.ts +2 -0
  14. package/dist/getFeatureFlag.d.ts.map +1 -0
  15. package/dist/getFeatureFlag.js +43 -0
  16. package/dist/hooks/index.d.ts +3 -0
  17. package/dist/hooks/index.d.ts.map +1 -0
  18. package/dist/hooks/index.js +2 -0
  19. package/dist/hooks/useMediaQuery.d.ts +2 -0
  20. package/dist/hooks/useMediaQuery.d.ts.map +1 -0
  21. package/dist/hooks/useMediaQuery.js +24 -0
  22. package/dist/hooks/useThrottledMeasure.d.ts +11 -0
  23. package/dist/hooks/useThrottledMeasure.d.ts.map +1 -0
  24. package/dist/hooks/useThrottledMeasure.js +32 -0
  25. package/dist/hooks.d.ts +2 -0
  26. package/dist/hooks.d.ts.map +1 -0
  27. package/dist/hooks.js +1 -0
  28. package/dist/index.d.ts +6 -0
  29. package/dist/index.d.ts.map +1 -0
  30. package/dist/index.js +5 -0
  31. package/dist/initWithRoutes.d.ts +8 -0
  32. package/dist/initWithRoutes.d.ts.map +1 -0
  33. package/dist/initWithRoutes.js +80 -0
  34. package/dist/instrument.d.ts +2 -0
  35. package/dist/instrument.d.ts.map +1 -0
  36. package/dist/instrument.js +29 -0
  37. package/dist/types.d.ts +8 -0
  38. package/dist/types.d.ts.map +1 -0
  39. package/dist/types.js +1 -0
  40. package/dist/utils/useApplyScroll.d.ts +2 -0
  41. package/dist/utils/useApplyScroll.d.ts.map +1 -0
  42. package/dist/utils/useApplyScroll.js +138 -0
  43. package/package.json +27 -7
  44. package/hooks.ts +0 -1
  45. package/instrument.ts +0 -32
  46. package/src/RootProvider/index.tsx +0 -15
  47. package/src/apiClient/getServerApiClient.ts +0 -133
  48. package/src/apiClient/index.ts +0 -86
  49. package/src/cleanupURL.ts +0 -46
  50. package/src/getFeatureFlag.ts +0 -58
  51. package/src/hooks/index.ts +0 -2
  52. package/src/hooks/useMediaQuery.ts +0 -31
  53. package/src/hooks/useThrottledMeasure.ts +0 -49
  54. package/src/index.ts +0 -5
  55. package/src/initWithRoutes.tsx +0 -115
  56. package/src/types.ts +0 -8
  57. package/src/utils/useApplyScroll.ts +0 -169
@@ -0,0 +1,138 @@
1
+ import { useCallback, useEffect, useRef } from "react";
2
+ import { useLocation } from "@rpcbase/router";
3
+ function throttle(callback, limit) {
4
+ let wait = false;
5
+ return (...args) => {
6
+ if (!wait) {
7
+ callback(...args);
8
+ wait = true;
9
+ setTimeout(() => {
10
+ wait = false;
11
+ }, limit);
12
+ }
13
+ };
14
+ }
15
+ export function useApplyScroll() {
16
+ const location = useLocation();
17
+ const previousPathRef = useRef(location.pathname);
18
+ const isScrollingProgrammatically = useRef(false);
19
+ const scrollTimeoutRef = useRef(null);
20
+ const lastAppliedHashRef = useRef("");
21
+ useEffect(() => {
22
+ if (typeof window !== "undefined") {
23
+ lastAppliedHashRef.current = window.location.hash || "";
24
+ }
25
+ }, []);
26
+ useEffect(() => {
27
+ lastAppliedHashRef.current = location.hash || "";
28
+ }, [location.hash]);
29
+ const replaceHashSilently = useCallback((hash) => {
30
+ if (typeof window === "undefined") {
31
+ return;
32
+ }
33
+ if (lastAppliedHashRef.current === hash) {
34
+ return;
35
+ }
36
+ const base = `${window.location.pathname}${window.location.search}`;
37
+ window.history.replaceState(window.history.state, "", `${base}${hash}`);
38
+ lastAppliedHashRef.current = hash;
39
+ }, []);
40
+ const markProgrammaticScroll = useCallback(() => {
41
+ isScrollingProgrammatically.current = true;
42
+ if (scrollTimeoutRef.current) {
43
+ clearTimeout(scrollTimeoutRef.current);
44
+ }
45
+ scrollTimeoutRef.current = setTimeout(() => {
46
+ isScrollingProgrammatically.current = false;
47
+ }, 1000);
48
+ }, []);
49
+ useEffect(() => {
50
+ const pathChanged = previousPathRef.current !== location.pathname;
51
+ if (pathChanged) {
52
+ previousPathRef.current = location.pathname;
53
+ if (!location.hash) {
54
+ window.scrollTo({ top: 0, left: 0, behavior: "auto" });
55
+ return;
56
+ }
57
+ setTimeout(() => {
58
+ const id = location.hash.substring(1);
59
+ const element = document.getElementById(id);
60
+ if (element) {
61
+ markProgrammaticScroll();
62
+ element.scrollIntoView({ behavior: "smooth" });
63
+ }
64
+ }, 100);
65
+ return;
66
+ }
67
+ if (!location.hash) {
68
+ return;
69
+ }
70
+ const id = location.hash.substring(1);
71
+ const element = document.getElementById(id);
72
+ if (element) {
73
+ markProgrammaticScroll();
74
+ element.scrollIntoView({ behavior: "smooth" });
75
+ }
76
+ }, [location.hash, location.pathname, markProgrammaticScroll]);
77
+ useEffect(() => {
78
+ if (typeof window === "undefined") {
79
+ return;
80
+ }
81
+ const handleScroll = throttle(() => {
82
+ if (isScrollingProgrammatically.current) {
83
+ return;
84
+ }
85
+ const sections = Array.from(document.querySelectorAll("section[id]"));
86
+ if (sections.length === 0) {
87
+ replaceHashSilently("");
88
+ return;
89
+ }
90
+ const scrollPosition = window.scrollY;
91
+ const viewportHeight = window.innerHeight;
92
+ const checkPoint = scrollPosition + viewportHeight / 3;
93
+ let activeSectionId = null;
94
+ for (const section of sections) {
95
+ if (section.offsetTop <= checkPoint &&
96
+ section.offsetTop + section.offsetHeight > checkPoint) {
97
+ activeSectionId = section.id;
98
+ break;
99
+ }
100
+ }
101
+ const newHash = activeSectionId ? `#${activeSectionId}` : "";
102
+ replaceHashSilently(newHash);
103
+ }, 150);
104
+ document.addEventListener("scroll", handleScroll);
105
+ return () => {
106
+ document.removeEventListener("scroll", handleScroll);
107
+ if (scrollTimeoutRef.current) {
108
+ clearTimeout(scrollTimeoutRef.current);
109
+ scrollTimeoutRef.current = null;
110
+ }
111
+ };
112
+ }, [replaceHashSilently]);
113
+ useEffect(() => {
114
+ const handleClick = (event) => {
115
+ const target = event.target;
116
+ const link = target?.closest("a");
117
+ const currentHash = typeof window !== "undefined"
118
+ ? window.location.hash
119
+ : location.hash || "";
120
+ if (!link ||
121
+ !link.hash ||
122
+ link.pathname !== location.pathname ||
123
+ link.hash !== currentHash) {
124
+ return;
125
+ }
126
+ const id = link.hash.substring(1);
127
+ const element = document.getElementById(id);
128
+ if (element) {
129
+ event.preventDefault();
130
+ event.stopPropagation();
131
+ markProgrammaticScroll();
132
+ element.scrollIntoView({ behavior: "smooth" });
133
+ }
134
+ };
135
+ document.addEventListener("click", handleClick, true);
136
+ return () => document.removeEventListener("click", handleClick, true);
137
+ }, [location.hash, location.pathname, markProgrammaticScroll]);
138
+ }
package/package.json CHANGED
@@ -1,20 +1,40 @@
1
1
  {
2
2
  "name": "@rpcbase/client",
3
- "version": "0.283.0",
3
+ "version": "0.285.0",
4
4
  "type": "module",
5
- "main": "./src/index.ts",
5
+ "files": [
6
+ "dist"
7
+ ],
8
+ "main": "./dist/index.js",
9
+ "types": "./dist/index.d.ts",
6
10
  "scripts": {
7
- "build": "tsc --watch",
11
+ "build": "wireit",
8
12
  "release": "wireit"
9
13
  },
10
14
  "wireit": {
15
+ "build": {
16
+ "command": "node ../../scripts/build-package.js client",
17
+ "files": [
18
+ "src/**/*",
19
+ "hooks.ts",
20
+ "instrument.ts",
21
+ "../../tsconfig.json",
22
+ "../../tsconfig.base.json",
23
+ "../../scripts/build-package.js"
24
+ ],
25
+ "output": [
26
+ "dist/"
27
+ ]
28
+ },
11
29
  "release": {
12
30
  "command": "../../scripts/publish.js",
13
- "dependencies": [],
31
+ "dependencies": [
32
+ "build"
33
+ ],
14
34
  "files": [
15
35
  "package.json",
16
- "./instrument.ts",
17
- "./hooks.ts",
36
+ "hooks.ts",
37
+ "instrument.ts",
18
38
  "src/**/*"
19
39
  ],
20
40
  "output": [],
@@ -27,7 +47,7 @@
27
47
  },
28
48
  "peerDependencies": {},
29
49
  "dependencies": {
30
- "axios": "1.9.0",
50
+ "axios": "1.13.2",
31
51
  "fast-equals": "5.2.2",
32
52
  "lodash": "4.17.21",
33
53
  "react-use": "17.6.0"
package/hooks.ts DELETED
@@ -1 +0,0 @@
1
- export * from "./src/hooks"
package/instrument.ts DELETED
@@ -1,32 +0,0 @@
1
- import posthog from "posthog-js"
2
-
3
-
4
- const isProduction = import.meta.env.MODE === "production"
5
-
6
-
7
- if (isProduction) {
8
- if (import.meta.env.RB_PUBLIC_POSTHOG_KEY) {
9
- posthog.init(import.meta.env.RB_PUBLIC_POSTHOG_KEY, {
10
- api_host: "/ingest",
11
- ui_host: "https://eu.posthog.com",
12
- person_profiles: "always",
13
- session_recording: {
14
- maskAllInputs: false
15
- },
16
- capture_pageview: isProduction,
17
- capture_exceptions: {
18
- capture_unhandled_errors: true,
19
- capture_unhandled_rejections: true,
20
- capture_console_errors: true,
21
- },
22
- autocapture: isProduction,
23
- disable_session_recording: !isProduction,
24
- })
25
- } else {
26
- console.warn("missing POSTHOG_KEY")
27
- }
28
-
29
-
30
- } else {
31
- console.info("ℹ️ Not initializing posthog in development")
32
- }
@@ -1,15 +0,0 @@
1
- import posthog from "posthog-js"
2
- import { PostHogProvider } from "posthog-js/react"
3
-
4
- import { useApplyScroll } from "../utils/useApplyScroll"
5
-
6
-
7
- export const RootProvider = ({children}) => {
8
- useApplyScroll()
9
-
10
- return (
11
- <PostHogProvider client={posthog}>
12
- {children}
13
- </PostHogProvider>
14
- )
15
- }
@@ -1,133 +0,0 @@
1
- /* eslint-disable @typescript-eslint/no-explicit-any */
2
- import { Application, IRouter, Request, Response } from "express"
3
-
4
- // import { Ctx } from "@rpcbase/api"
5
- type Ctx = any
6
-
7
-
8
- export const getServerApiClient = async(app: Application) => {
9
- const callRoute = async <TResponse = Record<string, unknown>>(
10
- app: Application,
11
- method: string,
12
- path: string,
13
- req: Partial<Request>,
14
- res: Partial<Response>
15
- ): Promise<TResponse> => {
16
- return new Promise((resolve, reject) => {
17
- let isEnded = false
18
-
19
- const mockReq = {
20
- ...req,
21
- method: method.toUpperCase(),
22
- url: path
23
- } as Request
24
-
25
- const mockRes = {
26
- ...res,
27
- json: (data: any) => {
28
- if (!isEnded) {
29
- isEnded = true
30
- resolve(data)
31
- }
32
- },
33
- status: (statusCode: number) => {
34
- console.log("Status:", statusCode)
35
- return mockRes
36
- },
37
- } as Response
38
-
39
- const routerStack: any[] = (app.router as unknown as IRouter).stack
40
-
41
- const firstApiMiddlewareIndex = routerStack.findIndex((layer) => layer.name === "__FIRST_API_MIDDLEWARE__")
42
- if (!(firstApiMiddlewareIndex > -1)) {
43
- throw new Error("middleware: __FIRST_API_MIDDLEWARE__ was not found in stack")
44
- }
45
-
46
- const apiStack = routerStack.slice(firstApiMiddlewareIndex + 1)
47
-
48
- const processLayer = async (index: number) => {
49
- if (index >= apiStack.length || isEnded) return
50
-
51
- const layer = apiStack[index]
52
-
53
- const isNonMatchingLayer = !layer.match(path)
54
- if (isNonMatchingLayer) {
55
- // console.log("not machthing route:", path, "to layer:", index, layer.name, layer, "reason: ", {isNonMatchingLayer})
56
- await processLayer(index + 1)
57
- return
58
- }
59
-
60
- const runHandler = async(handler: any) => new Promise<void>((resolveMiddleware, rejectMiddleware) => {
61
- handler(mockReq, mockRes, (err?: any) => {
62
- if (err) {
63
- console.error("Middleware error:", err)
64
- if (!isEnded) {
65
- isEnded = true
66
- rejectMiddleware(err)
67
- }
68
- return
69
- }
70
- resolveMiddleware()
71
- })
72
- })
73
-
74
- if (layer.route) {
75
- if (!layer.route.methods[method.toLowerCase()]) {
76
- // console.log("not machthing route:", path, "to route layer:", index, layer.name, layer, "reason: method not matching")
77
- await processLayer(index + 1)
78
- return
79
- }
80
-
81
- if (layer.route.stack.length !== 1) {
82
- throw new Error(`expected only one handler per route for route: ${layer.route.path}`)
83
- }
84
-
85
- await runHandler(layer.route.stack[0].handle)
86
-
87
- } else {
88
- await runHandler(layer.handle)
89
- }
90
-
91
- if (!isEnded) {
92
- await processLayer(index + 1)
93
- }
94
- }
95
-
96
- // AWAIT ??
97
- processLayer(0)
98
-
99
- // Set a timeout to prevent hanging
100
- setTimeout(() => {
101
- if (!isEnded) {
102
- reject("Route handler timed out")
103
- }
104
- }, 30000)
105
- })
106
- }
107
-
108
- const createMethod = (method: string) => {
109
- return async <TResponse = Record<string, unknown>>(
110
- path: string,
111
- payload: Record<string, unknown>,
112
- ctx?: Ctx,
113
- ): Promise<TResponse> => {
114
- if (!ctx) {
115
- throw new Error("Context must be provided in SSR mode")
116
- }
117
-
118
- ctx.req.body = payload
119
- return callRoute<TResponse>(app, method, path, ctx.req, ctx.res)
120
- }
121
- }
122
-
123
- const apiClient = {
124
- get: createMethod("get"),
125
- post: createMethod("post"),
126
- put: createMethod("put"),
127
- delete: createMethod("delete")
128
- }
129
-
130
- return apiClient
131
- }
132
-
133
- export default getServerApiClient
@@ -1,86 +0,0 @@
1
- import type { Application } from "express"
2
-
3
- // import { Ctx } from "@rpcbase/api"
4
- type Ctx = any
5
-
6
-
7
- type ServerArgs = {
8
- app: Application;
9
- };
10
-
11
- type PayloadNotCtx = Record<string, unknown> & {
12
- [P in keyof Ctx]?: never;
13
- };
14
-
15
- type ApiClientMethod = <TResponse = Record<string, unknown>>(
16
- path: string,
17
- payload: PayloadNotCtx,
18
- ctx?: Ctx,
19
- ) => Promise<TResponse>;
20
-
21
- export type HttpMethod = "get" | "put" | "post" | "delete";
22
- type MethodRecord<T> = Record<HttpMethod, T>;
23
-
24
- export type ApiClient = MethodRecord<ApiClientMethod>;
25
-
26
- let apiClient: ApiClient
27
-
28
- export const initApiClient = async (args?: ServerArgs) => {
29
- // @ts-expect-error -- Suppress TS2339: Property 'env' does not exist on type 'ImportMeta'
30
- if (import.meta.env.SSR) {
31
- if (!args) {
32
- throw new Error("Server args must be provided in SSR mode")
33
- }
34
-
35
- const { getServerApiClient } = await import("./getServerApiClient")
36
-
37
- apiClient = await getServerApiClient(args.app)
38
- } else {
39
- const axios = (await import("axios")).default
40
-
41
- const axiosClient = axios.create({
42
- baseURL: "/",
43
- withCredentials: true,
44
- headers: {
45
- "Content-Type": "application/json",
46
- },
47
- })
48
-
49
- const createMethod = (method: string): ApiClientMethod => {
50
- return async <TResponse = Record<string, unknown>>(
51
- path: string,
52
- payload: PayloadNotCtx,
53
- _ctx?: Ctx,
54
- ): Promise<TResponse> => {
55
- const config = {
56
- method,
57
- url: path,
58
- data: payload,
59
- headers: {
60
- // ...(typeof ctxOrPath !== 'string' && {
61
- // // 'X-Custom-Header': ctxOrPath.someHeaderValue,
62
- // // ...ctxOrPath.additionalHeaders,
63
- // }),
64
- },
65
- }
66
-
67
- try {
68
- const response = await axiosClient(config)
69
- return response.data
70
- } catch (error) {
71
- console.log("AXIOS API ERROR", error)
72
- throw error
73
- }
74
- }
75
- }
76
-
77
- apiClient = {
78
- get: createMethod("get"),
79
- put: createMethod("put"),
80
- post: createMethod("post"),
81
- delete: createMethod("delete"),
82
- }
83
- }
84
- }
85
-
86
- export { apiClient }
package/src/cleanupURL.ts DELETED
@@ -1,46 +0,0 @@
1
- const CLEANUP_WAIT_DELAY = 1000
2
-
3
- // Function to clean UTM params while preserving others
4
- export const cleanupURL = () => {
5
- if (import.meta.env.SSR) {
6
- return
7
- }
8
-
9
- const runCleanup = () => {
10
- // Add a small delay before running cleanupURL
11
- setTimeout(() => {
12
- const url = new URL(window.location.href)
13
- const params = new URLSearchParams(url.search)
14
-
15
- // Get all current query parameter keys
16
- const paramKeys = Array.from(params.keys())
17
-
18
- // Remove any parameter starting with 'utm_'
19
- paramKeys.forEach((key) => {
20
- if (key.startsWith("utm_")) {
21
- params.delete(key)
22
- }
23
- })
24
-
25
- // Build the new URL: keep pathname and append remaining query params (if any)
26
- const cleanUrl =
27
- url.pathname +
28
- (params.toString() ? "?" + params.toString() : "") +
29
- url.hash
30
-
31
- // Update the browser URL without reloading
32
- window.history.replaceState({}, document.title, cleanUrl)
33
- }, CLEANUP_WAIT_DELAY)
34
- }
35
-
36
- // If DOM is already loaded, schedule the cleanup
37
- if (
38
- document.readyState === "complete" ||
39
- document.readyState === "interactive"
40
- ) {
41
- runCleanup()
42
- } else {
43
- // Otherwise wait for the DOM content to be loaded
44
- document.addEventListener("DOMContentLoaded", runCleanup, { once: true })
45
- }
46
- }
@@ -1,58 +0,0 @@
1
- import _snakeCase from "lodash/snakeCase"
2
-
3
-
4
- export const getFeatureFlag = async (
5
- flag: string,
6
- ): Promise<boolean | string | undefined> => {
7
- const envKey = `RB_PUBLIC_FLAG_${_snakeCase(flag).toUpperCase()}`
8
-
9
- if (import.meta.env.SSR) {
10
- if (process.env[envKey] !== undefined) {
11
- return process.env[envKey]
12
- }
13
-
14
- const startTime = performance.now()
15
- const { PostHog } = await import("posthog-node")
16
- const client = new PostHog(
17
- process.env.RB_PUBLIC_POSTHOG_KEY!,
18
- { host: "https://eu.i.posthog.com" },
19
- )
20
-
21
- const distinctId = "server"
22
- console.log("TODO: NYI server side feature flags client distinctId")
23
- const value = await client.getFeatureFlag(flag, distinctId)
24
- const endTime = performance.now()
25
- console.log(`SSR: Feature flag "${flag}" loaded in ${(endTime - startTime).toFixed(2)}ms`)
26
-
27
- return value
28
- } else {
29
- if (import.meta.env[envKey] !== undefined) {
30
- return import.meta.env[envKey]
31
- }
32
-
33
- const startTime = performance.now()
34
- const { posthog } = await import("posthog-js")
35
-
36
- let hasLoadedFeatureFlags = false
37
-
38
- function waitForFeatureFlags(): Promise<void> {
39
- return new Promise((resolve) => {
40
- if (hasLoadedFeatureFlags) {
41
- resolve()
42
- } else {
43
- posthog.onFeatureFlags(() => {
44
- hasLoadedFeatureFlags = true
45
- resolve()
46
- })
47
- }
48
- })
49
- }
50
-
51
- await waitForFeatureFlags()
52
- const endTime = performance.now()
53
-
54
- console.log(`Client: Feature flag "${flag}" loaded in ${(endTime - startTime).toFixed(2)}ms`)
55
-
56
- return posthog.getFeatureFlag(flag)
57
- }
58
- }
@@ -1,2 +0,0 @@
1
- export * from "./useThrottledMeasure"
2
- export * from "./useMediaQuery"
@@ -1,31 +0,0 @@
1
- import { useSyncExternalStore } from "react"
2
-
3
-
4
- const emptyUnsubscribe = () => {}
5
-
6
- export const useMediaQuery = (query: string): boolean => {
7
- const isServer = typeof window === "undefined"
8
-
9
- const subscribe = (callback: () => void) => {
10
- if (isServer) return emptyUnsubscribe
11
-
12
- const mql = window.matchMedia(query)
13
-
14
- // Modern browsers
15
- if (mql.addEventListener) {
16
- mql.addEventListener("change", callback)
17
- return () => mql.removeEventListener("change", callback)
18
- }
19
-
20
- // Legacy fallback
21
- mql.addListener(callback)
22
- return () => mql.removeListener(callback)
23
- }
24
-
25
- const getSnapshot = () => {
26
- if (isServer) return false
27
- return window.matchMedia(query).matches
28
- }
29
-
30
- return useSyncExternalStore(subscribe, getSnapshot, () => false)
31
- }
@@ -1,49 +0,0 @@
1
- import {useState, useEffect, useRef, useCallback} from "react"
2
- import useMeasure from "react-use/lib/useMeasure"
3
- import _throttle from "lodash/throttle"
4
- import { deepEqual } from "fast-equals"
5
-
6
-
7
- const useMeasureHook = useMeasure.default || useMeasure
8
-
9
- const DEFAULT_THROTTLE_TIME = 16
10
-
11
- export const useThrottledMeasure = (throttleDuration = DEFAULT_THROTTLE_TIME) => {
12
- const hasInitialMeasure = useRef(false)
13
-
14
- const [ref, measuredRect] = useMeasureHook()
15
- const [rect, setRect] = useState(() => {
16
- return {x: 0, y: 0, width: 0, height: 0, top: 0, left: 0, bottom: 0, right: 0}
17
- })
18
-
19
- const throttledSetRect = useCallback(
20
- _throttle(
21
- (newRect) => {
22
- setRect((current) => {
23
- return deepEqual(current, newRect) ? current : newRect
24
- })
25
- },
26
- throttleDuration,
27
- {leading: true, trailing: true},
28
- ),
29
- [throttleDuration],
30
- )
31
-
32
- useEffect(() => {
33
- if (measuredRect.width > 0 && !hasInitialMeasure.current) {
34
- hasInitialMeasure.current = true
35
- setRect((current) => {
36
- return deepEqual(current, measuredRect) ? current : measuredRect
37
- })
38
- return
39
- }
40
-
41
- throttledSetRect(measuredRect)
42
-
43
- return () => {
44
- throttledSetRect.cancel()
45
- }
46
- }, [measuredRect, throttledSetRect])
47
-
48
- return [ref, rect]
49
- }
package/src/index.ts DELETED
@@ -1,5 +0,0 @@
1
- export * from "./apiClient"
2
- export * from "./initWithRoutes"
3
- export * from "./types"
4
- export * from "./getFeatureFlag"
5
- export * from "./RootProvider"