@flowerforce/flower-react 4.0.10-beta.0 → 4.0.11-beta.1

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/dist/index.esm.js CHANGED
@@ -1,20 +1,46 @@
1
- import React, { memo, useRef, useState, useMemo, Children, useEffect, useContext, useCallback } from 'react';
1
+ import React, { useEffect, memo, useRef, useState, useMemo, Children, useContext, useCallback } from 'react';
2
2
  import _keyBy from 'lodash/keyBy';
3
- import { CoreUtils, FlowerCoreBaseReducers, REDUCER_NAME, FlowerCoreStateSelectors, FlowerStateUtils, devtoolState, Emitter } from '@flowerforce/flower-core';
3
+ import { FlowUtils, FlowerCoreBaseReducers, REDUCER_NAME, FlowerCoreStateSelectors, FlowerStateUtils, Emitter, devtoolState } from '@flowerforce/flower-core';
4
4
  import { FlowerReactProvider, FlowerReactContext } from '@flowerforce/flower-react-context';
5
5
  import _get from 'lodash/get';
6
- import { createSlice, configureStore, combineReducers, createAction } from '@reduxjs/toolkit';
7
6
  import { reducerData, ReduxFlowerProvider, flowerDataActions, middlewares } from '@flowerforce/flower-react-store';
8
7
  export { createApi } from '@flowerforce/flower-react-store';
8
+ import { createSlice, configureStore, combineReducers, createAction } from '@reduxjs/toolkit';
9
9
  import { createSelector } from 'reselect';
10
+ import { useHistoryContext } from '@flowerforce/flower-react-history-context';
11
+ export { HistoryContextProvider } from '@flowerforce/flower-react-history-context';
10
12
  import { FlowerRule } from '@flowerforce/flower-react-shared';
11
13
  import set from 'lodash/set';
12
14
 
