@pushwoosh/smart-components-kit 2.1.1 → 2.1.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.
@@ -53,10 +53,13 @@ export const CanvaImportDrawer = ({
53
53
  query: debouncedQuery
54
54
  });
55
55
  }, [rpcGateway, isOpen, isReady, debouncedQuery]);
56
- useEffect(() => {
56
+ const designsDeps = [designsAsync.value];
57
+ const [prevDesignsDeps, setPrevDesignsDeps] = useState(null);
58
+ if (prevDesignsDeps === null || designsDeps.some((dep, index) => dep !== prevDesignsDeps[index])) {
59
+ setPrevDesignsDeps(designsDeps);
57
60
  setDesigns(designsAsync.value?.designs ?? []);
58
61
  setContinuation(designsAsync.value?.continuation ?? '');
59
- }, [designsAsync.value]);
62
+ }
60
63
  useEffect(() => {
61
64
  if (designsAsync.error) {
62
65
  openToast({
@@ -1,5 +1,5 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { useEffect, useLayoutEffect, useRef, useState } from 'react';
2
+ import { useLayoutEffect, useRef, useState } from 'react';
3
3
  import { Button, Chip, Drawer, DrawerBody, DrawerHeader, DrawerTitle, ModalConfirm, NativeInput, useToast } from '@pushwoosh/dumb-components';
4
4
  import { Color } from '@pushwoosh/kit-constants';
5
5
  import { Columns, Vertical } from '@pushwoosh/kit-helpers';
@@ -96,7 +96,10 @@ export const CreateCropDrawer = ({
96
96
  // The drawer mounts once and is toggled via `isOpen`, so reset every field
97
97
  // whenever it opens for a different original — otherwise values (and the
98
98
  // `ratioExists` guard) leak from the previously edited image.
99
- useEffect(() => {
99
+ const originalDeps = [original];
100
+ const [prevOriginalDeps, setPrevOriginalDeps] = useState(null);
101
+ if (prevOriginalDeps === null || originalDeps.some((dep, index) => dep !== prevOriginalDeps[index])) {
102
+ setPrevOriginalDeps(originalDeps);
100
103
  if (original) {
101
104
  setRatio('original');
102
105
  setLastEdited('width');
@@ -105,7 +108,7 @@ export const CreateCropDrawer = ({
105
108
  setViewedCrop(null);
106
109
  setFocal(CENTER_FOCAL);
107
110
  }
108
- }, [original]);
111
+ }
109
112
  const isJpeg = /jpe?g/i.test(original?.mimeType ?? '');
110
113
  const sizeValue = Number(size);
111
114
  const isSizeValid = Number.isFinite(sizeValue) && sizeValue > 0;
@@ -153,11 +153,18 @@ export const MediaStorage = ({
153
153
  // resolves, fetch each one's crops in the background and let the
154
154
  // "N crops" badge appear per file as soon as its request resolves. The
155
155
  // cleanup flag drops results of a page that has since been replaced.
156
+ const listDeps = [listAsync.value];
157
+ const [prevListDeps, setPrevListDeps] = useState(null);
158
+ if (prevListDeps === null || listDeps.some((dep, index) => dep !== prevListDeps[index])) {
159
+ setPrevListDeps(listDeps);
160
+ if (listAsync.value?.files) {
161
+ setCropsByUuid({});
162
+ setSelectedUuids([]);
163
+ }
164
+ }
156
165
  useEffect(() => {
157
166
  const originals = listAsync.value?.files;
158
167
  if (!originals) return undefined;
159
- setCropsByUuid({});
160
- setSelectedUuids([]);
161
168
  let cancelled = false;
162
169
  originals.forEach(file => {
163
170
  void (async () => {
@@ -49,7 +49,10 @@ export function ModalCloningJourney({
49
49
  }))
50
50
  }));
51
51
  }, [rpcGateway]);
52
- useEffect(() => {
52
+ const applicationsDeps = [applications.value];
53
+ const [prevApplicationsDeps, setPrevApplicationsDeps] = useState(null);
54
+ if (prevApplicationsDeps === null || applicationsDeps.some((dep, index) => dep !== prevApplicationsDeps[index])) {
55
+ setPrevApplicationsDeps(applicationsDeps);
53
56
  if (applications.value && applications.value.length > 0) {
54
57
  const filteredApplications = applications.value.reduce((acc, item) => {
55
58
  if (item.platforms.length > 0) {
@@ -62,7 +65,7 @@ export function ModalCloningJourney({
62
65
  }, []);
63
66
  setApplicationsOptions(filteredApplications);
64
67
  }
65
- }, [applications]);
68
+ }
66
69
  const contentOptions = [{
67
70
  label: lang({
68
71
  message: 'SMART.MODAL_CLONING_JOURNEY.CONTENT_OPTION.KEEP'
@@ -15,14 +15,9 @@ export function usePagedItems(loadPage, resetKey, enabled = true) {
15
15
  hasMore: true,
16
16
  isFetching: false
17
17
  });
18
- const fetchPage = useCallback(page => {
18
+ const requestPage = useCallback(page => {
19
19
  const run = runRef.current;
20
20
  cursorRef.current.isFetching = true;
21
- setState(prev => ({
22
- ...prev,
23
- isLoading: true,
24
- isError: false
25
- }));
26
21
  load(page).then(({
27
22
  items,
28
23
  hasMore
@@ -52,25 +47,38 @@ export function usePagedItems(loadPage, resetKey, enabled = true) {
52
47
  }
53
48
  });
54
49
  }, [load]);
55
- useEffect(() => {
56
- cursorRef.current = {
57
- next: 0,
58
- hasMore: true,
59
- isFetching: false
60
- };
50
+ const fetchPage = useCallback(page => {
51
+ setState(prev => ({
52
+ ...prev,
53
+ isLoading: true,
54
+ isError: false
55
+ }));
56
+ requestPage(page);
57
+ }, [requestPage]);
58
+ const resetDeps = [resetKey, enabled, requestPage];
59
+ const [prevResetDeps, setPrevResetDeps] = useState(null);
60
+ if (prevResetDeps === null || resetDeps.some((dep, index) => dep !== prevResetDeps[index])) {
61
+ setPrevResetDeps(resetDeps);
61
62
  setState({
62
63
  items: [],
63
64
  hasMore: true,
64
65
  isLoading: enabled,
65
66
  isError: false
66
67
  });
68
+ }
69
+ useEffect(() => {
70
+ cursorRef.current = {
71
+ next: 0,
72
+ hasMore: true,
73
+ isFetching: false
74
+ };
67
75
  if (enabled) {
68
- fetchPage(0);
76
+ requestPage(0);
69
77
  }
70
78
  return () => {
71
79
  runRef.current += 1;
72
80
  };
73
- }, [resetKey, enabled, fetchPage]);
81
+ }, [resetKey, enabled, requestPage]);
74
82
  const loadMore = useCallback(() => {
75
83
  const {
76
84
  next,
@@ -1,16 +1,19 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
- import { useRef, useState, useEffect, useContext } from 'react';
2
+ import { useRef, useState, useContext } from 'react';
3
3
  import { SearchInput } from '@pushwoosh/dumb-components';
4
4
  import { DataTableContext } from '../../context';
5
5
  export function DataTableSearchInput(props) {
6
6
  const context = useContext(DataTableContext);
7
7
  const [inputValue, setInputValue] = useState(context.params.search);
8
8
  const timeoutRef = useRef(undefined);
9
- useEffect(() => {
9
+ const searchDeps = [context.params.search];
10
+ const [prevSearchDeps, setPrevSearchDeps] = useState(null);
11
+ if (prevSearchDeps === null || searchDeps.some((dep, index) => dep !== prevSearchDeps[index])) {
12
+ setPrevSearchDeps(searchDeps);
10
13
  if (inputValue !== context.params.search) {
11
14
  setInputValue(context.params.search);
12
15
  }
13
- }, [context.params.search]); // eslint-disable-line react-hooks/exhaustive-deps
16
+ }
14
17
  return _jsx(SearchInput, {
15
18
  ...props,
16
19
  value: inputValue,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pushwoosh/smart-components-kit",
3
- "version": "2.1.1",
3
+ "version": "2.1.2",
4
4
  "description": "Stateful, data-connected React components shared by Pushwoosh micro-frontends",
5
5
  "repository": {
6
6
  "type": "git",
@@ -17,7 +17,7 @@
17
17
  },
18
18
  "dependencies": {
19
19
  "@floating-ui/react-dom": "^2.1.2",
20
- "@pushwoosh/dumb-components": "^4.3.1",
20
+ "@pushwoosh/dumb-components": "^4.4.0",
21
21
  "@pushwoosh/kit-constants": "^3.0.0",
22
22
  "@pushwoosh/kit-helpers": "^4.16.0",
23
23
  "@pushwoosh/kit-icons": "^2.3.15",
@@ -28,7 +28,7 @@
28
28
  },
29
29
  "devDependencies": {
30
30
  "@pushwoosh/frontend-builder-engine": "^4.0.0",
31
- "@pushwoosh/spa-context": "^3.3.0",
31
+ "@pushwoosh/spa-context": "^3.3.1",
32
32
  "@svgr/webpack": "^8.1.0",
33
33
  "@types/node": "^24.19.1",
34
34
  "@types/react": "^19.3.0",