@byline/ui 1.10.1 → 1.10.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.
@@ -107,16 +107,19 @@ const FormStatusDisplay = ({ initialData, workflowStatuses, publishedVersion, on
107
107
  function computeStatusTransitions(currentStatus, workflowStatuses, nextStatus) {
108
108
  if (!workflowStatuses || 0 === workflowStatuses.length || !currentStatus) return {
109
109
  primaryStatus: nextStatus,
110
- secondaryStatuses: []
110
+ secondaryStatuses: [],
111
+ isTerminal: false
111
112
  };
112
113
  if (workflowStatuses.length <= 1) return {
113
114
  primaryStatus: void 0,
114
- secondaryStatuses: []
115
+ secondaryStatuses: [],
116
+ isTerminal: false
115
117
  };
116
118
  const currentIndex = workflowStatuses.findIndex((s)=>s.name === currentStatus);
117
119
  if (-1 === currentIndex) return {
118
120
  primaryStatus: nextStatus,
119
- secondaryStatuses: []
121
+ secondaryStatuses: [],
122
+ isTerminal: false
120
123
  };
121
124
  const isAtEnd = currentIndex === workflowStatuses.length - 1;
122
125
  const isAtStart = 0 === currentIndex;
@@ -124,19 +127,15 @@ function computeStatusTransitions(currentStatus, workflowStatuses, nextStatus) {
124
127
  if (!isAtStart && workflowStatuses[0]) availableTargets.push(workflowStatuses[0]);
125
128
  if (currentIndex > 1 && workflowStatuses[currentIndex - 1]) availableTargets.push(workflowStatuses[currentIndex - 1]);
126
129
  if (!isAtEnd && workflowStatuses[currentIndex + 1]) availableTargets.push(workflowStatuses[currentIndex + 1]);
127
- let primaryStatus;
128
- let secondaryStatuses;
129
- if (isAtEnd) {
130
- const prevStatus = workflowStatuses[currentIndex - 1];
131
- primaryStatus = prevStatus;
132
- secondaryStatuses = availableTargets.filter((s)=>s.name !== prevStatus?.name);
133
- } else {
134
- primaryStatus = nextStatus;
135
- secondaryStatuses = availableTargets.filter((s)=>s.name !== nextStatus?.name);
136
- }
130
+ if (isAtEnd) return {
131
+ primaryStatus: workflowStatuses[currentIndex],
132
+ secondaryStatuses: availableTargets,
133
+ isTerminal: true
134
+ };
137
135
  return {
138
- primaryStatus,
139
- secondaryStatuses
136
+ primaryStatus: nextStatus,
137
+ secondaryStatuses: availableTargets.filter((s)=>s.name !== nextStatus?.name),
138
+ isTerminal: false
140
139
  };
141
140
  }
142
141
  const FormContent = ({ mode, fields, onSubmit, onCancel, onStatusChange, onUnpublish, onDelete, onDuplicate, onCopyToLocale, contentLocales, nextStatus, workflowStatuses, publishedVersion, initialData, adminConfig, useAsTitle, useAsPath, headingLabel, headerSlot, collectionPath, initialLocale, onLocaleChange, defaultLocale = 'en', useNavigationGuard: useNavigationGuardProp, restoreWarnings, _activeTabBySet, _onTabChange })=>{
@@ -245,7 +244,7 @@ const FormContent = ({ mode, fields, onSubmit, onCancel, onStatusChange, onUnpub
245
244
  const useGuard = useNavigationGuardProp ?? guardFromContext;
246
245
  const guard = useGuard(hasChanges);
247
246
  const currentStatus = initialData?.status;
248
- const { primaryStatus, secondaryStatuses } = computeStatusTransitions(currentStatus, workflowStatuses, nextStatus);
247
+ const { primaryStatus, secondaryStatuses, isTerminal } = computeStatusTransitions(currentStatus, workflowStatuses, nextStatus);
249
248
  useEffect(()=>subscribeErrors((newErrors)=>setErrors(newErrors)), [
250
249
  subscribeErrors
251
250
  ]);
@@ -415,13 +414,13 @@ const FormContent = ({ mode, fields, onSubmit, onCancel, onStatusChange, onUnpub
415
414
  buttonClassName: classnames('byline-form-actions-combo-button', form_renderer_module["actions-combo-button"]),
416
415
  triggerClassName: classnames('byline-form-actions-combo-trigger', form_renderer_module["actions-combo-trigger"]),
417
416
  options: secondaryStatuses.map((s)=>({
418
- label: s.verb ?? s.label ?? s.name,
417
+ label: isTerminal ? `Revert to ${s.label ?? s.name}` : s.verb ?? s.label ?? s.name,
419
418
  value: s.name
420
419
  })),
421
420
  sideOffset: 5,
422
421
  size: "sm",
423
422
  type: "button",
424
- intent: "success",
423
+ intent: isTerminal ? 'info' : 'success',
425
424
  disabled: statusBusy,
426
425
  onOptionSelect: async (value)=>{
427
426
  setStatusBusy(true);
@@ -431,7 +430,7 @@ const FormContent = ({ mode, fields, onSubmit, onCancel, onStatusChange, onUnpub
431
430
  setStatusBusy(false);
432
431
  }
433
432
  },
434
- onButtonClick: async ()=>{
433
+ onButtonClick: isTerminal ? void 0 : async ()=>{
435
434
  setStatusBusy(true);
436
435
  try {
437
436
  await onStatusChange(primaryStatus.name);
@@ -439,7 +438,7 @@ const FormContent = ({ mode, fields, onSubmit, onCancel, onStatusChange, onUnpub
439
438
  setStatusBusy(false);
440
439
  }
441
440
  },
442
- children: statusBusy ? '...' : primaryStatus.verb ?? primaryStatus.label ?? primaryStatus.name
441
+ children: statusBusy ? '...' : isTerminal ? primaryStatus.label ?? primaryStatus.name : primaryStatus.verb ?? primaryStatus.label ?? primaryStatus.name
443
442
  })
444
443
  }),
445
444
  /*#__PURE__*/ jsx(DocumentActions, {
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "private": false,
4
4
  "type": "module",
5
5
  "license": "MPL-2.0",
6
- "version": "1.10.1",
6
+ "version": "1.10.2",
7
7
  "engines": {
8
8
  "node": ">=20.9.0"
9
9
  },
@@ -50,48 +50,48 @@
50
50
  }
51
51
  },
52
52
  "dependencies": {
53
- "@base-ui/react": "^1.4.0",
53
+ "@base-ui/react": "^1.4.1",
54
54
  "@dnd-kit/core": "^6.3.1",
55
55
  "@dnd-kit/modifiers": "^9.0.0",
56
56
  "@dnd-kit/sortable": "^10.0.0",
57
57
  "@dnd-kit/utilities": "^3.2.2",
58
- "@tanstack/react-form-start": "^1.29.1",
58
+ "@tanstack/react-form-start": "^1.32.0",
59
59
  "classnames": "^2.5.1",
60
60
  "date-fns": "^4.1.0",
61
61
  "lodash-es": "^4.18.1",
62
62
  "motion": "^12.38.0",
63
63
  "npm-run-all": "^4.1.5",
64
- "react-day-picker": "^9.14.0",
64
+ "react-day-picker": "^10.0.0",
65
65
  "react-diff-viewer-continued": "^4.2.2",
66
- "zod": "^4.4.2",
66
+ "zod": "^4.4.3",
67
67
  "zod-form-data": "^3.0.1",
68
- "@byline/client": "1.10.1",
69
- "@byline/core": "1.10.1",
70
- "@byline/admin": "1.10.1"
68
+ "@byline/admin": "1.10.2",
69
+ "@byline/client": "1.10.2",
70
+ "@byline/core": "1.10.2"
71
71
  },
72
72
  "peerDependencies": {
73
73
  "react": "^19.0.0",
74
74
  "react-dom": "^19.0.0"
75
75
  },
76
76
  "devDependencies": {
77
- "@biomejs/biome": "2.4.14",
77
+ "@biomejs/biome": "2.4.15",
78
78
  "@rsbuild/plugin-react": "^2.0.0",
79
- "@rslib/core": "^0.21.3",
79
+ "@rslib/core": "^0.21.4",
80
80
  "@types/lodash": "^4.17.24",
81
81
  "@types/lodash-es": "^4.17.12",
82
- "@types/node": "^25.6.0",
82
+ "@types/node": "^25.6.2",
83
83
  "@types/react": "19.2.14",
84
84
  "@types/react-dom": "19.2.3",
85
85
  "@vitejs/plugin-react": "^6.0.1",
86
86
  "chokidar": "^5.0.0",
87
87
  "lightningcss": "^1.32.0",
88
88
  "lightningcss-cli": "^1.32.0",
89
- "react": "19.2.5",
90
- "react-dom": "19.2.5",
89
+ "react": "^19.2.6",
90
+ "react-dom": "^19.2.6",
91
91
  "rimraf": "^6.1.3",
92
92
  "typescript": "6.0.3",
93
93
  "typescript-plugin-css-modules": "^5.2.0",
94
- "vite": "^8.0.10",
94
+ "vite": "^8.0.12",
95
95
  "vitest": "^4.1.5"
96
96
  },
97
97
  "publishConfig": {
@@ -202,8 +202,12 @@ const FormStatusDisplay = ({
202
202
 
203
203
  /**
204
204
  * Compute the primary and secondary status transitions for the ComboButton.
205
- * - Primary: the main action (forward step, or back step if at the end)
206
- * - Secondary: other available transitions to show as dropdown options
205
+ * - Primary: the main action (forward step), or the current status itself
206
+ * when the document has reached the final workflow step (terminal state).
207
+ * - Secondary: other available transitions to show as dropdown options.
208
+ * - isTerminal: true when the document is at the final workflow status —
209
+ * the primary button renders as a non-actionable indicator and all
210
+ * back-steps move into the dropdown.
207
211
  */
208
212
  function computeStatusTransitions(
209
213
  currentStatus: string | undefined,
@@ -212,20 +216,21 @@ function computeStatusTransitions(
212
216
  ): {
213
217
  primaryStatus: WorkflowStatus | undefined
214
218
  secondaryStatuses: WorkflowStatus[]
219
+ isTerminal: boolean
215
220
  } {
216
221
  if (!workflowStatuses || workflowStatuses.length === 0 || !currentStatus) {
217
- return { primaryStatus: nextStatus, secondaryStatuses: [] }
222
+ return { primaryStatus: nextStatus, secondaryStatuses: [], isTerminal: false }
218
223
  }
219
224
 
220
225
  // Single-status workflows (e.g. SINGLE_STATUS_WORKFLOW for lookups) have
221
226
  // no transitions — short-circuit so the form shows only Close / Save.
222
227
  if (workflowStatuses.length <= 1) {
223
- return { primaryStatus: undefined, secondaryStatuses: [] }
228
+ return { primaryStatus: undefined, secondaryStatuses: [], isTerminal: false }
224
229
  }
225
230
 
226
231
  const currentIndex = workflowStatuses.findIndex((s) => s.name === currentStatus)
227
232
  if (currentIndex === -1) {
228
- return { primaryStatus: nextStatus, secondaryStatuses: [] }
233
+ return { primaryStatus: nextStatus, secondaryStatuses: [], isTerminal: false }
229
234
  }
230
235
 
231
236
  const isAtEnd = currentIndex === workflowStatuses.length - 1
@@ -249,22 +254,23 @@ function computeStatusTransitions(
249
254
  availableTargets.push(workflowStatuses[currentIndex + 1])
250
255
  }
251
256
 
252
- // Determine primary and secondary
253
- let primaryStatus: WorkflowStatus | undefined
254
- let secondaryStatuses: WorkflowStatus[]
255
-
256
257
  if (isAtEnd) {
257
- // At the last status: primary is the back step (previous status)
258
- const prevStatus = workflowStatuses[currentIndex - 1]
259
- primaryStatus = prevStatus
260
- secondaryStatuses = availableTargets.filter((s) => s.name !== prevStatus?.name)
261
- } else {
262
- // Not at end: primary is the forward step (nextStatus)
263
- primaryStatus = nextStatus
264
- secondaryStatuses = availableTargets.filter((s) => s.name !== nextStatus?.name)
258
+ // Terminal state: the primary button is a non-actionable indicator of the
259
+ // current status; both back-steps (revert to previous / reset to first)
260
+ // are surfaced in the dropdown.
261
+ return {
262
+ primaryStatus: workflowStatuses[currentIndex],
263
+ secondaryStatuses: availableTargets,
264
+ isTerminal: true,
265
+ }
265
266
  }
266
267
 
267
- return { primaryStatus, secondaryStatuses }
268
+ // Not at end: primary is the forward step (nextStatus)
269
+ return {
270
+ primaryStatus: nextStatus,
271
+ secondaryStatuses: availableTargets.filter((s) => s.name !== nextStatus?.name),
272
+ isTerminal: false,
273
+ }
268
274
  }
269
275
 
270
276
  const FormContent = ({
@@ -461,7 +467,7 @@ const FormContent = ({
461
467
 
462
468
  // Compute available status transitions
463
469
  const currentStatus = initialData?.status
464
- const { primaryStatus, secondaryStatuses } = computeStatusTransitions(
470
+ const { primaryStatus, secondaryStatuses, isTerminal } = computeStatusTransitions(
465
471
  currentStatus,
466
472
  workflowStatuses,
467
473
  nextStatus
@@ -673,13 +679,15 @@ const FormContent = ({
673
679
  styles['actions-combo-trigger']
674
680
  )}
675
681
  options={secondaryStatuses.map((s) => ({
676
- label: s.verb ?? s.label ?? s.name,
682
+ label: isTerminal
683
+ ? `Revert to ${s.label ?? s.name}`
684
+ : (s.verb ?? s.label ?? s.name),
677
685
  value: s.name,
678
686
  }))}
679
687
  sideOffset={5}
680
688
  size="sm"
681
689
  type="button"
682
- intent="success"
690
+ intent={isTerminal ? 'info' : 'success'}
683
691
  disabled={statusBusy}
684
692
  onOptionSelect={async (value: string) => {
685
693
  setStatusBusy(true)
@@ -689,18 +697,24 @@ const FormContent = ({
689
697
  setStatusBusy(false)
690
698
  }
691
699
  }}
692
- onButtonClick={async () => {
693
- setStatusBusy(true)
694
- try {
695
- await onStatusChange(primaryStatus.name)
696
- } finally {
697
- setStatusBusy(false)
698
- }
699
- }}
700
+ onButtonClick={
701
+ isTerminal
702
+ ? undefined
703
+ : async () => {
704
+ setStatusBusy(true)
705
+ try {
706
+ await onStatusChange(primaryStatus.name)
707
+ } finally {
708
+ setStatusBusy(false)
709
+ }
710
+ }
711
+ }
700
712
  >
701
713
  {statusBusy
702
714
  ? '...'
703
- : (primaryStatus.verb ?? primaryStatus.label ?? primaryStatus.name)}
715
+ : isTerminal
716
+ ? (primaryStatus.label ?? primaryStatus.name)
717
+ : (primaryStatus.verb ?? primaryStatus.label ?? primaryStatus.name)}
704
718
  </ComboButton>
705
719
  </div>
706
720
  )}