13
- // eslint-disable-next-line import/prefer-default-export
14
- const convertElements = (nodes) => {
15
- const res = CoreUtils.generateNodesForFlowerJson(nodes);
16
- return res;
15
+ const getRulesExists = (rules) => {
16
+ return Object.keys(rules).length ? FlowUtils.mapEdge(rules) : undefined;
17
17
  };
18
+ function hasDisplayName(type) {
19
+ return (!!type &&
20
+ typeof type === 'object' &&
21
+ 'displayName' in type &&
22
+ typeof type.displayName === 'string');
23
+ }
24
+ const generateNodesForFlowerJson = (nodes) => nodes
25
+ .filter((child) => typeof child === 'object' && child !== null && 'props' in child)
26
+ .filter((e) => !!_get(e, 'props.id'))
27
+ .map((e) => {
28
+ const rules = FlowUtils.makeRules(e.props.to ?? {});
29
+ const nextRules = getRulesExists(rules);
30
+ const children = e.props.data?.children;
31
+ const nodeType = hasDisplayName(e.type)
32
+ ? e.type.displayName
33
+ : e.props.as || 'FlowerNode';
34
+ return {
35
+ nodeId: e.props.id,
36
+ nodeType,
37
+ nodeTitle: _get(e.props, 'data.title'),
38
+ children,
39
+ nextRules,
40
+ retain: e.props.retain,
41
+ disabled: e.props.disabled
42
+ };
43
+ });
18
44
 
19
45
  const flowerReducer = createSlice({
20
46
  name: REDUCER_NAME.FLOWER_FLOW,
@@ -41,60 +67,37 @@ const selectFlowerHistory = (name) => createSelector(selectFlower(name), FlowerC
41
67
  const makeSelectNodesIds = (name) => createSelector(selectFlower(name), FlowerCoreStateSelectors.makeSelectNodesIds);
42
68
  const makeSelectStartNodeId = (name) => createSelector(selectFlower(name), FlowerCoreStateSelectors.makeSelectStartNodeId);
43
69
  const makeSelectCurrentNodeId = (name) => createSelector(selectFlower(name), makeSelectStartNodeId(name), FlowerCoreStateSelectors.makeSelectCurrentNodeId);
70
+ const makeSelectIsCurrentNode = (name) => createSelector(selectFlower(name), makeSelectCurrentNodeId(name), (flower, current) => flower.nodes[current]);
44
71
  const makeSelectPrevNodeRetain = (name) => createSelector(makeSelectNodesIds(name), selectFlowerHistory(name), makeSelectCurrentNodeId(name), FlowerCoreStateSelectors.makeSelectPrevNodeRetain);
45
72
  const makeSelectCurrentNodeDisabled = (name) => createSelector(makeSelectNodesIds(name), makeSelectCurrentNodeId(name), FlowerCoreStateSelectors.makeSelectCurrentNodeDisabled);
46
73
  // dati nel flow selezionato
47
74
  const makeSelectData = (name) => createSelector(selectFlowerDataNode(name), (data) => data?.data ?? {});
48
75
  createSelector(selectGlobalData, FlowerStateUtils.getAllData);
49
76
 
50
- /* eslint-disable no-undef */
51
- /* eslint-disable no-underscore-dangle */
52
- /*
53
- * FlowerClient
54
- */
55
- const FlowerClient = ({ children, name, destroyOnUnmount = true, startId = null, initialState = {}, initialData }) => {
56
- const flowName = name;
57
- const { dispatch, store, useSelector } = ReduxFlowerProvider.getReduxHooks();
58
- const one = useRef(false);
59
- const [wsDevtools, setWsDevtools] = useState(devtoolState && _get(devtoolState, '__FLOWER_DEVTOOLS_INITIALIZED__', false));
60
- // TODO could make that transformation in CoreUtils.generateNodesForFlowerJson
61
- // eslint-disable-next-line react-hooks/exhaustive-deps, max-len
62
- const nodes = useMemo(
63
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
64
- () => convertElements(Children.toArray(children)), [children]);
65
- const nodeById = useMemo(() => _keyBy(Children.toArray(children), 'props.id'), [children]);
66
- const isInitialized = useSelector(makeSelectStartNodeId(name));
67
- const history = useSelector(selectFlowerHistory(name));
68
- const current = useSelector(makeSelectCurrentNodeId(flowName));
69
- const isDisabled = useSelector(makeSelectCurrentNodeDisabled(flowName));
70
- const prevFlowerNodeId = useSelector(makeSelectPrevNodeRetain(flowName));
77
+ const useInitNodes = ({ one, nodes, name, startId, persist = false, initialData, initialState = {} }) => {
78
+ const { dispatch } = ReduxFlowerProvider.getReduxHooks();
71
79
  useEffect(() => {
72
80
  if (nodes.length > 0 && one.current === false) {
73
81
  one.current = true;
74
82
  dispatch(flowerActions.initNodes({
75
- name: flowName,
76
- // @ts-expect-error FIX ME
83
+ name,
77
84
  nodes,
78
85
  startId: startId ?? '',
79
- persist: destroyOnUnmount === false,
86
+ persist,
80
87
  initialState
81
88
  }));
82
- if (initialData) {
83
- dispatch(flowerDataActions.initData({
84
- rootName: flowName,
85
- initialData: initialData ?? {}
86
- }));
87
- }
88
89
  }
89
- }, [
90
- dispatch,
91
- flowName,
92
- nodes,
93
- startId,
94
- destroyOnUnmount,
95
- initialState,
96
- initialData
97
- ]);
90
+ if (initialData) {
91
+ dispatch(flowerDataActions.initData({
92
+ rootName: name,
93
+ initialData: initialData ?? {}
94
+ }));
95
+ }
96
+ }, [dispatch, name, nodes, startId, initialData, initialState, persist]);
97
+ };
98
+
99
+ const useInitDevtools = ({ devtoolState, setWsDevtools, flowName, }) => {
100
+ const { dispatch } = ReduxFlowerProvider.getReduxHooks();
98
101
  useEffect(() => {
99
102
  /* istanbul ignore next */
100
103
  const eventCb = (msg) => {
@@ -108,12 +111,10 @@ const FlowerClient = ({ children, name, destroyOnUnmount = true, startId = null,
108
111
  dispatch(flowerActions.setCurrentNode({ name: msg.name, node: msg.id }));
109
112
  }
110
113
  // if (msg.action === 'REPLACE_DATA' && msg.name === flowName) {
111
- // dispatch(
112
- // formActions.replaceData({ flowName: msg.name, value: msg.data })
113
- // )
114
+ // dispatch(actions.replaceData({ flowName: msg.name, value: msg.data }))
114
115
  // }
115
116
  // if (msg.action === 'ADD_DATA' && msg.name === flowName) {
116
- // dispatch(formActions.addData({ flowName: msg.name, value: msg.data }))
117
+ // dispatch(actions.addData({ flowName: msg.name, value: msg.data }))
117
118
  // }
118
119
  };
119
120
  /* istanbul ignore next */
@@ -127,13 +128,22 @@ const FlowerClient = ({ children, name, destroyOnUnmount = true, startId = null,
127
128
  }
128
129
  };
129
130
  }, [dispatch, flowName]);
131
+ };
132
+
133
+ const useDestroyFlow = ({ flowName, one, persist }) => {
134
+ const { dispatch } = ReduxFlowerProvider.getReduxHooks();
130
135
  useEffect(() => () => {
131
- // unmount function
132
- if (destroyOnUnmount && one.current === true) {
136
+ if (persist)
137
+ return;
138
+ if (one.current === true) {
133
139
  one.current = false;
134
140
  dispatch(flowerActions.destroy({ name: flowName }));
135
141
  }
136
- }, [dispatch, flowName, destroyOnUnmount]);
142
+ }, [dispatch, flowName, persist]);
143
+ };
144
+
145
+ const useClientInitEvent = ({ flowName, isInitialized, wsDevtools }) => {
146
+ const { store } = ReduxFlowerProvider.getReduxHooks();
137
147
  useEffect(() => {
138
148
  /* istanbul ignore next */
139
149
  if (isInitialized &&
@@ -149,7 +159,11 @@ const FlowerClient = ({ children, name, destroyOnUnmount = true, startId = null,
149
159
  getState: store.getState
150
160
  });
151
161
  }
152
- }, [dispatch, flowName, wsDevtools, isInitialized, store]);
162
+ }, [flowName, wsDevtools, isInitialized, store]);
163
+ };
164
+ const useSetHistoryEvent = ({ flowName, isInitialized, wsDevtools }) => {
165
+ const { useSelector } = ReduxFlowerProvider.getReduxHooks();
166
+ const history = useSelector(selectFlowerHistory(flowName));
153
167
  useEffect(() => {
154
168
  /* istanbul ignore next */
155
169
  if (isInitialized &&
@@ -163,7 +177,9 @@ const FlowerClient = ({ children, name, destroyOnUnmount = true, startId = null,
163
177
  history
164
178
  });
165
179
  }
166
- }, [dispatch, flowName, history, wsDevtools, isInitialized]);
180
+ }, [flowName, history, wsDevtools, isInitialized]);
181
+ };
182
+ const useSetCurrentEvent = ({ current, flowName, isInitialized, wsDevtools }) => {
167
183
  useEffect(() => {
168
184
  if (!current)
169
185
  return;
@@ -183,6 +199,9 @@ const FlowerClient = ({ children, name, destroyOnUnmount = true, startId = null,
183
199
  });
184
200
  }
185
201
  }, [flowName, current, wsDevtools, isInitialized]);
