@vitus-labs/core 1.4.0 → 1.4.2

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/lib/index.d.ts CHANGED
@@ -199,6 +199,14 @@ declare const hoistNonReactStatics: <T, S>(target: T, source: S, excludeList?: R
199
199
  type IsEmpty = <T extends Record<number | string, any> | any[] | null | undefined>(param: T) => T extends null | undefined ? true : keyof T extends never ? true : T extends T[] ? T[number] extends never ? true : false : false;
200
200
  declare const isEmpty: IsEmpty;
201
201
  //#endregion
202
+ //#region src/isEqual.d.ts
203
+ /**
204
+ * Order-independent deep equality for plain objects, arrays, and primitives.
205
+ * Handles null, undefined, nested structures. Does not handle Date, RegExp,
206
+ * Map, Set, or circular references — not needed for theme/props comparison.
207
+ */
208
+ declare const isEqual: (a: unknown, b: unknown) => boolean;
209
+ //#endregion
202
210
  //#region src/render.d.ts
203
211
  type CreateTypes = Parameters<typeof createElement>[0];
204
212
  type CloneTypes = Parameters<typeof cloneElement>[0];
@@ -214,6 +222,18 @@ type RenderProps<T extends Record<string, unknown> | undefined> = (props: Partia
214
222
  type Render = <T extends Record<string, any> | undefined>(content?: CreateTypes | CloneTypes | ReactNode | ReactNode[] | RenderProps<T>, attachProps?: T) => ReturnType<typeof createElement> | ReturnType<typeof cloneElement> | null;
215
223
  declare const render: Render;
216
224
  //#endregion
225
+ //#region src/useStableValue.d.ts
226
+ /**
227
+ * Returns a referentially stable version of `value`. The returned reference
228
+ * only changes when the value is no longer deeply equal to the previous one.
229
+ *
230
+ * Use this to stabilize object/array props before passing them as hook
231
+ * dependencies, preventing unnecessary recalculations in useMemo/useEffect.
232
+ *
233
+ * Based on the useDeepCompareMemoize pattern from use-deep-compare.
234
+ */
235
+ declare const useStableValue: <T>(value: T) => T;
236
+ //#endregion
217
237
  //#region src/utils.d.ts
218
238
  declare const omit: <T extends Record<string, any>>(obj: T | null | undefined, keys?: readonly (string | keyof T)[]) => Partial<T>;
219
239
  declare const pick: <T extends Record<string, any>>(obj: T | null | undefined, keys?: readonly (string | keyof T)[]) => Partial<T>;
@@ -227,5 +247,5 @@ declare const throttle: <T extends (...args: any[]) => any>(fn: T, wait?: number
227
247
  };
228
248
  declare const merge: <T extends Record<string, any>>(target: T, ...sources: Record<string, any>[]) => T;
229
249
  //#endregion
230
- export { type BreakpointKeys, type Breakpoints, type HTMLElementAttrs, type HTMLTagAttrsByTag, type HTMLTags, type HTMLTextTags, HTML_TAGS, HTML_TEXT_TAGS, type IsEmpty, Provider, type Render, compose, config, context, get, hoistNonReactStatics, init, isEmpty, merge, omit, pick, render, set, throttle };
250
+ export { type BreakpointKeys, type Breakpoints, type HTMLElementAttrs, type HTMLTagAttrsByTag, type HTMLTags, type HTMLTextTags, HTML_TAGS, HTML_TEXT_TAGS, type IsEmpty, Provider, type Render, compose, config, context, get, hoistNonReactStatics, init, isEmpty, isEqual, merge, omit, pick, render, set, throttle, useStableValue };
231
251
  //# sourceMappingURL=index2.d.ts.map
package/lib/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { ThemeProvider, css, styled } from "styled-components";
2
- import { cloneElement, createContext, createElement, isValidElement, useMemo } from "react";
2
+ import { cloneElement, createContext, createElement, isValidElement, useMemo, useRef } from "react";
3
3
  import { Fragment, jsx } from "react/jsx-runtime";
4
4
  import { isFragment, isMemo, isValidElementType } from "react-is";
5
5
 
@@ -54,6 +54,52 @@ const isEmpty = (param) => {
54
54
  return Object.keys(param).length === 0;
55
55
  };
56
56
 
57
+ //#endregion
58
+ //#region src/isEqual.ts
59
+ /**
60
+ * Order-independent deep equality for plain objects, arrays, and primitives.
61
+ * Handles null, undefined, nested structures. Does not handle Date, RegExp,
62
+ * Map, Set, or circular references — not needed for theme/props comparison.
63
+ */
64
+ const isArrayEqual = (a, b) => {
65
+ if (a.length !== b.length) return false;
66
+ for (let i = 0; i < a.length; i++) if (!isEqual(a[i], b[i])) return false;
67
+ return true;
68
+ };
69
+ const isObjectEqual = (a, b) => {
70
+ const aKeys = Object.keys(a);
71
+ if (aKeys.length !== Object.keys(b).length) return false;
72
+ for (const key of aKeys) {
73
+ if (!Object.hasOwn(b, key)) return false;
74
+ if (!isEqual(a[key], b[key])) return false;
75
+ }
76
+ return true;
77
+ };
78
+ const isEqual = (a, b) => {
79
+ if (Object.is(a, b)) return true;
80
+ if (typeof a !== typeof b || a == null || b == null || typeof a !== "object") return false;
81
+ if (Array.isArray(a)) return Array.isArray(b) && isArrayEqual(a, b);
82
+ if (Array.isArray(b)) return false;
83
+ return isObjectEqual(a, b);
84
+ };
85
+
86
+ //#endregion
87
+ //#region src/useStableValue.ts
88
+ /**
89
+ * Returns a referentially stable version of `value`. The returned reference
90
+ * only changes when the value is no longer deeply equal to the previous one.
91
+ *
92
+ * Use this to stabilize object/array props before passing them as hook
93
+ * dependencies, preventing unnecessary recalculations in useMemo/useEffect.
94
+ *
95
+ * Based on the useDeepCompareMemoize pattern from use-deep-compare.
96
+ */
97
+ const useStableValue = (value) => {
98
+ const ref = useRef(value);
99
+ if (!isEqual(ref.current, value)) ref.current = value;
100
+ return ref.current;
101
+ };
102
+
57
103
  //#endregion
58
104
  //#region src/context.tsx
59
105
  /**
@@ -69,14 +115,10 @@ const VitusLabsProvider = context.Provider;
69
115
  */
70
116
  const Provider = ({ theme, children, ...props }) => {
71
117
  const ExternalProvider = useMemo(() => config.ExternalProvider, []);
72
- const context = useMemo(() => ({
118
+ const context = useStableValue({
73
119
  theme,
74
120
  ...props
75
- }), [
76
- theme,
77
- ...Object.values(props),
78
- props
79
- ]);
121
+ });
80
122
  if (isEmpty(theme) || !theme) return /* @__PURE__ */ jsx(Fragment, { children });
81
123
  if (ExternalProvider) return /* @__PURE__ */ jsx(VitusLabsProvider, {
82
124
  value: context,
@@ -436,5 +478,5 @@ const merge = (target, ...sources) => {
436
478
  };
437
479
 
438
480
  //#endregion
439
- export { HTML_TAGS, HTML_TEXT_TAGS, Provider, compose, config, context, get, hoistNonReactStatics, init, isEmpty, merge, omit, pick, render, set, throttle };
481
+ export { HTML_TAGS, HTML_TEXT_TAGS, Provider, compose, config, context, get, hoistNonReactStatics, init, isEmpty, isEqual, merge, omit, pick, render, set, throttle, useStableValue };
440
482
  //# sourceMappingURL=index.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vitus-labs/core",
3
- "version": "1.4.0",
3
+ "version": "1.4.2",
4
4
  "license": "MIT",
5
5
  "author": "Vit Bokisch <vit@bokisch.cz>",
6
6
  "maintainers": [
@@ -61,5 +61,5 @@
61
61
  "@vitus-labs/tools-rolldown": "^1.6.0",
62
62
  "@vitus-labs/tools-typescript": "^1.6.0"
63
63
  },
64
- "gitHead": "297985a88495c40ddebfdccdd3ab35f9e41bbe0c"
64
+ "gitHead": "f12f43c61149964ff4f3f4b80cb6f92da2825915"
65
65
  }