@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/CHANGELOG.md CHANGED
@@ -1,3 +1,51 @@
1
+ ## 3.7.2 (2025-04-23)
2
+
3
+
4
+ ### 🩹 Fixes
5
+
6
+ - package lock ([a3bb210](https://github.com/flowerforce/flower/commit/a3bb210))
7
+
8
+
9
+ ### 🧱 Updated Dependencies
10
+
11
+ - Updated flower-core to 3.5.2
12
+
13
+ ## 3.7.1 (2025-04-19)
14
+
15
+
16
+ ### 🧱 Updated Dependencies
17
+
18
+ - Updated flower-core to 3.5.1
19
+
20
+ ## 3.7.0 (2025-04-19)
21
+
22
+
23
+ ### 🚀 Features
24
+
25
+ - remove data blank from init nodes ([#80](https://github.com/flowerforce/flower/pull/80))
26
+
27
+
28
+ ### 🧱 Updated Dependencies
29
+
30
+ - Updated flower-core to 3.5.0
31
+
32
+ ## 3.6.0 (2025-04-19)
33
+
34
+
35
+ ### 🚀 Features
36
+
37
+ - added remove value on hide element ([#68](https://github.com/flowerforce/flower/pull/68))
38
+
39
+
40
+ ### 🩹 Fixes
41
+
42
+ - avoid validate hidden field ([#67](https://github.com/flowerforce/flower/pull/67))
43
+
44
+
45
+ ### 🧱 Updated Dependencies
46
+
47
+ - Updated flower-core to 3.4.0
48
+
1
49
  ## 3.5.0 (2024-10-08)
2
50
 
3
51
 
package/dist/index.cjs.js CHANGED
@@ -5,17 +5,42 @@ var _keyBy = require('lodash/keyBy');
5
5
  var flowerCore = require('@flowerforce/flower-core');
6
6
  var flowerReactContext = require('@flowerforce/flower-react-context');
7
7
  var _get = require('lodash/get');
8
- var toolkit = require('@reduxjs/toolkit');
9
8
  var flowerReactStore = require('@flowerforce/flower-react-store');
9
+ var toolkit = require('@reduxjs/toolkit');
10
10
  var reselect = require('reselect');
11
+ var flowerReactHistoryContext = require('@flowerforce/flower-react-history-context');
11
12
  var flowerReactShared = require('@flowerforce/flower-react-shared');
12
13
  var set = require('lodash/set');
13
14
 
14
- // eslint-disable-next-line import/prefer-default-export
15
- const convertElements = (nodes) => {
16
- const res = flowerCore.CoreUtils.generateNodesForFlowerJson(nodes);
17
- return res;
15
+ const getRulesExists = (rules) => {
16
+ return Object.keys(rules).length ? flowerCore.FlowUtils.mapEdge(rules) : undefined;
18
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 = flowerCore.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
+ });
19
44
 
20
45
  const flowerReducer = toolkit.createSlice({
21
46
  name: flowerCore.REDUCER_NAME.FLOWER_FLOW,
@@ -42,60 +67,37 @@ const selectFlowerHistory = (name) => reselect.createSelector(selectFlower(name)
42
67
  const makeSelectNodesIds = (name) => reselect.createSelector(selectFlower(name), flowerCore.FlowerCoreStateSelectors.makeSelectNodesIds);
43
68
  const makeSelectStartNodeId = (name) => reselect.createSelector(selectFlower(name), flowerCore.FlowerCoreStateSelectors.makeSelectStartNodeId);
44
69
  const makeSelectCurrentNodeId = (name) => reselect.createSelector(selectFlower(name), makeSelectStartNodeId(name), flowerCore.FlowerCoreStateSelectors.makeSelectCurrentNodeId);
70
+ const makeSelectIsCurrentNode = (name) => reselect.createSelector(selectFlower(name), makeSelectCurrentNodeId(name), (flower, current) => flower.nodes[current]);
45
71
  const makeSelectPrevNodeRetain = (name) => reselect.createSelector(makeSelectNodesIds(name), selectFlowerHistory(name), makeSelectCurrentNodeId(name), flowerCore.FlowerCoreStateSelectors.makeSelectPrevNodeRetain);
46
72
  const makeSelectCurrentNodeDisabled = (name) => reselect.createSelector(makeSelectNodesIds(name), makeSelectCurrentNodeId(name), flowerCore.FlowerCoreStateSelectors.makeSelectCurrentNodeDisabled);
47
73
  // dati nel flow selezionato
48
74
  const makeSelectData = (name) => reselect.createSelector(selectFlowerDataNode(name), (data) => data?.data ?? {});
49
75
  reselect.createSelector(selectGlobalData, flowerCore.FlowerStateUtils.getAllData);
50
76
 
51
- /* eslint-disable no-undef */
52
- /* eslint-disable no-underscore-dangle */
53
- /*
54
- * FlowerClient
55
- */
56
- const FlowerClient = ({ children, name, destroyOnUnmount = true, startId = null, initialState = {}, initialData }) => {
57
- const flowName = name;
58
- const { dispatch, store, useSelector } = flowerReactStore.ReduxFlowerProvider.getReduxHooks();
59
- const one = React.useRef(false);
60
- const [wsDevtools, setWsDevtools] = React.useState(flowerCore.devtoolState && _get(flowerCore.devtoolState, '__FLOWER_DEVTOOLS_INITIALIZED__', false));
61
- // TODO could make that transformation in CoreUtils.generateNodesForFlowerJson
62
- // eslint-disable-next-line react-hooks/exhaustive-deps, max-len
63
- const nodes = React.useMemo(
64
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
65
- () => convertElements(React.Children.toArray(children)), [children]);
66
- const nodeById = React.useMemo(() => _keyBy(React.Children.toArray(children), 'props.id'), [children]);
67
- const isInitialized = useSelector(makeSelectStartNodeId(name));
68
- const history = useSelector(selectFlowerHistory(name));
69
- const current = useSelector(makeSelectCurrentNodeId(flowName));
70
- const isDisabled = useSelector(makeSelectCurrentNodeDisabled(flowName));
71
- const prevFlowerNodeId = useSelector(makeSelectPrevNodeRetain(flowName));
77
+ const useInitNodes = ({ one, nodes, name, startId, persist = false, initialData, initialState = {} }) => {
78
+ const { dispatch } = flowerReactStore.ReduxFlowerProvider.getReduxHooks();
72
79
  React.useEffect(() => {
73
80
  if (nodes.length > 0 && one.current === false) {
74
81
  one.current = true;
75
82
  dispatch(flowerActions.initNodes({
76
- name: flowName,
77
- // @ts-expect-error FIX ME
83
+ name,
78
84
  nodes,
79
85
  startId: startId ?? '',
80
- persist: destroyOnUnmount === false,
86
+ persist,
81
87
  initialState
82
88
  }));
83
- if (initialData) {
84
- dispatch(flowerReactStore.flowerDataActions.initData({
85
- rootName: flowName,
86
- initialData: initialData ?? {}
87
- }));
88
- }
89
89
  }
90
- }, [
91
- dispatch,
92
- flowName,
93
- nodes,
94
- startId,
95
- destroyOnUnmount,
96
- initialState,
97
- initialData
98
- ]);
90
+ if (initialData) {
91
+ dispatch(flowerReactStore.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 } = flowerReactStore.ReduxFlowerProvider.getReduxHooks();
99
101
  React.useEffect(() => {
100
102
  /* istanbul ignore next */
101
103
  const eventCb = (msg) => {
@@ -109,32 +111,39 @@ const FlowerClient = ({ children, name, destroyOnUnmount = true, startId = null,
109
111
  dispatch(flowerActions.setCurrentNode({ name: msg.name, node: msg.id }));
110
112
  }
111
113
  // if (msg.action === 'REPLACE_DATA' && msg.name === flowName) {
112
- // dispatch(
113
- // formActions.replaceData({ flowName: msg.name, value: msg.data })
114
- // )
114
+ // dispatch(actions.replaceData({ flowName: msg.name, value: msg.data }))
115
115
  // }
116
116
  // if (msg.action === 'ADD_DATA' && msg.name === flowName) {
117
- // dispatch(formActions.addData({ flowName: msg.name, value: msg.data }))
117
+ // dispatch(actions.addData({ flowName: msg.name, value: msg.data }))
118
118
  // }
119
119
  };
120
120
  /* istanbul ignore next */
121
- if (flowerCore.devtoolState && _get(flowerCore.devtoolState, '__FLOWER_DEVTOOLS__')) {
121
+ if (devtoolState && _get(devtoolState, '__FLOWER_DEVTOOLS__')) {
122
122
  flowerCore.Emitter.on('flower-devtool-to-client', eventCb);
123
123
  }
124
124
  return () => {
125
125
  /* istanbul ignore next */
126
- if (flowerCore.devtoolState && _get(flowerCore.devtoolState, '__FLOWER_DEVTOOLS__')) {
126
+ if (devtoolState && _get(devtoolState, '__FLOWER_DEVTOOLS__')) {
127
127
  flowerCore.Emitter.off('flower-devtool-to-client', eventCb);
128
128
  }
129
129
  };
130
130
  }, [dispatch, flowName]);
131
+ };
132
+
133
+ const useDestroyFlow = ({ flowName, one, persist }) => {
134
+ const { dispatch } = flowerReactStore.ReduxFlowerProvider.getReduxHooks();
131
135
  React.useEffect(() => () => {
132
- // unmount function
133
- if (destroyOnUnmount && one.current === true) {
136
+ if (persist)
137
+ return;
138
+ if (one.current === true) {
134
139
  one.current = false;
135
140
  dispatch(flowerActions.destroy({ name: flowName }));
136
141
  }
137
- }, [dispatch, flowName, destroyOnUnmount]);
142
+ }, [dispatch, flowName, persist]);
143
+ };
144
+
145
+ const useClientInitEvent = ({ flowName, isInitialized, wsDevtools }) => {
146
+ const { store } = flowerReactStore.ReduxFlowerProvider.getReduxHooks();
138
147
  React.useEffect(() => {
139
148
  /* istanbul ignore next */
140
149
  if (isInitialized &&
@@ -150,7 +159,11 @@ const FlowerClient = ({ children, name, destroyOnUnmount = true, startId = null,
150
159
  getState: store.getState
151
160
  });
152
161
  }
153
- }, [dispatch, flowName, wsDevtools, isInitialized, store]);
162
+ }, [flowName, wsDevtools, isInitialized, store]);
163
+ };
164
+ const useSetHistoryEvent = ({ flowName, isInitialized, wsDevtools }) => {
165
+ const { useSelector } = flowerReactStore.ReduxFlowerProvider.getReduxHooks();
166
+ const history = useSelector(selectFlowerHistory(flowName));
154
167
  React.useEffect(() => {
155
168
  /* istanbul ignore next */
156
169
  if (isInitialized &&
@@ -164,7 +177,9 @@ const FlowerClient = ({ children, name, destroyOnUnmount = true, startId = null,
164
177
  history
165
178
  });
166
179
  }
167
- }, [dispatch, flowName, history, wsDevtools, isInitialized]);
180
+ }, [flowName, history, wsDevtools, isInitialized]);
181
+ };
182
+ const useSetCurrentEvent = ({ current, flowName, isInitialized, wsDevtools }) => {
168
183
  React.useEffect(() => {
169
184
  if (!current)
170
185
  return;
@@ -184,6 +199,9 @@ const FlowerClient = ({ children, name, destroyOnUnmount = true, startId = null,
184
199
  });
185
200
  }
186
201
  }, [flowName, current, wsDevtools, isInitialized]);
202
+ };
203
+ const useFlowerNavigateEvent = ({ current, flowName, isInitialized, wsDevtools, isDisabled }) => {
204
+ const { dispatch } = flowerReactStore.ReduxFlowerProvider.getReduxHooks();
187
205
  React.useEffect(() => {
188
206
  if (!current)
189
207
  return;
@@ -191,7 +209,7 @@ const FlowerClient = ({ children, name, destroyOnUnmount = true, startId = null,
191
209
  if (!isInitialized)
192
210
  return;
193
211
  if (isDisabled) {
194
- dispatch(flowerActions.next({ flowName }));
212
+ dispatch({ type: `${flowerCore.REDUCER_NAME.FLOWER_FLOW}/next`, payload: { flowName, disabled: true } });
195
213
  // eslint-disable-next-line no-underscore-dangle, no-undef
196
214
  /* istanbul ignore next */
197
215
  if (wsDevtools &&
@@ -214,7 +232,7 @@ const FlowerClient = ({ children, name, destroyOnUnmount = true, startId = null,
214
232
  flowerCore.devtoolState &&
215
233
  _get(flowerCore.devtoolState, '__FLOWER_DEVTOOLS__')) {
216
234
  if (isInitialized === current)
217
- return; // salto il primo event
235
+ return; // salto il primo evento
218
236
  flowerCore.Emitter.emit('flower-devtool-from-client', {
219
237
  source: 'flower-client',
220
238
  action: 'SET_SELECTED',
@@ -223,15 +241,55 @@ const FlowerClient = ({ children, name, destroyOnUnmount = true, startId = null,
223
241
  time: new Date()
224
242
  });
225
243
  }
226
- }, [
227
- dispatch,
228
- flowName,
244
+ }, [dispatch, flowName, current, isDisabled, wsDevtools, isInitialized]);
245
+ };
246
+
247
+ const useSelectorsClient = (flowName) => {
248
+ const { useSelector } = flowerReactStore.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,
229
255
  current,
230
256
  isDisabled,
231
- store,
232
- wsDevtools,
233
- isInitialized
234
- ]);
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 = React.useRef(false);
268
+ const [wsDevtools, setWsDevtools] = React.useState(flowerCore.devtoolState && _get(flowerCore.devtoolState, '__FLOWER_DEVTOOLS_INITIALIZED__', false));
269
+ const nodes = React.useMemo(() => generateNodesForFlowerJson(React.Children.toArray(children)), [children]);
270
+ const nodeById = React.useMemo(() => _keyBy(React.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: flowerCore.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
+ });
235
293
  const currentNodeId = prevFlowerNodeId || current;
236
294
  const contextValues = React.useMemo(() => ({
237
295
  name: flowName,
@@ -245,10 +303,10 @@ const FlowerClient = ({ children, name, destroyOnUnmount = true, startId = null,
245
303
  React.createElement(flowerReactContext.FlowerReactProvider, { value: prevContextValues }, nodeById[currentNodeId]),
246
304
  React.createElement(flowerReactContext.FlowerReactProvider, { value: contextValues }, !isDisabled && current !== currentNodeId && nodeById[current]))) : null;
247
305
  };
248
- const component$9 = React.memo(FlowerClient);
249
- component$9.displayName = 'Flower';
306
+ const component$8 = React.memo(FlowerClient);
307
+ component$8.displayName = 'Flower';
250
308
  // workaround for let typescript read JSX component as a valid JSX element using react 19(?)
251
- const Flower = component$9;
309
+ const Flower = component$8;
252
310
 
253
311
  const FlowAction = ({ children, onEnter, onExit }) => {
254
312
  React.useEffect(() => {
@@ -259,13 +317,12 @@ const FlowAction = ({ children, onEnter, onExit }) => {
259
317
  }, [onEnter, onExit]);
260
318
  return React.createElement(React.Fragment, null, children);
261
319
  };
262
- const component$8 = React.memo(FlowAction);
263
- component$8.displayName = 'FlowerAction';
264
- const FlowerAction = component$8;
320
+ const component$7 = React.memo(FlowAction);
321
+ component$7.displayName = 'FlowerAction';
322
+ const FlowerAction = component$7;
265
323
 
266
324
  const _FlowerComponent = ({ children }) => children;
267
- const component$7 = React.memo(_FlowerComponent);
268
- const FlowerComponent = component$7;
325
+ React.memo(_FlowerComponent);
269
326
 
270
327
  const _FlowerFlow = ({ children, onEnter, onExit }) => {
271
328
  React.useEffect(() => {
@@ -311,6 +368,43 @@ const makeActionPayloadOnReset = makeActionPayload(ACTION_TYPES.reset, PAYLOAD_K
311
368
  const makeActionPayloadOnNode = makeActionPayload(ACTION_TYPES.jump, PAYLOAD_KEYS_NEEDED.jump);
312
369
  const makeActionPayloadOnNext = makeActionPayload(ACTION_TYPES.next, PAYLOAD_KEYS_NEEDED.next);
313
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 } = flowerReactStore.ReduxFlowerProvider.getReduxHooks();
387
+ const { index, isActive, setIndex, withUrl } = flowerReactHistoryContext.useHistoryContext();
388
+ React.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
+ };
314
408
 
315
409
  /** This hook allows you to read flow informations, such as the flowName and ID of the current node.
316
410
  *
@@ -332,10 +426,18 @@ const makeActionPayloadOnRestart = makeActionPayload(ACTION_TYPES.restart, PAYLO
332
426
  */
333
427
  const useFlower = ({ flowName: customFlowName, name } = {}) => {
334
428
  const { name: flowNameDefault, initialData } = React.useContext(flowerReactContext.FlowerReactContext);
429
+ const { index, isActive, setIndex, withUrl } = flowerReactHistoryContext.useHistoryContext();
335
430
  const { store, dispatch, useSelector } = flowerReactStore.ReduxFlowerProvider.getReduxHooks();
336
431
  const flowName = (customFlowName || name || flowNameDefault);
337
432
  const nodeId = useSelector(makeSelectCurrentNodeId(flowName ?? ''));
433
+ const currentNode = useSelector(makeSelectIsCurrentNode(flowName ?? ''));
338
434
  const startId = useSelector(makeSelectStartNodeId(flowName ?? ''));
435
+ React.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 = React.useMemo(() => window.history.state?.stack?.map((path) => path.split('/')[1]), [window.history.state?.stack]);
339
441
  const emitNavigateEvent = React.useCallback(
340
442
  //TODO check this function is needed
341
443
  (params) => {
@@ -357,18 +459,37 @@ const useFlower = ({ flowName: customFlowName, name } = {}) => {
357
459
  const { type, payload } = makeActionPayloadOnNext(flowName, params);
358
460
  dispatch({
359
461
  type: `${flowerCore.REDUCER_NAME.FLOWER_FLOW}/${type}`,
360
- payload: {
361
- ...payload,
362
- data: store.getState()
363
- }
462
+ payload: { ...payload, data: store.getState() }
364
463
  });
464
+ if (isActive) {
465
+ setIndex(handleHistoryStackChange(index, currentNode, flowName, withUrl));
466
+ }
365
467
  emitNavigateEvent({ type, payload });
366
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
+ };
367
483
  const back = React.useCallback((param) => {
368
- const { type, payload } = makeActionPayloadOnBack(flowName, param);
369
- dispatch({ type: `${flowerCore.REDUCER_NAME.FLOWER_FLOW}/${type}`, payload });
484
+ const { type, payload } = makeActionPayloadOnBack(isActive ? (stack?.[stack?.length - 1] ?? flowName) : flowName, param);
485
+ dispatch({
486
+ type: `${flowerCore.REDUCER_NAME.FLOWER_FLOW}/${type}`,
487
+ payload
488
+ });
489
+ setIndex(index - 1);
370
490
  emitNavigateEvent({ type, payload });
371
- }, [dispatch, emitNavigateEvent, flowName]);
491
+ }, [dispatch, emitNavigateEvent, flowName, stack]);
492
+ useHistorySync({ backAction: back, nextAction: next });
372
493
  const restart = React.useCallback((param) => {
373
494
  const { type, payload } = makeActionPayloadOnRestart(flowName, param);
374
495
  dispatch({ type: `${flowerCore.REDUCER_NAME.FLOWER_FLOW}/${type}`, payload });
@@ -377,10 +498,7 @@ const useFlower = ({ flowName: customFlowName, name } = {}) => {
377
498
  const reset = React.useCallback((param) => {
378
499
  const { type, payload } = makeActionPayloadOnReset(flowName, typeof param === 'string'
379
500
  ? { node: param, initialData }
380
- : {
381
- ...param,
382
- initialData
383
- });
501
+ : { ...param, initialData });
384
502
  dispatch({ type: `${flowerCore.REDUCER_NAME.FLOWER_FLOW}/${type}`, payload });
385
503
  emitNavigateEvent({ type, payload });
386
504
  }, [dispatch, emitNavigateEvent, flowName, initialData]);
@@ -403,7 +521,7 @@ const useFlower = ({ flowName: customFlowName, name } = {}) => {
403
521
  startId,
404
522
  next,
405
523
  jump,
406
- back,
524
+ back: isActive ? interceptBack : back,
407
525
  reset,
408
526
  restart
409
527
  };
@@ -647,9 +765,12 @@ Object.defineProperty(exports, "createApi", {
647
765
  enumerable: true,
648
766
  get: function () { return flowerReactStore.createApi; }
649
767
  });
768
+ Object.defineProperty(exports, "HistoryContextProvider", {
769
+ enumerable: true,
770
+ get: function () { return flowerReactHistoryContext.HistoryContextProvider; }
771
+ });
650
772
  exports.Flower = Flower;
651
773
  exports.FlowerAction = FlowerAction;
652
- exports.FlowerComponent = FlowerComponent;
653
774
  exports.FlowerFlow = FlowerFlow;
654
775
  exports.FlowerNavigate = FlowerNavigate;
655
776
  exports.FlowerNode = FlowerNode;