202
+ };
203
+ const useFlowerNavigateEvent = ({ current, flowName, isInitialized, wsDevtools, isDisabled }) => {
204
+ const { dispatch } = ReduxFlowerProvider.getReduxHooks();
186
205
  useEffect(() => {
187
206
  if (!current)
188
207
  return;
@@ -190,7 +209,7 @@ const FlowerClient = ({ children, name, destroyOnUnmount = true, startId = null,
190
209
  if (!isInitialized)
191
210
  return;
192
211
  if (isDisabled) {
193
- dispatch(flowerActions.next({ flowName }));
212
+ dispatch({ type: `${REDUCER_NAME.FLOWER_FLOW}/next`, payload: { flowName, disabled: true } });
194
213
  // eslint-disable-next-line no-underscore-dangle, no-undef
195
214
  /* istanbul ignore next */
196
215
  if (wsDevtools &&
@@ -213,7 +232,7 @@ const FlowerClient = ({ children, name, destroyOnUnmount = true, startId = null,
213
232
  devtoolState &&
214
233
  _get(devtoolState, '__FLOWER_DEVTOOLS__')) {
215
234
  if (isInitialized === current)
216
- return; // salto il primo event
235
+ return; // salto il primo evento
217
236
  Emitter.emit('flower-devtool-from-client', {
218
237
  source: 'flower-client',
219
238
  action: 'SET_SELECTED',
@@ -222,15 +241,55 @@ const FlowerClient = ({ children, name, destroyOnUnmount = true, startId = null,
222
241
  time: new Date()
223
242
  });
224
243
  }
225
- }, [
226
- dispatch,
227
- flowName,
244
+ }, [dispatch, flowName, current, isDisabled, wsDevtools, isInitialized]);
245
+ };
246
+
247
+ const useSelectorsClient = (flowName) => {
248
+ const { useSelector } = ReduxFlowerProvider.getReduxHooks();
249
+ const isInitialized = useSelector(makeSelectStartNodeId(flowName));
250
+ const current = useSelector(makeSelectCurrentNodeId(flowName));
251
+ const isDisabled = useSelector(makeSelectCurrentNodeDisabled(flowName));
252
+ const prevFlowerNodeId = useSelector(makeSelectPrevNodeRetain(flowName));
253
+ return {
254
+ isInitialized,
228
255
  current,
229
256
  isDisabled,
230
- store,
231
- wsDevtools,
232
- isInitialized
233
- ]);
257
+ prevFlowerNodeId
258
+ };
259
+ };
260
+
261
+ /*
262
+ * FlowerClient
263
+ */
264
+ const FlowerClient = ({ children, name, destroyOnUnmount = true, persist = false, startId = null, initialState = {}, initialData }) => {
265
+ const flowName = name;
266
+ const _persist = persist || !destroyOnUnmount;
267
+ const one = useRef(false);
268
+ const [wsDevtools, setWsDevtools] = useState(devtoolState && _get(devtoolState, '__FLOWER_DEVTOOLS_INITIALIZED__', false));
269
+ const nodes = useMemo(() => generateNodesForFlowerJson(Children.toArray(children)), [children]);
270
+ const nodeById = useMemo(() => _keyBy(Children.toArray(children), 'props.id'), [children]);
271
+ const { current, isDisabled, isInitialized, prevFlowerNodeId } = useSelectorsClient(flowName);
272
+ useInitNodes({
273
+ name,
274
+ nodes,
275
+ one,
276
+ initialData,
277
+ initialState,
278
+ persist: _persist,
279
+ startId
280
+ });
281
+ useDestroyFlow({ flowName, one, persist: _persist });
282
+ useInitDevtools({ devtoolState, setWsDevtools, flowName });
283
+ useClientInitEvent({ flowName, isInitialized, wsDevtools });
284
+ useSetHistoryEvent({ flowName, isInitialized, wsDevtools });
285
+ useSetCurrentEvent({ current, flowName, isInitialized, wsDevtools });
286
+ useFlowerNavigateEvent({
287
+ current,
288
+ flowName,
289
+ isDisabled,
290
+ isInitialized,
291
+ wsDevtools
292
+ });
234
293
  const currentNodeId = prevFlowerNodeId || current;
235
294
  const contextValues = useMemo(() => ({
236
295
  name: flowName,
@@ -244,10 +303,10 @@ const FlowerClient = ({ children, name, destroyOnUnmount = true, startId = null,
244
303
  React.createElement(FlowerReactProvider, { value: prevContextValues }, nodeById[currentNodeId]),
245
304
  React.createElement(FlowerReactProvider, { value: contextValues }, !isDisabled && current !== currentNodeId && nodeById[current]))) : null;
246
305
  };
247
- const component$9 = memo(FlowerClient);
248
- component$9.displayName = 'Flower';
306
+ const component$8 = memo(FlowerClient);
307
+ component$8.displayName = 'Flower';
249
308
  // workaround for let typescript read JSX component as a valid JSX element using react 19(?)
250
- const Flower = component$9;
309
+ const Flower = component$8;
251
310
 
252
311
  const FlowAction = ({ children, onEnter, onExit }) => {
253
312
  useEffect(() => {
@@ -258,13 +317,12 @@ const FlowAction = ({ children, onEnter, onExit }) => {
258
317
  }, [onEnter, onExit]);
259
318
  return React.createElement(React.Fragment, null, children);
260
319
  };
261
- const component$8 = React.memo(FlowAction);
262
- component$8.displayName = 'FlowerAction';
263
- const FlowerAction = component$8;
320
+ const component$7 = React.memo(FlowAction);
321
+ component$7.displayName = 'FlowerAction';
322
+ const FlowerAction = component$7;
264
323
 
265
324
  const _FlowerComponent = ({ children }) => children;
266
- const component$7 = memo(_FlowerComponent);
267
- const FlowerComponent = component$7;
325
+ memo(_FlowerComponent);
268
326
 
269
327
  const _FlowerFlow = ({ children, onEnter, onExit }) => {
270
328
  useEffect(() => {
@@ -310,6 +368,43 @@ const makeActionPayloadOnReset = makeActionPayload(ACTION_TYPES.reset, PAYLOAD_K
310
368
  const makeActionPayloadOnNode = makeActionPayload(ACTION_TYPES.jump, PAYLOAD_KEYS_NEEDED.jump);
311
369
  const makeActionPayloadOnNext = makeActionPayload(ACTION_TYPES.next, PAYLOAD_KEYS_NEEDED.next);
312
370
  const makeActionPayloadOnRestart = makeActionPayload(ACTION_TYPES.restart, PAYLOAD_KEYS_NEEDED.restart);
371
+ const handleHistoryStackChange = (currentIndex, currentNode, flowName, withUrl) => {
372
+ const historyNode = `/${flowName}/${currentNode.nodeId}`;
373
+ if (currentNode.nodeType === 'FlowerAction')
374
+ return currentIndex;
375
+ const nextIndex = currentIndex + 1;
376
+ if (history.state?.index !== nextIndex) {
377
+ window.history.pushState({
378
+ index: nextIndex,
379
+ stack: [...(window.history.state.stack ?? []), historyNode]
380
+ }, '', withUrl ? historyNode : '');
381
+ }
382
+ return nextIndex;
383
+ };
384
+
385
+ const useHistorySync = ({ backAction, nextAction }) => {
386
+ const { dispatch } = ReduxFlowerProvider.getReduxHooks();
387
+ const { index, isActive, setIndex, withUrl } = useHistoryContext();
388
+ useEffect(() => {
389
+ if (!isActive)
390
+ return;
391
+ const initialIndex = window.history.state?.index ?? 0;
392
+ setIndex(initialIndex);
393
+ window.history.replaceState({ index: initialIndex, stack: [...(window.history.state?.stack ?? [])] }, withUrl ? '/' : '', '');
394
+ const onPopState = (event) => {
395
+ const newIndex = window.history.state?.index ?? 0;
396
+ if (newIndex > index) {
397
+ nextAction();
398
+ }
399
+ if (newIndex < index) {
400
+ backAction();
401
+ }
402
+ setIndex(newIndex);
403
+ };
404
+ window.addEventListener('popstate', onPopState);
405
+ return () => window.removeEventListener('popstate', onPopState);
406
+ }, [dispatch, backAction, nextAction]);
407
+ };
313
408
 
314
409
  /** This hook allows you to read flow informations, such as the flowName and ID of the current node.
315
410
  *
@@ -331,10 +426,18 @@ const makeActionPayloadOnRestart = makeActionPayload(ACTION_TYPES.restart, PAYLO
331
426
  */
332
427
  const useFlower = ({ flowName: customFlowName, name } = {}) => {
333
428
  const { name: flowNameDefault, initialData } = useContext(FlowerReactContext);
429
+ const { index, isActive, setIndex, withUrl } = useHistoryContext();
334
430
  const { store, dispatch, useSelector } = ReduxFlowerProvider.getReduxHooks();
335
431
  const flowName = (customFlowName || name || flowNameDefault);
336
432
  const nodeId = useSelector(makeSelectCurrentNodeId(flowName ?? ''));
433
+ const currentNode = useSelector(makeSelectIsCurrentNode(flowName ?? ''));
337
434
  const startId = useSelector(makeSelectStartNodeId(flowName ?? ''));
435
+ useEffect(() => {
436
+ if (currentNode.nodeType === 'FlowerAction')
437
+ return;
438
+ window.history.replaceState({ ...window.history.state }, '', withUrl ? `/${flowName}/${nodeId}` : '');
439
+ }, [nodeId, flowName, withUrl, currentNode]);
440
+ const stack = useMemo(() => window.history.state?.stack?.map((path) => path.split('/')[1]), [window.history.state?.stack]);
338
441
  const emitNavigateEvent = useCallback(
339
442
  //TODO check this function is needed
340
443
  (params) => {
@@ -356,18 +459,37 @@ const useFlower = ({ flowName: customFlowName, name } = {}) => {
356
459
  const { type, payload } = makeActionPayloadOnNext(flowName, params);
357
460
  dispatch({
358
461
  type: `${REDUCER_NAME.FLOWER_FLOW}/${type}`,
359
- payload: {
360
- ...payload,
361
- data: store.getState()
362
- }
462
+ payload: { ...payload, data: store.getState() }
363
463
  });
464
+ if (isActive) {
465
+ setIndex(handleHistoryStackChange(index, currentNode, flowName, withUrl));
466
+ }
364
467
  emitNavigateEvent({ type, payload });
365
468
  }, [dispatch, emitNavigateEvent, flowName, store]);
469
+ /**
470
+ * By doing this, we have a full control over flower navigation from both our buttons and browser back and forward navigation
471
+ * In order to trigger back correctly, trigger a real history back
472
+ * If you use replaceState({ index: 2 }) while at index 3,
473
+ * you visually move to step 2, but the browser still sees you at step 3.
474
+ * As a result:
475
+ * - The browser's Forward button stays disabled
476
+ * - No popstate event is triggered
477
+ * - The history flow is broken
478
+ * Use history.back() instead to preserve proper browser navigation.
479
+ */
480
+ const interceptBack = () => {
481
+ window.history.back();
482
+ };
366
483
  const back = useCallback((param) => {
367
- const { type, payload } = makeActionPayloadOnBack(flowName, param);
368
- dispatch({ type: `${REDUCER_NAME.FLOWER_FLOW}/${type}`, payload });
484
+ const { type, payload } = makeActionPayloadOnBack(isActive ? (stack?.[stack?.length - 1] ?? flowName) : flowName, param);
485
+ dispatch({
486
+ type: `${REDUCER_NAME.FLOWER_FLOW}/${type}`,
487
+ payload
488
+ });
489
+ setIndex(index - 1);
369
490
  emitNavigateEvent({ type, payload });
370
- }, [dispatch, emitNavigateEvent, flowName]);
491
+ }, [dispatch, emitNavigateEvent, flowName, stack]);
492
+ useHistorySync({ backAction: back, nextAction: next });
371
493
  const restart = useCallback((param) => {
372
494
  const { type, payload } = makeActionPayloadOnRestart(flowName, param);
373
495
  dispatch({ type: `${REDUCER_NAME.FLOWER_FLOW}/${type}`, payload });
@@ -376,10 +498,7 @@ const useFlower = ({ flowName: customFlowName, name } = {}) => {
376
498
  const reset = useCallback((param) => {
377
499
  const { type, payload } = makeActionPayloadOnReset(flowName, typeof param === 'string'
378
500
  ? { node: param, initialData }
379
- : {
380
- ...param,
381
- initialData
382
- });
501
+ : { ...param, initialData });
383
502
  dispatch({ type: `${REDUCER_NAME.FLOWER_FLOW}/${type}`, payload });
384
503
  emitNavigateEvent({ type, payload });
385
504
  }, [dispatch, emitNavigateEvent, flowName, initialData]);
@@ -402,7 +521,7 @@ const useFlower = ({ flowName: customFlowName, name } = {}) => {
402
521
  startId,
403
522
  next,
404
523
  jump,
405
- back,
524
+ back: isActive ? interceptBack : back,
406
525
  reset,
407
526
  restart
408
527
  };
@@ -642,4 +761,4 @@ const createSliceWithFlower = (createSliceOptions) => {
642
761
  return slice;
643
762
  };
644
763
 
645
- export { Flower, FlowerAction, FlowerComponent, FlowerFlow, FlowerNavigate, FlowerNode, FlowerProvider, FlowerRoute, FlowerServer, FlowerStart, createSliceWithFlower, createStoreWithFlower, flowerReducers, makeSelectData, reducerFlower, useFlower, useFlowerNavigate };
764
+ export { Flower, FlowerAction, FlowerFlow, FlowerNavigate, FlowerNode, FlowerProvider, FlowerRoute, FlowerServer, FlowerStart, createSliceWithFlower, createStoreWithFlower, flowerReducers, makeSelectData, reducerFlower, useFlower, useFlowerNavigate };
@@ -1,15 +1,3 @@
1
- import React, { PropsWithChildren } from 'react';
2
- type FlowerInitialState = {
3
- startId?: string;
4
- current?: string;
5
- history?: string[];
6
- };
7
- type FlowerClientProps = PropsWithChildren<{
8
- name: string;
9
- destroyOnUnmount?: boolean;
10
- startId?: string | null;
11
- initialState?: FlowerInitialState;
12
- initialData?: Record<string, unknown>;
13
- }>;
14
- export declare const Flower: ({ children, name, destroyOnUnmount, startId, initialState, initialData }: FlowerClientProps) => React.JSX.Element | null;
15
- export {};
1
+ import React from 'react';
2
+ import { FlowerClientProps } from '../types/Flower';
3
+ export declare const Flower: ({ children, name, destroyOnUnmount, persist, startId, initialState, initialData }: FlowerClientProps) => React.JSX.Element | null;
@@ -0,0 +1,5 @@
1
+ import { UseClientInitEventProps, UseFlowerNavigateEventProps, UseSetCurrentEventProps, UseSetHistoryEventProps } from './types';
2
+ export declare const useClientInitEvent: ({ flowName, isInitialized, wsDevtools }: UseClientInitEventProps) => void;
3
+ export declare const useSetHistoryEvent: ({ flowName, isInitialized, wsDevtools }: UseSetHistoryEventProps) => void;
4
+ export declare const useSetCurrentEvent: ({ current, flowName, isInitialized, wsDevtools }: UseSetCurrentEventProps) => void;
5
+ export declare const useFlowerNavigateEvent: ({ current, flowName, isInitialized, wsDevtools, isDisabled }: UseFlowerNavigateEventProps) => void;
@@ -0,0 +1,5 @@
1
+ export * from './useInitNodes';
2
+ export * from './useInitDevtools';
3
+ export * from './useDestroyFlow';
4
+ export * from './eventsHandlers';
5
+ export * from './useSelectorsClient';
@@ -0,0 +1,29 @@
1
+ import { NodeConfig } from '@flowerforce/flower-core';
2
+ import { FlowerClientProps } from '../../../types/Flower';
3
+ import { MutableRefObject } from 'react';
4
+ export type UseClientInitEventProps = {
5
+ isInitialized: string;
6
+ wsDevtools: boolean;
7
+ flowName: string;
8
+ };
9
+ export type UseSetHistoryEventProps = UseClientInitEventProps;
10
+ export type UseSetCurrentEventProps = UseClientInitEventProps & {
11
+ current: string;
12
+ };
13
+ export type UseFlowerNavigateEventProps = UseSetCurrentEventProps & {
14
+ isDisabled: boolean;
15
+ };
16
+ export type UseDestroyFlowProps = {
17
+ one: MutableRefObject<boolean>;
18
+ persist: boolean;
19
+ flowName: string;
20
+ };
21
+ export type UseInitDevtoolsProps = {
22
+ devtoolState: Object;
23
+ flowName: string;
24
+ setWsDevtools: (value: boolean) => void;
25
+ };
26
+ export type UseInitNodesProps = {
27
+ one: MutableRefObject<boolean>;
28
+ nodes: NodeConfig[];
29
+ } & Omit<FlowerClientProps, 'destroyOnUnmount'>;
@@ -0,0 +1,12 @@
1
+ import { useFlowerActions } from '../../types';
2
+ /**
3
+ * Hook centralizzato per sincronizzare la navigazione browser con Redux
4
+ * @param {function} backAction - Azione Redux da chiamare quando si fa "indietro"
5
+ * @param {function} nextAction - Azione Redux da chiamare quando si fa "avanti"
6
+ */
7
+ type UseHistorySyncProps = {
8
+ backAction: () => ReturnType<useFlowerActions['back']>;
9
+ nextAction: () => ReturnType<useFlowerActions['next']>;
10
+ };
11
+ export declare const useHistorySync: ({ backAction, nextAction }: UseHistorySyncProps) => void;
12
+ export {};
@@ -0,0 +1,2 @@
1
+ import { UseDestroyFlowProps } from './types';
2
+ export declare const useDestroyFlow: ({ flowName, one, persist }: UseDestroyFlowProps) => void;
@@ -0,0 +1,2 @@
1
+ import { UseInitDevtoolsProps } from './types';
2
+ export declare const useInitDevtools: ({ devtoolState, setWsDevtools, flowName, }: UseInitDevtoolsProps) => void;
@@ -0,0 +1,2 @@
1
+ import { UseInitNodesProps } from './types';
2
+ export declare const useInitNodes: ({ one, nodes, name, startId, persist, initialData, initialState }: UseInitNodesProps) => void;
@@ -0,0 +1,6 @@
1
+ export declare const useSelectorsClient: (flowName: string) => {
2
+ isInitialized: string;
3
+ current: string;
4
+ isDisabled: boolean;
5
+ prevFlowerNodeId: string | undefined;
6
+ };
@@ -1,3 +1,4 @@
1
+ import { INode } from '@flowerforce/flower-core';
1
2
  export declare const makeActionPayloadOnBack: (flowName: string | undefined, params: any) => {
2
3
  type: string;
3
4
  payload: Record<string, any>;
@@ -18,3 +19,4 @@ export declare const makeActionPayloadOnRestart: (flowName: string | undefined,
18
19
  type: string;
19
20
  payload: Record<string, any>;
20
21
  };
22
+ export declare const handleHistoryStackChange: (currentIndex: number, currentNode: INode, flowName: string, withUrl?: boolean) => number;