@ostack.tech/ui-kform 0.4.0 → 0.5.0

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.
Files changed (33) hide show
  1. package/dist/chunks/{en-DlhP9NuN.js → en-DdEhXMHn.js} +6 -2
  2. package/dist/chunks/en-DdEhXMHn.js.map +1 -0
  3. package/dist/locales/en-GB.js +1 -1
  4. package/dist/locales/en-US.js +1 -1
  5. package/dist/locales/fr.js +5 -1
  6. package/dist/locales/fr.js.map +1 -1
  7. package/dist/locales/pt.js +5 -1
  8. package/dist/locales/pt.js.map +1 -1
  9. package/dist/ostack-ui-kform.css +37 -9
  10. package/dist/ostack-ui-kform.css.map +1 -1
  11. package/dist/ostack-ui-kform.js +322 -134
  12. package/dist/ostack-ui-kform.js.map +1 -1
  13. package/dist/types/components/Annexes/Annex.d.ts +2 -0
  14. package/dist/types/components/Annexes/Annexes.d.ts +1 -1
  15. package/dist/types/components/FormApp/FormApp.d.ts +6 -2
  16. package/dist/types/components/FormApp/FormAppContext.d.ts +5 -1
  17. package/dist/types/components/FormApp/index.d.ts +1 -1
  18. package/dist/types/components/LoadAction/LoadAction.d.ts +1 -1
  19. package/dist/types/components/PrintAction/PrintAction.d.ts +40 -0
  20. package/dist/types/components/PrintAction/index.d.ts +1 -0
  21. package/dist/types/components/SaveAction/SaveAction.d.ts +1 -1
  22. package/dist/types/components/SubmitAction/SubmitAction.d.ts +1 -1
  23. package/dist/types/components/TableControl/TableControl.d.ts +1 -1
  24. package/dist/types/components/TableControl/TableControlAddRowTrigger.d.ts +6 -0
  25. package/dist/types/components/TableControl/TableControlColumn.d.ts +3 -1
  26. package/dist/types/components/ValidateAction/ValidateAction.d.ts +1 -1
  27. package/dist/types/index.d.ts +1 -0
  28. package/dist/types/providers/LocalizationProvider/LocalizationObject.d.ts +3 -1
  29. package/dist/types/utils/useFormSaver.d.ts +19 -3
  30. package/package.json +3 -2
  31. package/scss/components/Annexes/_Annexes.scss +20 -0
  32. package/scss/components/FormPages/_FormPages.scss +10 -1
  33. package/dist/chunks/en-DlhP9NuN.js.map +0 -1
@@ -1,5 +1,5 @@
1
1
  import { jsx, jsxs, Fragment } from "react/jsx-runtime";
2
- import { usePrefix as usePrefix$1, useControllableState, useLatestValues, combineEventHandlers, LocalizationProvider as LocalizationProvider$1, useConstant, useSpacing, useCssVars, NATIVE_CONTROLS, useResponsiveValues, useCombinedRef, cx, useIsInRoot, warnOnce, PrefixProvider, Root, computed, TabContent, ErrorBoundary, DocumentTitle, Spinner, useToastManager, Tabs, useErrorReporter, EMPTY_STORE, Field, Feedback, FeedbackList, FeedbackPopover, useMediaBreakpointUp, DropdownMenu, DropdownMenuTrigger, Button, DropdownMenuContent, DropdownMenuRadioGroup, DropdownMenuGroup, DropdownMenuSub, DropdownMenuSubTrigger, DropdownMenuSubContent, DropdownMenuItem, useAlertDialog, DropdownMenuRadioItem, controlStatusToAccent, VisuallyHidden, IconButton, Tab, boolDataAttr, TabList, useIsInTableCell, useDataTableColumnLabel, useOnFieldLabelChange, Checkbox, OptionsGroup, Option, CheckboxGroup, useDateTransformer, DateInput, DateRangeInput, Input, Dialog, Tooltip, DialogTrigger, ControlAddon, Icon, DialogContent, DialogHeader, DialogTitle, DialogBody, Alert, Stack, Popover, PopoverTrigger, PopoverContent, useMeasure, Container, Select, MenuListItem, MenuList, StepContent, Step, StepList, Stepper, CloseButton, useScrollPosition, setBoolDataAttr, Card, CardHeader, CardTitle, CardBody, useIntersectionObserver, useKeyboardShortcut, NumericInput, Link, RadioGroup, Radio, ButtonGroup, AlertDialog, AlertDialogTrigger, AlertDialogContent, AlertDialogHeader, AlertDialogTitle, AlertDialogBody, AlertDialogDescription, AlertDialogFooter, AlertDialogCancel, AlertDialogAction, DataTableCell, DataTableRow, useDataTableApiRef, DataTable, Slot, DataTableContent, DataTablePagination, DataTableRowsPerPage, TextArea, PortalContext } from "@ostack.tech/ui";
2
+ import { usePrefix as usePrefix$1, useControllableState, useLatestValues, combineEventHandlers, LocalizationProvider as LocalizationProvider$1, usePrinting, useConstant, useSpacing, useCssVars, NATIVE_CONTROLS, useResponsiveValues, useCombinedRef, cx, useIsInRoot, warnOnce, usePrintInProgress, PrefixProvider, Root, computed, TabContent, ErrorBoundary, DocumentTitle, Spinner, useToastManager, useStartPrintingTask, Tabs, useErrorReporter, EMPTY_STORE, Field, Feedback, FeedbackList, FeedbackPopover, useMediaBreakpointUp, DropdownMenu, DropdownMenuTrigger, Button, DropdownMenuContent, DropdownMenuRadioGroup, DropdownMenuGroup, DropdownMenuSub, DropdownMenuSubTrigger, DropdownMenuSubContent, DropdownMenuItem, useAlertDialog, DropdownMenuRadioItem, controlStatusToAccent, VisuallyHidden, IconButton, Tab, boolDataAttr, TabList, useIsInTableCell, useDataTableColumnLabel, useOnFieldLabelChange, Checkbox, OptionsGroup, Option, CheckboxGroup, useDateTransformer, DateInput, DateRangeInput, Input, Dialog, Tooltip, DialogTrigger, ControlAddon, Icon, DialogContent, DialogHeader, DialogTitle, DialogBody, Alert, Stack, Popover, PopoverTrigger, PopoverContent, useMeasure, Container, Select, MenuListItem, MenuList, usePrintClassNames, StepContent, Step, StepList, Stepper, CloseButton, useScrollPosition, setBoolDataAttr, Card, CardHeader, CardTitle, CardBody, useIntersectionObserver, useKeyboardShortcut, NumericInput, Link, usePrint, PrinterTrigger, RadioGroup, Radio, ButtonGroup, AlertDialog, AlertDialogTrigger, AlertDialogContent, AlertDialogHeader, AlertDialogTitle, AlertDialogBody, AlertDialogDescription, AlertDialogFooter, AlertDialogCancel, AlertDialogAction, DataTableCell, DataTableRow, useDataTableApiRef, DataTable, Slot, DataTableContent, DataTablePagination, DataTableRowsPerPage, TextArea, PortalContext } from "@ostack.tech/ui";
3
3
  import { AbsolutePath, AbsolutePathFragment, PathMultimap, sliceTable, listableSize, Path, ValidationFailure, nullableSchemaInnerSchema, compareSchemaPaths, PromiseCancellationException, arrayToTable, indexOfTableRowId, isComputedSchema } from "@ostack.tech/kform";
4
4
  import { useResolvedPath, equals, useFormController, useForm, FormContext, CurrentPath, useCurrentPath, useFormManager, useFormattedValue, InvalidPathError, AtPathError, useIssuesTracker, useFormContext, useInput, useListableInput, formatTemporalAsString, useTemporalInput, useFileInput, useController, useNumericInput, formatNumericAsString, useFormatter } from "@ostack.tech/kform-react";
5
5
  import { createContext, useContext, useCallback, useMemo, useRef, useEffect, forwardRef, useState, useImperativeHandle, startTransition, Suspense, useDeferredValue, Children, isValidElement, createElement, memo } from "react";
@@ -8,12 +8,12 @@ import { subscribeWithSelector } from "zustand/middleware";
8
8
  import { useShallow } from "zustand/react/shallow";
9
9
  import { shallow } from "zustand/shallow";
10
10
  import { supported, fileOpen, fileSave } from "browser-fs-access";
11
+ import { addDays, min, max, parseISO, format } from "date-fns";
11
12
  import { enGB } from "./locales/en-GB.js";
12
13
  import { enUS } from "./locales/en-US.js";
13
14
  import { fr } from "./locales/fr.js";
14
15
  import { pt } from "./locales/pt.js";
15
- import { faChevronUp, faChevronDown, faTrash, faFileLines, faDownload, faCircleQuestion, faArrowsToDot, faAnglesLeft, faAngleLeft, faAngleRight, faAnglesRight, faCircleCheck, faCircleExclamation, faTriangleExclamation, faFolderOpen, faFloppyDisk, faCaretDown, faArrowRight, faPlus } from "@fortawesome/free-solid-svg-icons";
16
- import { addDays, min, max, parseISO, format } from "date-fns";
16
+ import { faChevronUp, faChevronDown, faTrash, faFileLines, faDownload, faCircleQuestion, faArrowsToDot, faAnglesLeft, faAngleLeft, faAngleRight, faAnglesRight, faCircleCheck, faCircleExclamation, faTriangleExclamation, faFolderOpen, faPrint, faFloppyDisk, faCaretDown, faArrowRight, faPlus } from "@fortawesome/free-solid-svg-icons";
17
17
  import { faCircleCheck as faCircleCheck$1 } from "@fortawesome/free-regular-svg-icons";
18
18
  const DEFAULT_PREFIX_SUFFIX = "kform-";
19
19
  const defaultPrefixSuffixStore = createStore(() => ({
@@ -80,7 +80,7 @@ function ActivePathProvider({
80
80
  [latest, setActivePath]
81
81
  );
82
82
  return /* @__PURE__ */ jsx(
83
- ActivePathContext,
83
+ ActivePathContext.Provider,
84
84
  {
85
85
  value: useMemo(
86
86
  () => ({
@@ -160,6 +160,7 @@ function useEqualityFn(selector, equalityFn = Object.is) {
160
160
  }
161
161
  const FormAppContext = createContext(null);
162
162
  function useCreateFormAppContext({
163
+ formTitle,
163
164
  controller,
164
165
  disabled,
165
166
  readOnly,
@@ -168,7 +169,7 @@ function useCreateFormAppContext({
168
169
  formAppElement,
169
170
  onPathFocus
170
171
  }) {
171
- const listeners = useLatestValues({ onPathFocus });
172
+ const latest = useLatestValues({ printing: usePrinting(), onPathFocus });
172
173
  const store = useConstant(
173
174
  () => createStore()(
174
175
  subscribeWithSelector((set, get) => ({
@@ -188,6 +189,9 @@ function useCreateFormAppContext({
188
189
  deferredLabelRemovalEntryIds: [],
189
190
  actions: {
190
191
  setIssuesPanelPath: (path) => {
192
+ if (latest.printing) {
193
+ return;
194
+ }
191
195
  const {
192
196
  deferredIssueMessageRemovalEntryIds,
193
197
  deferredLabelRemovalEntryIds
@@ -227,6 +231,9 @@ function useCreateFormAppContext({
227
231
  return breadcrumbParts;
228
232
  },
229
233
  focus: (path) => {
234
+ if (latest.printing) {
235
+ return;
236
+ }
230
237
  const { focusedPath } = get();
231
238
  const absolutePath = path instanceof AbsolutePath ? path : new AbsolutePath(path);
232
239
  if (!get().controller.getState().formManager.isValidPath(absolutePath)) {
@@ -243,11 +250,13 @@ function useCreateFormAppContext({
243
250
  focusCounter: focusCounter + 1
244
251
  }));
245
252
  if (focusPathChanged) {
246
- listeners.onPathFocus?.(absolutePath);
253
+ latest.onPathFocus?.(absolutePath);
247
254
  }
248
255
  },
249
256
  resetFocus: () => {
250
- set({ focusedPath: null });
257
+ if (!latest.printing) {
258
+ set({ focusedPath: null });
259
+ }
251
260
  },
252
261
  registerController: (path, controller2) => {
253
262
  if (controller2 == null) {
@@ -263,7 +272,9 @@ function useCreateFormAppContext({
263
272
  },
264
273
  isRegistered: (path) => get().registeredControllers[0].containsPath(path),
265
274
  setLatestInteraction: (path) => {
266
- set({ latestInteraction: path });
275
+ if (!latest.printing) {
276
+ set({ latestInteraction: path });
277
+ }
267
278
  },
268
279
  registerIssueMessages: (basePath, issueMessages, priority = 0) => {
269
280
  if (issueMessages == null) {
@@ -366,6 +377,7 @@ function useCreateFormAppContext({
366
377
  }, [controller, store]);
367
378
  return useMemo(
368
379
  () => ({
380
+ formTitle,
369
381
  disabled,
370
382
  readOnly,
371
383
  issuesDisplayMode,
@@ -377,6 +389,7 @@ function useCreateFormAppContext({
377
389
  disabled,
378
390
  displayIssueCodes,
379
391
  formAppElement,
392
+ formTitle,
380
393
  issuesDisplayMode,
381
394
  readOnly,
382
395
  store
@@ -390,6 +403,9 @@ function useFormAppContext() {
390
403
  }
391
404
  return formAppContext;
392
405
  }
406
+ function useFormTitle() {
407
+ return useFormAppContext().formTitle;
408
+ }
393
409
  function useFormIsDisabled() {
394
410
  return useFormAppContext().disabled;
395
411
  }
@@ -407,23 +423,26 @@ function useFormAppElement() {
407
423
  }
408
424
  function useSetTopBarHeight() {
409
425
  const { store } = useFormAppContext();
426
+ const printing = usePrinting();
410
427
  return useCallback(
411
- (height) => store.setState({ topBarHeight: height ?? 0 }),
412
- [store]
428
+ (height) => !printing && store.setState({ topBarHeight: height ?? 0 }),
429
+ [printing, store]
413
430
  );
414
431
  }
415
432
  function useSetLeftSidebarWidth() {
416
433
  const { store } = useFormAppContext();
434
+ const printing = usePrinting();
417
435
  return useCallback(
418
- (width) => store.setState({ leftSidebarWidth: width ?? 0 }),
419
- [store]
436
+ (width) => !printing && store.setState({ leftSidebarWidth: width ?? 0 }),
437
+ [printing, store]
420
438
  );
421
439
  }
422
440
  function useSetBottomPanelHeight() {
423
441
  const { store } = useFormAppContext();
442
+ const printing = usePrinting();
424
443
  return useCallback(
425
- (height) => store.setState({ bottomPanelHeight: height ?? 0 }),
426
- [store]
444
+ (height) => !printing && store.setState({ bottomPanelHeight: height ?? 0 }),
445
+ [printing, store]
427
446
  );
428
447
  }
429
448
  function useIssuesPanelPath() {
@@ -447,10 +466,12 @@ function useResetFocus() {
447
466
  function useRegisterController(controller) {
448
467
  const store = useFormAppContext().store;
449
468
  const path = controller.usePath();
450
- useEffect(
451
- () => store.getState().actions.registerController(path, controller),
452
- [store, controller, path]
453
- );
469
+ const printing = usePrinting();
470
+ useEffect(() => {
471
+ if (!printing) {
472
+ return store.getState().actions.registerController(path, controller);
473
+ }
474
+ }, [store, controller, path, printing]);
454
475
  }
455
476
  function useIsRegistered(path) {
456
477
  return useStore(
@@ -472,11 +493,12 @@ function useSetLatestInteraction() {
472
493
  }
473
494
  function useRegisterIssueMessages(path, issueMessages, priority) {
474
495
  const store = useFormAppContext().store;
496
+ const printing = usePrinting();
475
497
  useEffect(() => {
476
- if (path != null) {
498
+ if (!printing && path != null) {
477
499
  return store.getState().actions.registerIssueMessages(path, issueMessages, priority);
478
500
  }
479
- }, [path, issueMessages, priority, store]);
501
+ }, [path, issueMessages, priority, store, printing]);
480
502
  }
481
503
  function useRegisteredIssueMessage(path, code) {
482
504
  return useStore(
@@ -486,11 +508,12 @@ function useRegisteredIssueMessage(path, code) {
486
508
  }
487
509
  function useRegisterLabel(path, label, priority = 0) {
488
510
  const store = useFormAppContext().store;
511
+ const printing = usePrinting();
489
512
  useEffect(() => {
490
- if (path != null) {
513
+ if (!printing && path != null) {
491
514
  return store.getState().actions.registerLabel(path, label, priority);
492
515
  }
493
- }, [store, path, label, priority]);
516
+ }, [store, path, label, priority, printing]);
494
517
  }
495
518
  function useActiveIssuesPanelBreadcrumb() {
496
519
  return useStore(
@@ -518,21 +541,26 @@ function useStartIssuesNavigation() {
518
541
  }
519
542
  function useOnPathFocus(cb, { fireImmediately = true } = {}) {
520
543
  const { store } = useFormAppContext();
521
- useEffect(
522
- () => store.subscribe(
523
- ({ focusedPath, focusCounter }) => ({ focusedPath, focusCounter }),
524
- ({ focusedPath }) => focusedPath && cb(focusedPath),
525
- { fireImmediately, equalityFn: shallow }
526
- ),
527
- [cb, fireImmediately, store]
528
- );
544
+ const printing = usePrinting();
545
+ useEffect(() => {
546
+ if (!printing) {
547
+ return store.subscribe(
548
+ ({ focusedPath, focusCounter }) => ({ focusedPath, focusCounter }),
549
+ ({ focusedPath }) => focusedPath && cb(focusedPath),
550
+ { fireImmediately, equalityFn: shallow }
551
+ );
552
+ }
553
+ }, [cb, fireImmediately, printing, store]);
529
554
  }
530
555
  function useSetStartIssuesNavigation(fn) {
531
556
  const { store } = useFormAppContext();
557
+ const printing = usePrinting();
532
558
  useEffect(() => {
533
- store.setState({ startIssuesNavigation: fn });
534
- return () => store.setState({ startIssuesNavigation: void 0 });
535
- }, [fn, store]);
559
+ if (!printing) {
560
+ store.setState({ startIssuesNavigation: fn });
561
+ return () => store.setState({ startIssuesNavigation: void 0 });
562
+ }
563
+ }, [fn, printing, store]);
536
564
  }
537
565
  const FOCUSABLE_ELEMENTS = ["INPUT", "SELECT", "TEXTAREA"];
538
566
  function useControlAutofocus({ usePath, useExists }, enabled = true) {
@@ -741,6 +769,7 @@ const FormApp = forwardRef(function FormApp2({
741
769
  errorBoundaryProps,
742
770
  schema,
743
771
  initialValue,
772
+ formTitle,
744
773
  issuesPanelLabel,
745
774
  disabled = false,
746
775
  readOnly = false,
@@ -819,7 +848,8 @@ const FormApp = forwardRef(function FormApp2({
819
848
  "FormApp: No locale has been provided. Either provide a `defaultLocale`/`locale` property or wrap the component in a `LocalizationProvider`."
820
849
  );
821
850
  }
822
- issuesPanelLabel ??= locale.FormApp.issuesPanelLabel;
851
+ formTitle ??= locale.FormApp.formTitle;
852
+ issuesPanelLabel ??= locale.FormApp.issuesPanelLabel ?? formTitle;
823
853
  confirmUnloadMessage ??= locale.FormApp.confirmUnloadMessage;
824
854
  const controller = useForm(schema, {
825
855
  initialValue,
@@ -858,8 +888,10 @@ const FormApp = forwardRef(function FormApp2({
858
888
  }),
859
889
  [controller, formManager]
860
890
  );
861
- const displayDisabled = controller.useSubmitting() || disabled;
891
+ const printInProgress = usePrintInProgress();
892
+ const displayDisabled = controller.useSubmitting() || disabled || printInProgress;
862
893
  const formAppContextValue = useCreateFormAppContext({
894
+ formTitle,
863
895
  disabled: displayDisabled,
864
896
  readOnly,
865
897
  issuesDisplayMode,
@@ -987,6 +1019,7 @@ function useCreateAnnexesContext({
987
1019
  const { activePath, onActivePathChange } = useActivePathContext();
988
1020
  activeAnnex ??= activePath;
989
1021
  const latest = useLatestValues({
1022
+ printing: usePrinting(),
990
1023
  formManager,
991
1024
  onActivePathChange,
992
1025
  onActiveAnnexChange,
@@ -1130,6 +1163,9 @@ function useCreateAnnexesContext({
1130
1163
  return newRepetitiveAnnexStates;
1131
1164
  },
1132
1165
  setActiveAnnex: (path) => {
1166
+ if (latest.printing) {
1167
+ return;
1168
+ }
1133
1169
  const newActiveAnnex = path === null || path instanceof AbsolutePath ? path : new AbsolutePath(path);
1134
1170
  const oldActiveAnnex = get().activeAnnex;
1135
1171
  if (!oldActiveAnnex?.equals(newActiveAnnex)) {
@@ -1144,6 +1180,9 @@ function useCreateAnnexesContext({
1144
1180
  }
1145
1181
  },
1146
1182
  updateActiveAnnex: (oldActiveAnnexIndex) => {
1183
+ if (latest.printing) {
1184
+ return;
1185
+ }
1147
1186
  const tabStates = get().tabStates();
1148
1187
  const nextActiveAnnex = get().nextActiveAnnex;
1149
1188
  if (nextActiveAnnex !== null && tabStates.some((state) => state.path.equals(nextActiveAnnex))) {
@@ -1300,10 +1339,13 @@ const AnnexTabContent = forwardRef(function AnnexTabContent2({
1300
1339
  issueMessages,
1301
1340
  children,
1302
1341
  className,
1342
+ containerProps,
1343
+ tabContentLabelProps,
1303
1344
  errorBoundaryProps,
1304
1345
  ...otherProps
1305
1346
  }, forwardedRef) {
1306
1347
  const prefix = usePrefix();
1348
+ const printing = usePrinting();
1307
1349
  const annexPath = useCurrentPath();
1308
1350
  const documentTitle = useAnnexState(
1309
1351
  annexPath,
@@ -1315,13 +1357,36 @@ const AnnexTabContent = forwardRef(function AnnexTabContent2({
1315
1357
  );
1316
1358
  }
1317
1359
  return /* @__PURE__ */ jsx(
1318
- TabContent,
1360
+ "div",
1319
1361
  {
1320
- className: cx(prefix("annexes__annex"), className),
1321
- value: annexPath.toString(),
1322
- ...otherProps,
1323
- ref: forwardedRef,
1324
- children: /* @__PURE__ */ jsx(ErrorBoundary, { ...errorBoundaryProps, children: /* @__PURE__ */ jsx(DocumentTitle, { title: documentTitle ?? void 0, children: /* @__PURE__ */ jsx(FormAppStatus, { disabled, readOnly, children: /* @__PURE__ */ jsx(FormAppIssueMessages, { issueMessages, children: /* @__PURE__ */ jsx(Suspense, { fallback: /* @__PURE__ */ jsx(Spinner, { size: "xl", color: "primary" }), children }) }) }) }) })
1362
+ ...containerProps,
1363
+ className: cx(
1364
+ prefix("annexes__annex-container"),
1365
+ containerProps?.className
1366
+ ),
1367
+ children: /* @__PURE__ */ jsx(
1368
+ TabContent,
1369
+ {
1370
+ className: cx(prefix("annexes__annex"), className),
1371
+ value: annexPath.toString(),
1372
+ tabContentLabelProps: {
1373
+ ...tabContentLabelProps,
1374
+ className: cx(
1375
+ prefix("annexes__annex-label"),
1376
+ tabContentLabelProps?.className
1377
+ )
1378
+ },
1379
+ ...otherProps,
1380
+ ref: forwardedRef,
1381
+ children: /* @__PURE__ */ jsx(ErrorBoundary, { ...errorBoundaryProps, children: /* @__PURE__ */ jsx(
1382
+ DocumentTitle,
1383
+ {
1384
+ title: printing ? void 0 : documentTitle ?? void 0,
1385
+ children: /* @__PURE__ */ jsx(FormAppStatus, { disabled, readOnly, children: /* @__PURE__ */ jsx(FormAppIssueMessages, { issueMessages, children: /* @__PURE__ */ jsx(Suspense, { fallback: /* @__PURE__ */ jsx(Spinner, { size: "xl", color: "primary" }), children }) }) })
1386
+ }
1387
+ ) })
1388
+ }
1389
+ )
1325
1390
  }
1326
1391
  );
1327
1392
  });
@@ -1469,11 +1534,14 @@ function AnnexRegistrar({
1469
1534
  documentTitle
1470
1535
  }) {
1471
1536
  const store = useAnnexesContext();
1537
+ const printing = usePrinting();
1538
+ const finishPrintingTask = useStartPrintingTask();
1472
1539
  const [isNull = true, controller] = useFormattedValue(
1473
1540
  path.append(AbsolutePathFragment.RecursiveWildcard),
1474
1541
  {
1475
1542
  enabled: !useFormIsLoading(),
1476
- format: useCallback((value) => value === null, [])
1543
+ onInitialized: finishPrintingTask,
1544
+ format: useCallback((value2) => value2 === null, [])
1477
1545
  }
1478
1546
  );
1479
1547
  const isRepetitive = index != null;
@@ -1483,16 +1551,18 @@ function AnnexRegistrar({
1483
1551
  (state) => state.initialized && state.exists
1484
1552
  );
1485
1553
  const dirty = controller.useDirty();
1486
- const deferredValue = useDeferredValue(controller.useValue());
1554
+ const value = controller.useValue();
1555
+ const deferredValue = useDeferredValue(value);
1556
+ const relevantValue = printing ? value : deferredValue;
1487
1557
  const deferredIssuesToDisplay = useDeferredValue(
1488
1558
  controller.useState((state) => state.touched ? state.issues : [], {
1489
1559
  equalityFn: shallow
1490
1560
  })
1491
1561
  );
1492
1562
  const deferredDisplayStatus = useDeferredValue(controller.useDisplayStatus());
1493
- const actualTitle = isRepetitive ? typeof itemTitle === "function" ? deferredValue === void 0 ? null : itemTitle(deferredValue, index) : itemTitle === void 0 ? title : itemTitle : typeof title === "function" ? deferredValue === void 0 ? null : title(deferredValue) : title;
1494
- const actualSubtitle = typeof subtitle === "function" ? deferredValue === void 0 ? null : subtitle(deferredValue, index) : subtitle;
1495
- const actualDocumentTitle = typeof documentTitle === "function" ? deferredValue === void 0 ? null : documentTitle(deferredValue, index) : documentTitle === void 0 ? (actualTitle === null || typeof actualTitle === "string") && (actualSubtitle == null || typeof actualSubtitle === "string") ? [actualTitle, actualSubtitle].filter((s) => s).join(" — ") : void 0 : documentTitle;
1563
+ const actualTitle = isRepetitive ? typeof itemTitle === "function" ? relevantValue === void 0 ? null : itemTitle(relevantValue, index) : itemTitle === void 0 ? title : itemTitle : typeof title === "function" ? relevantValue === void 0 ? null : title(relevantValue) : title;
1564
+ const actualSubtitle = typeof subtitle === "function" ? relevantValue === void 0 ? null : subtitle(relevantValue, index) : subtitle;
1565
+ const actualDocumentTitle = typeof documentTitle === "function" ? relevantValue === void 0 ? null : documentTitle(relevantValue, index) : documentTitle === void 0 ? (actualTitle === null || typeof actualTitle === "string") && (actualSubtitle == null || typeof actualSubtitle === "string") ? [actualTitle, actualSubtitle].filter((s) => s).join(" — ") : void 0 : documentTitle;
1496
1566
  useEffect(() => {
1497
1567
  if (exists) {
1498
1568
  const { registerAnnexState } = store.getState().actions;
@@ -1546,8 +1616,10 @@ function RepetitiveAnnexRegistrar({
1546
1616
  ...annexProps
1547
1617
  }) {
1548
1618
  const store = useAnnexesContext();
1619
+ const finishPrintingTask = useStartPrintingTask();
1549
1620
  const [rowIds, controller] = useFormattedValue(path.parent(), {
1550
1621
  enabled: !useFormIsLoading(),
1622
+ onInitialized: finishPrintingTask,
1551
1623
  format: useCallback(
1552
1624
  (value) => value == null ? [] : sliceTable(value).map(([id]) => id),
1553
1625
  []
@@ -1700,6 +1772,7 @@ const Annexes = forwardRef(
1700
1772
  activationMode: "manual",
1701
1773
  value: activeAnnexString,
1702
1774
  onValueChange: handleValueChange,
1775
+ showAllTabsWhilePrinting: true,
1703
1776
  ...otherProps,
1704
1777
  ref: forwardedRef,
1705
1778
  children
@@ -2541,6 +2614,7 @@ function useRegisterControl({
2541
2614
  preventAutoFocus,
2542
2615
  apiRef
2543
2616
  }) {
2617
+ const printing = usePrinting();
2544
2618
  const { useState: useState2, usePath, useInitialized, useDisplayStatus } = controller;
2545
2619
  const path = usePath();
2546
2620
  const formIsDisabled = useFormIsDisabled();
@@ -2549,13 +2623,20 @@ function useRegisterControl({
2549
2623
  const deferredIsValidating = useDeferredValue(
2550
2624
  useState2((state) => state.validationStatus === "validating")
2551
2625
  );
2552
- const displayLoading = !useInitialized() || deferredIsValidating;
2626
+ const initialized = useInitialized();
2627
+ const displayLoading = !initialized || deferredIsValidating;
2553
2628
  const displayStatusToDisplay = useDeferredValue(useDisplayStatus());
2554
2629
  const issuesToDisplay = useDeferredValue(
2555
2630
  useState2((state) => state.touched ? state.issues : [], {
2556
2631
  equalityFn: shallow
2557
2632
  })
2558
2633
  );
2634
+ const finishPrintingTask = useStartPrintingTask();
2635
+ useEffect(() => {
2636
+ if (initialized) {
2637
+ finishPrintingTask();
2638
+ }
2639
+ }, [finishPrintingTask, initialized]);
2559
2640
  const columnLabel = useDataTableColumnLabel();
2560
2641
  useRegisterLabel(
2561
2642
  path,
@@ -2568,24 +2649,24 @@ function useRegisterControl({
2568
2649
  useImperativeHandle(apiRef, () => controller, [controller]);
2569
2650
  const autofocusRef = useControlAutofocus(
2570
2651
  controller,
2571
- !preventAutoFocus
2652
+ !preventAutoFocus && !printing
2572
2653
  );
2573
2654
  const setLatestInteraction = useSetLatestInteraction();
2574
2655
  const handleFocus = useCallback(
2575
2656
  (event) => {
2576
- if (event.target === event.currentTarget && !event.defaultPrevented) {
2657
+ if (!printing && event.target === event.currentTarget && !event.defaultPrevented) {
2577
2658
  setLatestInteraction(controller.getState().path);
2578
2659
  }
2579
2660
  },
2580
- [controller, setLatestInteraction]
2661
+ [controller, printing, setLatestInteraction]
2581
2662
  );
2582
2663
  return useMemo(
2583
2664
  () => ({
2584
- displayLoading,
2585
- displayDisabled,
2586
- displayReadOnly,
2587
- displayStatusToDisplay,
2588
- issuesToDisplay,
2665
+ displayLoading: printing ? false : displayLoading,
2666
+ displayDisabled: printing ? false : displayDisabled,
2667
+ displayReadOnly: printing ? false : displayReadOnly,
2668
+ displayStatusToDisplay: printing ? void 0 : displayStatusToDisplay,
2669
+ issuesToDisplay: printing ? [] : issuesToDisplay,
2589
2670
  autofocusRef,
2590
2671
  handleFocus
2591
2672
  }),
@@ -2596,7 +2677,8 @@ function useRegisterControl({
2596
2677
  displayReadOnly,
2597
2678
  displayStatusToDisplay,
2598
2679
  handleFocus,
2599
- issuesToDisplay
2680
+ issuesToDisplay,
2681
+ printing
2600
2682
  ]
2601
2683
  );
2602
2684
  }
@@ -3526,7 +3608,11 @@ function useCreateFormPagesContext({
3526
3608
  const setLatestInteraction = useSetLatestInteraction();
3527
3609
  const { activePath, onActivePathChange } = useActivePathContext();
3528
3610
  activePage ??= activePath;
3529
- const latest = useLatestValues({ onActivePathChange, onActivePageChange });
3611
+ const latest = useLatestValues({
3612
+ printing: usePrinting(),
3613
+ onActivePathChange,
3614
+ onActivePageChange
3615
+ });
3530
3616
  const store = useConstant(
3531
3617
  () => createStore()(
3532
3618
  subscribeWithSelector((set, get) => ({
@@ -3553,6 +3639,9 @@ function useCreateFormPagesContext({
3553
3639
  get().actions.updateActivePage(oldActivePageIndex);
3554
3640
  },
3555
3641
  setActivePage: (path) => {
3642
+ if (latest.printing) {
3643
+ return;
3644
+ }
3556
3645
  const newActivePage = path === null || path instanceof AbsolutePath ? path : new AbsolutePath(path);
3557
3646
  const oldActivePage = get().activePage;
3558
3647
  if (!oldActivePage?.equals(newActivePage)) {
@@ -3567,7 +3656,7 @@ function useCreateFormPagesContext({
3567
3656
  }
3568
3657
  },
3569
3658
  updateActivePage: (oldActivePageIndex) => {
3570
- if (get().activePage !== null && get().pages.some((page) => page.path.equals(get().activePage))) {
3659
+ if (latest.printing || get().activePage !== null && get().pages.some((page) => page.path.equals(get().activePage))) {
3571
3660
  return;
3572
3661
  }
3573
3662
  get().actions.setActivePage(
@@ -3585,6 +3674,9 @@ function useCreateFormPagesContext({
3585
3674
  get().actions.updateActivePage(oldActivePageIndex);
3586
3675
  },
3587
3676
  setPageHeaderHeight: (path, height) => {
3677
+ if (latest.printing) {
3678
+ return;
3679
+ }
3588
3680
  const {
3589
3681
  pageHeaderHeights: [pageHeaderHeights]
3590
3682
  } = get();
@@ -3658,17 +3750,18 @@ const FormPageHeader = forwardRef(function FormPageHeader2({
3658
3750
  ...otherProps
3659
3751
  }, forwardedRef) {
3660
3752
  const prefix = usePrefix();
3753
+ const printing = usePrinting();
3661
3754
  const currentPath = useCurrentPath();
3662
3755
  const issuesDisplayMode = useIssuesDisplayMode();
3663
3756
  const deferredIssuesToDisplay = useFormPageState(
3664
3757
  currentPath,
3665
3758
  useShallow(
3666
- (state) => issuesDisplayMode === "inline" && state?.deferredIssuesToDisplay || []
3759
+ (state) => !printing && issuesDisplayMode === "inline" && state?.deferredIssuesToDisplay || []
3667
3760
  )
3668
3761
  ) ?? [];
3669
3762
  const deferredDisplayStatus = useFormPageState(
3670
3763
  currentPath,
3671
- (state) => state?.deferredDisplayStatus
3764
+ (state) => printing ? void 0 : state?.deferredDisplayStatus
3672
3765
  );
3673
3766
  const code = useFormPageState(currentPath, (state) => state?.code);
3674
3767
  const title = useFormPageState(currentPath, (state) => state?.title);
@@ -3702,7 +3795,7 @@ const FormPageHeader = forwardRef(function FormPageHeader2({
3702
3795
  children: title
3703
3796
  }
3704
3797
  ),
3705
- /* @__PURE__ */ jsxs(
3798
+ !printing && /* @__PURE__ */ jsxs(
3706
3799
  Stack,
3707
3800
  {
3708
3801
  direction: "row",
@@ -3807,6 +3900,7 @@ const FormPage = forwardRef(
3807
3900
  const prefix = usePrefix();
3808
3901
  const [locale] = useLocale();
3809
3902
  helperButtonLabel ??= locale.FormPage.helperButtonLabel;
3903
+ const printing = usePrinting();
3810
3904
  const store = useFormPagesContext();
3811
3905
  const pagePath = useResolvedPath(path);
3812
3906
  const activePage = useStore(store, (state) => state.activePage);
@@ -3836,60 +3930,66 @@ const FormPage = forwardRef(
3836
3930
  const formAppEl = useFormAppElement();
3837
3931
  const isFirstDisplay = useRef(true);
3838
3932
  useEffect(() => {
3839
- if (shouldDisplay && isFirstDisplay.current) {
3933
+ if (shouldDisplay && !printing && isFirstDisplay.current) {
3840
3934
  formAppEl.scrollIntoView(true);
3841
3935
  isFirstDisplay.current = false;
3842
3936
  return () => {
3843
3937
  isFirstDisplay.current = true;
3844
3938
  };
3845
3939
  }
3846
- }, [formAppEl, shouldDisplay]);
3940
+ }, [formAppEl, printing, shouldDisplay]);
3847
3941
  const combinedHeaderRef = useCombinedRef(setHeaderEl, headerProps?.ref);
3848
- return shouldDisplay ? /* @__PURE__ */ jsx(CurrentPath, { path: pagePath, children: /* @__PURE__ */ jsx(DocumentTitle, { title: documentTitle ?? void 0, children: /* @__PURE__ */ jsx(
3849
- "div",
3942
+ return shouldDisplay || printing ? /* @__PURE__ */ jsx(CurrentPath, { path: pagePath, children: /* @__PURE__ */ jsx(
3943
+ DocumentTitle,
3850
3944
  {
3851
- className: cx(prefix("form-pages__page"), className),
3852
- ...otherProps,
3853
- ref: forwardedRef,
3854
- children: /* @__PURE__ */ jsx(FormAppStatus, { disabled, readOnly, children: /* @__PURE__ */ jsxs(FormAppIssueMessages, { issueMessages, children: [
3855
- /* @__PURE__ */ jsx(
3856
- FormPageHeader,
3857
- {
3858
- helperText,
3859
- helperButtonLabel,
3860
- ownIssueMessages,
3861
- codeProps,
3862
- titleProps,
3863
- headerPopoverContainerProps,
3864
- issuesPopoverProps,
3865
- issueMessagesProps,
3866
- helperButtonProps,
3867
- helperPopoverProps,
3868
- helperPopoverContentProps,
3869
- ...headerProps,
3870
- ref: combinedHeaderRef
3871
- }
3872
- ),
3873
- /* @__PURE__ */ jsx(
3874
- "div",
3875
- {
3876
- ...contentProps,
3877
- className: cx(
3878
- prefix("form-pages__page-content"),
3879
- contentProps?.className
3945
+ title: printing ? void 0 : documentTitle ?? void 0,
3946
+ children: /* @__PURE__ */ jsx(
3947
+ "div",
3948
+ {
3949
+ className: cx(prefix("form-pages__page"), className),
3950
+ ...otherProps,
3951
+ ref: forwardedRef,
3952
+ children: /* @__PURE__ */ jsx(FormAppStatus, { disabled, readOnly, children: /* @__PURE__ */ jsxs(FormAppIssueMessages, { issueMessages, children: [
3953
+ /* @__PURE__ */ jsx(
3954
+ FormPageHeader,
3955
+ {
3956
+ helperText,
3957
+ helperButtonLabel,
3958
+ ownIssueMessages,
3959
+ codeProps,
3960
+ titleProps,
3961
+ headerPopoverContainerProps,
3962
+ issuesPopoverProps,
3963
+ issueMessagesProps,
3964
+ helperButtonProps,
3965
+ helperPopoverProps,
3966
+ helperPopoverContentProps,
3967
+ ...headerProps,
3968
+ ref: combinedHeaderRef
3969
+ }
3880
3970
  ),
3881
- children: /* @__PURE__ */ jsx(Container, { fluid: "md", gutter: 0, ...containerProps, children: /* @__PURE__ */ jsx(ErrorBoundary, { ...errorBoundaryProps, children: /* @__PURE__ */ jsx(
3882
- Suspense,
3971
+ /* @__PURE__ */ jsx(
3972
+ "div",
3883
3973
  {
3884
- fallback: /* @__PURE__ */ jsx(Spinner, { size: "xl", color: "primary" }),
3885
- children
3974
+ ...contentProps,
3975
+ className: cx(
3976
+ prefix("form-pages__page-content"),
3977
+ contentProps?.className
3978
+ ),
3979
+ children: /* @__PURE__ */ jsx(Container, { fluid: "md", gutter: 0, ...containerProps, children: /* @__PURE__ */ jsx(ErrorBoundary, { ...errorBoundaryProps, children: /* @__PURE__ */ jsx(
3980
+ Suspense,
3981
+ {
3982
+ fallback: /* @__PURE__ */ jsx(Spinner, { size: "xl", color: "primary" }),
3983
+ children
3984
+ }
3985
+ ) }) })
3886
3986
  }
3887
- ) }) })
3888
- }
3889
- )
3890
- ] }) })
3987
+ )
3988
+ ] }) })
3989
+ }
3990
+ )
3891
3991
  }
3892
- ) }) }) : null;
3992
+ ) }) : null;
3893
3993
  }
3894
3994
  );
3895
3995
  function FormPageRegistrar({
@@ -3900,9 +4000,10 @@ function FormPageRegistrar({
3900
4000
  issuesPanelLabel
3901
4001
  }) {
3902
4002
  const store = useFormPagesContext();
4003
+ const finishPrintingTask = useStartPrintingTask();
3903
4004
  const controller = useController(
3904
4005
  path.append(AbsolutePathFragment.RecursiveWildcard),
3905
- { enabled: !useFormIsLoading() }
4006
+ { enabled: !useFormIsLoading(), onInitialized: finishPrintingTask }
3906
4007
  );
3907
4008
  const absolutePath = controller.usePath();
3908
4009
  const exists = controller.useState(
@@ -4256,11 +4357,12 @@ const FormPagesNavigation = forwardRef(function FormPagesNavigation2({
4256
4357
  const prefix = usePrefix();
4257
4358
  const [locale] = useLocale();
4258
4359
  ariaLabel ??= locale.FormPagesNavigation["aria-label"];
4360
+ const { printHidden } = usePrintClassNames();
4259
4361
  const isLargeScreen = useMediaBreakpointUp("sm");
4260
4362
  return /* @__PURE__ */ jsx(
4261
4363
  "nav",
4262
4364
  {
4263
- className: cx(prefix("form-pages__navigation"), className),
4365
+ className: cx(prefix("form-pages__navigation"), printHidden, className),
4264
4366
  "data-navigation-mode": isLargeScreen ? "sidebar" : "select",
4265
4367
  "aria-label": ariaLabel,
4266
4368
  ...otherProps,
@@ -4289,6 +4391,7 @@ function useCreateFormStepperContext({
4289
4391
  const { activePath, onActivePathChange } = useActivePathContext();
4290
4392
  activeStep ??= activePath;
4291
4393
  const latest = useLatestValues({
4394
+ printing: usePrinting(),
4292
4395
  formManager,
4293
4396
  onActivePathChange,
4294
4397
  onActiveStepChange,
@@ -4323,6 +4426,9 @@ function useCreateFormStepperContext({
4323
4426
  get().actions.updateActiveStep();
4324
4427
  },
4325
4428
  setActiveStep: (step, callListener = true) => {
4429
+ if (latest.printing) {
4430
+ return;
4431
+ }
4326
4432
  const oldActiveStep = get().activeStep;
4327
4433
  if (!oldActiveStep?.path.equals(step?.path) || oldActiveStep?.index !== step?.index) {
4328
4434
  startTransition(() => {
@@ -4341,7 +4447,7 @@ function useCreateFormStepperContext({
4341
4447
  }
4342
4448
  },
4343
4449
  updateActiveStep: () => {
4344
- if (get().activeStep !== null && get().steps.some(
4450
+ if (latest.printing || get().activeStep !== null && get().steps.some(
4345
4451
  (step) => step.path.equals(get().activeStep.path)
4346
4452
  )) {
4347
4453
  return;
@@ -4363,6 +4469,9 @@ function useCreateFormStepperContext({
4363
4469
  get().actions.updateActiveStep();
4364
4470
  },
4365
4471
  goToStep: async (newStepIndex) => {
4472
+ if (latest.printing) {
4473
+ return;
4474
+ }
4366
4475
  const oldActiveStep = get().activeStep;
4367
4476
  const newActiveStep = get().steps[newStepIndex];
4368
4477
  if (oldActiveStep?.path != newActiveStep?.path && (oldActiveStep?.path == null || newActiveStep?.path == null) || oldActiveStep?.path != null && newActiveStep?.path != null && !newActiveStep.path.contains(oldActiveStep.path)) {
@@ -5154,6 +5263,7 @@ const IssuesPanel = forwardRef(function ValidationPanel({
5154
5263
  ...otherProps
5155
5264
  }, forwardedRef) {
5156
5265
  const prefix = usePrefix();
5266
+ const printing = usePrinting();
5157
5267
  const [locale] = useLocale();
5158
5268
  errorsLabel ??= locale.IssuesPanel.errorsLabel;
5159
5269
  warningsLabel ??= locale.IssuesPanel.warningsLabel;
@@ -5169,7 +5279,7 @@ const IssuesPanel = forwardRef(function ValidationPanel({
5169
5279
  const [open, setOpen] = useControllableState(defaultOpen, controlledOpen);
5170
5280
  const formIsLoading = useFormIsLoading();
5171
5281
  const issuesTrackerResult = useIssuesTracker(AbsolutePath.MATCH_ALL, {
5172
- enabled: open && !formIsLoading,
5282
+ enabled: open && !formIsLoading && !printing,
5173
5283
  issuesOrderCompareFn
5174
5284
  });
5175
5285
  useReportValidationFailures(issuesTrackerResult.info);
@@ -5332,7 +5442,7 @@ const IssuesPanel = forwardRef(function ValidationPanel({
5332
5442
  setContainerEl,
5333
5443
  containerProps?.ref
5334
5444
  );
5335
- return open && /* @__PURE__ */ jsx(
5445
+ return open && !printing && /* @__PURE__ */ jsx(
5336
5446
  "div",
5337
5447
  {
5338
5448
  ...containerProps,
@@ -5421,6 +5531,7 @@ function LoadAction({
5421
5531
  label,
5422
5532
  keybinds,
5423
5533
  loading,
5534
+ enabledWhenLoading,
5424
5535
  disabled,
5425
5536
  onClick,
5426
5537
  decode,
@@ -5452,10 +5563,12 @@ function LoadAction({
5452
5563
  successMessage,
5453
5564
  errorMessage
5454
5565
  });
5455
- const formIsLoading = useFormIsLoading();
5456
5566
  const formIsDisabled = useFormIsDisabled();
5567
+ const formIsLoading = useFormIsLoading();
5568
+ const shouldDisable = disabled || loading && !enabledWhenLoading || formIsDisabled || formIsLoading;
5457
5569
  const formAppEl = useFormAppElement();
5458
5570
  useKeyboardShortcut(keybinds, () => load(), {
5571
+ enabled: !shouldDisable,
5459
5572
  target: formAppEl,
5460
5573
  preventDefault: true
5461
5574
  });
@@ -5467,8 +5580,9 @@ function LoadAction({
5467
5580
  icon: faFolderOpen,
5468
5581
  ...otherProps,
5469
5582
  onClick: combineEventHandlers(() => load(), onClick),
5583
+ disabled: shouldDisable,
5470
5584
  loading: loading || formIsLoading,
5471
- disabled: disabled || formIsDisabled,
5585
+ enabledWhenLoading,
5472
5586
  children: label
5473
5587
  }
5474
5588
  );
@@ -5626,6 +5740,50 @@ function PathLink({
5626
5740
  }
5627
5741
  );
5628
5742
  }
5743
+ function PrintAction({
5744
+ label,
5745
+ keybinds,
5746
+ disabled,
5747
+ loading,
5748
+ enabledWhenLoading,
5749
+ onClick,
5750
+ ...otherProps
5751
+ }) {
5752
+ const [locale] = useLocale();
5753
+ label ??= locale.PrintAction.label;
5754
+ keybinds ??= locale.PrintAction.keybinds;
5755
+ const printInProgress = usePrintInProgress();
5756
+ const formIsDisabled = useFormIsDisabled();
5757
+ const formIsLoading = useFormIsLoading();
5758
+ const shouldDisable = disabled || loading && !enabledWhenLoading || formIsDisabled || formIsLoading || printInProgress;
5759
+ const formAppEl = useFormAppElement();
5760
+ const formTitle = useFormTitle();
5761
+ const print = usePrint();
5762
+ const handlePrint = (evt) => {
5763
+ evt.preventDefault();
5764
+ void print({ documentTitle: formTitle });
5765
+ };
5766
+ useKeyboardShortcut(keybinds, handlePrint, {
5767
+ enabled: !shouldDisable,
5768
+ target: formAppEl,
5769
+ preventDefault: true
5770
+ });
5771
+ return /* @__PURE__ */ jsx(PrinterTrigger, { children: /* @__PURE__ */ jsx(
5772
+ Button,
5773
+ {
5774
+ vertical: true,
5775
+ variant: "subtle",
5776
+ icon: faPrint,
5777
+ onClick: combineEventHandlers(onClick, handlePrint, {
5778
+ checkDefaultPrevented: true
5779
+ }),
5780
+ ...otherProps,
5781
+ loading: loading || printInProgress,
5782
+ disabled: shouldDisable,
5783
+ children: label
5784
+ }
5785
+ ) });
5786
+ }
5629
5787
  const RadioGroupControl = forwardRef(function RadioGroupControl2({
5630
5788
  path,
5631
5789
  options,
@@ -5786,6 +5944,7 @@ function useFormSaver({
5786
5944
  const formManager = useFormManager();
5787
5945
  const { getState, _setState } = useFormController();
5788
5946
  const { addToast } = useToastManager();
5947
+ const formTitle = useFormTitle();
5789
5948
  return useMemo(() => {
5790
5949
  async function save({
5791
5950
  overwrite: overwrite2,
@@ -5824,7 +5983,7 @@ function useFormSaver({
5824
5983
  fileHandle = await fileSave(
5825
5984
  typeof encodedForm === "string" ? new Blob([encodedForm], { type: mimeTypes2?.[0] }) : encodedForm,
5826
5985
  {
5827
- fileName: suggestedFileName,
5986
+ fileName: suggestedFileName || defaultFileName(formTitle, extensions2?.[0]),
5828
5987
  extensions: extensions2,
5829
5988
  description: description2,
5830
5989
  mimeTypes: mimeTypes2,
@@ -5895,9 +6054,11 @@ function useFormSaver({
5895
6054
  extensions,
5896
6055
  fileName,
5897
6056
  formManager,
6057
+ formTitle,
5898
6058
  getState,
5899
6059
  id,
5900
- locale.SaveAction,
6060
+ locale.SaveAction.errorMessage,
6061
+ locale.SaveAction.successMessage,
5901
6062
  mimeTypes,
5902
6063
  overwrite,
5903
6064
  path,
@@ -5909,6 +6070,10 @@ function useFormSaver({
5909
6070
  function useFormIsSaving() {
5910
6071
  return useFormController().useState((state) => state.saving);
5911
6072
  }
6073
+ function defaultFileName(formTitle, extension) {
6074
+ const date = format(/* @__PURE__ */ new Date(), "yyyy-MM-dd");
6075
+ return [[formTitle, date].filter(Boolean).join(" "), extension].filter(Boolean).join("");
6076
+ }
5912
6077
  function SaveAction({
5913
6078
  label,
5914
6079
  keybinds,
@@ -5917,6 +6082,7 @@ function SaveAction({
5917
6082
  saveAsLabel,
5918
6083
  saveAsKeybinds,
5919
6084
  loading,
6085
+ enabledWhenLoading,
5920
6086
  disabled,
5921
6087
  onClick,
5922
6088
  variant = "subtle",
@@ -5957,12 +6123,15 @@ function SaveAction({
5957
6123
  });
5958
6124
  const formIsSaving = useFormIsSaving();
5959
6125
  const formIsLoading = useFormIsLoading();
6126
+ const shouldDisable = disabled || loading && !enabledWhenLoading || formIsSaving || formIsLoading;
5960
6127
  const formAppEl = useFormAppElement();
5961
6128
  useKeyboardShortcut(keybinds, () => save({ overwrite: !disableOverwrite }), {
6129
+ enabled: !shouldDisable,
5962
6130
  target: formAppEl,
5963
6131
  preventDefault: true
5964
6132
  });
5965
6133
  useKeyboardShortcut(saveAsKeybinds, () => save(), {
6134
+ enabled: !shouldDisable,
5966
6135
  target: formAppEl,
5967
6136
  preventDefault: true
5968
6137
  });
@@ -5978,8 +6147,9 @@ function SaveAction({
5978
6147
  () => save({ overwrite: !disableOverwrite }),
5979
6148
  onClick
5980
6149
  ),
6150
+ disabled: shouldDisable,
5981
6151
  loading: loading || formIsSaving,
5982
- disabled: disabled || formIsLoading,
6152
+ enabledWhenLoading,
5983
6153
  children: label
5984
6154
  }
5985
6155
  );
@@ -5994,18 +6164,11 @@ function SaveAction({
5994
6164
  icon: faCaretDown,
5995
6165
  ...saveOptionsProps,
5996
6166
  label: saveOptionsLabel,
5997
- disabled: disabled || loading || formIsSaving || formIsLoading || saveOptionsProps?.disabled,
6167
+ disabled: shouldDisable || saveOptionsProps?.disabled,
5998
6168
  style: { minWidth: 20, ...saveOptionsProps?.style }
5999
6169
  }
6000
6170
  ) }),
6001
- /* @__PURE__ */ jsx(DropdownMenuContent, { align: "end", ...dropdownMenuProps, children: /* @__PURE__ */ jsx(
6002
- DropdownMenuItem,
6003
- {
6004
- onClick: () => save(),
6005
- disabled: disabled || loading || formIsSaving || formIsLoading,
6006
- children: saveAsLabel
6007
- }
6008
- ) })
6171
+ /* @__PURE__ */ jsx(DropdownMenuContent, { align: "end", ...dropdownMenuProps, children: /* @__PURE__ */ jsx(DropdownMenuItem, { onClick: () => save(), disabled: shouldDisable, children: saveAsLabel }) })
6009
6172
  ] })
6010
6173
  ] }) : saveButton;
6011
6174
  }
@@ -6337,6 +6500,7 @@ function SubmitAction({
6337
6500
  keybinds,
6338
6501
  confirmWarnings = true,
6339
6502
  loading,
6503
+ enabledWhenLoading,
6340
6504
  disabled,
6341
6505
  onClick,
6342
6506
  dialogTitle,
@@ -6381,9 +6545,10 @@ function SubmitAction({
6381
6545
  const { submit, useSubmitting } = useFormController();
6382
6546
  const submitting = useSubmitting();
6383
6547
  const [runningOnSubmit, setRunningOnSubmit] = useState(false);
6384
- const formIsLoading = useFormIsLoading();
6385
6548
  const formIsDisabled = useFormIsDisabled();
6549
+ const formIsLoading = useFormIsLoading();
6386
6550
  const formAppEl = useFormAppElement();
6551
+ const shouldDisable = disabled || loading && !enabledWhenLoading || formIsDisabled || formIsLoading || submitting;
6387
6552
  const [submissionInfo, setSubmissionInfo] = useState(null);
6388
6553
  const [checkedWarnings, setCheckedWarnings] = useState([]);
6389
6554
  const allWarningsChecked = !submissionInfo?.warnings || submissionInfo.warnings.every(
@@ -6461,6 +6626,7 @@ function SubmitAction({
6461
6626
  convertExternalIssuesTableRowIndicesToIds
6462
6627
  });
6463
6628
  useKeyboardShortcut(keybinds, handleAction, {
6629
+ enabled: !shouldDisable,
6464
6630
  target: formAppEl,
6465
6631
  preventDefault: true
6466
6632
  });
@@ -6474,8 +6640,9 @@ function SubmitAction({
6474
6640
  iconPlacement: "end",
6475
6641
  ...otherProps,
6476
6642
  onClick: combineEventHandlers(handleAction, onClick),
6643
+ disabled: shouldDisable,
6477
6644
  loading: loading || submitting,
6478
- disabled: disabled || formIsDisabled || formIsLoading,
6645
+ enabledWhenLoading,
6479
6646
  children: label
6480
6647
  }
6481
6648
  ) }),
@@ -6567,13 +6734,14 @@ function useTableControlRowContext() {
6567
6734
  return tableControlRowContext;
6568
6735
  }
6569
6736
  const TableControlCell = forwardRef(function TableControlCell2({ variant, ...otherProps }, forwardedRef) {
6737
+ const printing = usePrinting();
6570
6738
  const { useDisplayStatus } = useTableControlRowContext();
6571
6739
  const deferredDisplayStatus = useDeferredValue(useDisplayStatus());
6572
6740
  return /* @__PURE__ */ jsx(
6573
6741
  DataTableCell,
6574
6742
  {
6575
6743
  variant,
6576
- status: variant === "header" ? displayStatusToControlStatus(deferredDisplayStatus) : void 0,
6744
+ status: !printing && variant === "header" ? displayStatusToControlStatus(deferredDisplayStatus) : void 0,
6577
6745
  ...otherProps,
6578
6746
  ref: forwardedRef
6579
6747
  }
@@ -6588,6 +6756,13 @@ const TableControlRow = memo(
6588
6756
  const path = controller.usePath();
6589
6757
  useRegisterController(controller);
6590
6758
  useRegisterLabel(path, row == null ? null : index + 1);
6759
+ const initialized = controller.useInitialized();
6760
+ const finishPrintingTask = useStartPrintingTask({ enabled: row != null });
6761
+ useEffect(() => {
6762
+ if (initialized) {
6763
+ finishPrintingTask();
6764
+ }
6765
+ }, [finishPrintingTask, initialized]);
6591
6766
  return /* @__PURE__ */ jsx(CurrentPath, { path, children: /* @__PURE__ */ jsx(
6592
6767
  TableControlRowContext.Provider,
6593
6768
  {
@@ -6770,12 +6945,14 @@ const TableControl = forwardRef(function TableControl2({
6770
6945
  [absolutePath, exists, goToId]
6771
6946
  )
6772
6947
  );
6948
+ const printing = usePrinting();
6773
6949
  const dataTableColumns = useMemo(
6774
6950
  () => tableControlToDataTableColumns(columns, {
6775
6951
  disabled: controlIsDisabled,
6776
- readOnly: controlIsReadOnly
6952
+ readOnly: controlIsReadOnly,
6953
+ printing
6777
6954
  }),
6778
- [columns, controlIsDisabled, controlIsReadOnly]
6955
+ [columns, controlIsDisabled, controlIsReadOnly, printing]
6779
6956
  );
6780
6957
  const tableControlController = useMemo(
6781
6958
  () => ({ ...controller, ...ownController }),
@@ -6812,6 +6989,7 @@ const TableControl = forwardRef(function TableControl2({
6812
6989
  loading: !initialized,
6813
6990
  renderRow: (props) => /* @__PURE__ */ jsx(TableControlRow, { ...props }),
6814
6991
  renderCell: (props) => /* @__PURE__ */ jsx(TableControlCell, { ...props }),
6992
+ showAllRowsWhilePrinting: true,
6815
6993
  apiRef: dataTableApiRef,
6816
6994
  ...otherProps,
6817
6995
  ref: forwardedRef
@@ -6854,6 +7032,7 @@ const TableControlAddRowTrigger = forwardRef(function TableControlAddRowTrigger2
6854
7032
  defaultButtonText,
6855
7033
  onRowAdded,
6856
7034
  showWhenReadOnly,
7035
+ showWhilePrinting,
6857
7036
  disabled,
6858
7037
  onClick,
6859
7038
  className,
@@ -6863,6 +7042,7 @@ const TableControlAddRowTrigger = forwardRef(function TableControlAddRowTrigger2
6863
7042
  const prefix = usePrefix();
6864
7043
  const [locale] = useLocale();
6865
7044
  defaultButtonText ??= locale.TableControlAddRowTrigger.defaultButtonText;
7045
+ const printing = usePrinting();
6866
7046
  const { controller, size, maxRows } = useTableControlContext();
6867
7047
  const controlIsDisabled = useFormIsDisabled();
6868
7048
  const controlIsReadOnly = useFormIsReadOnly();
@@ -6876,7 +7056,7 @@ const TableControlAddRowTrigger = forwardRef(function TableControlAddRowTrigger2
6876
7056
  ({ initialized, exists }) => !initialized || !exists || controlIsDisabled || disabled || controlIsReadOnly || maxRows != null && size >= maxRows
6877
7057
  );
6878
7058
  const As = Slot;
6879
- return (showWhenReadOnly || !controlIsReadOnly) && /* @__PURE__ */ jsx(
7059
+ return (showWhenReadOnly || !controlIsReadOnly) && (showWhilePrinting || !printing) && /* @__PURE__ */ jsx(
6880
7060
  As,
6881
7061
  {
6882
7062
  className: cx(prefix("table-control__add-row-trigger"), className),
@@ -6978,7 +7158,7 @@ function tableControlActionsColumn({
6978
7158
  removeRowProps,
6979
7159
  ...columnOverrides
6980
7160
  } = {}) {
6981
- return (tableControlStatus) => !tableControlStatus.readOnly && {
7161
+ return (tableControlStatus) => !tableControlStatus.readOnly && !tableControlStatus.printing && {
6982
7162
  sticky: "right",
6983
7163
  width: 50,
6984
7164
  fixed: true,
@@ -6996,13 +7176,14 @@ const TableControlContent = forwardRef(function TableControlContent2({ container
6996
7176
  void controller.setTouched();
6997
7177
  }
6998
7178
  }, [controller]);
7179
+ const printing = usePrinting();
6999
7180
  const deferredDisplayStatus = useDeferredValue(controller.useDisplayStatus());
7000
7181
  return /* @__PURE__ */ jsx(
7001
7182
  DataTableContent,
7002
7183
  {
7003
7184
  editable: true,
7004
7185
  variant: "control",
7005
- status: displayStatusToControlStatus(deferredDisplayStatus),
7186
+ status: printing ? void 0 : displayStatusToControlStatus(deferredDisplayStatus),
7006
7187
  containerProps: {
7007
7188
  ...containerProps,
7008
7189
  className: cx(
@@ -7154,6 +7335,7 @@ function parseText(formattedValue, state) {
7154
7335
  const TopBar = forwardRef(
7155
7336
  function TopBar2({ className, ...otherProps }, forwardedRef) {
7156
7337
  const prefix = usePrefix();
7338
+ const { printHidden } = usePrintClassNames();
7157
7339
  const setTopBarHeight = useSetTopBarHeight();
7158
7340
  const [topBarEl, setTopBarEl] = useState(null);
7159
7341
  useMeasure(
@@ -7167,7 +7349,7 @@ const TopBar = forwardRef(
7167
7349
  return /* @__PURE__ */ jsx(PortalContext.Provider, { value: { container: topBarEl }, children: /* @__PURE__ */ jsx(
7168
7350
  "div",
7169
7351
  {
7170
- className: cx(prefix("top-bar"), className),
7352
+ className: cx(prefix("top-bar"), printHidden, className),
7171
7353
  ...otherProps,
7172
7354
  ref: combinedTopBarRef
7173
7355
  }
@@ -7192,6 +7374,7 @@ function ValidateAction({
7192
7374
  label,
7193
7375
  keybinds,
7194
7376
  loading,
7377
+ enabledWhenLoading,
7195
7378
  disabled,
7196
7379
  onClick,
7197
7380
  ...otherProps
@@ -7200,11 +7383,14 @@ function ValidateAction({
7200
7383
  label ??= locale.ValidateAction.label;
7201
7384
  keybinds ??= locale.ValidateAction.keybinds;
7202
7385
  const { validate } = useFormValidator();
7203
- const { validatingAutomatically, validating } = useFormIsValidating();
7386
+ const { validatingAutomatically, validatingManually, validating } = useFormIsValidating();
7204
7387
  const deferredValidating = useDeferredValue(validating);
7388
+ const formIsDisabled = useFormIsDisabled();
7205
7389
  const formIsLoading = useFormIsLoading();
7390
+ const shouldDisable = disabled || loading && !enabledWhenLoading || formIsDisabled || formIsLoading || validatingManually;
7206
7391
  const formAppEl = useFormAppElement();
7207
7392
  useKeyboardShortcut(keybinds, validate, {
7393
+ enabled: !shouldDisable,
7208
7394
  target: formAppEl,
7209
7395
  preventDefault: true
7210
7396
  });
@@ -7216,9 +7402,9 @@ function ValidateAction({
7216
7402
  vertical: true,
7217
7403
  ...otherProps,
7218
7404
  onClick: combineEventHandlers(validate, onClick),
7219
- disabled: disabled || formIsLoading,
7405
+ disabled: shouldDisable,
7220
7406
  loading: loading || deferredValidating,
7221
- enabledWhenLoading: validatingAutomatically,
7407
+ enabledWhenLoading: enabledWhenLoading || validatingAutomatically,
7222
7408
  children: label
7223
7409
  }
7224
7410
  );
@@ -7258,6 +7444,7 @@ export {
7258
7444
  PathLink,
7259
7445
  PrefixSuffixContext,
7260
7446
  PrefixSuffixProvider,
7447
+ PrintAction,
7261
7448
  RadioGroupControl,
7262
7449
  RepetitiveAnnexRegistrar,
7263
7450
  SaveAction,
@@ -7297,6 +7484,7 @@ export {
7297
7484
  useFormIsValidating,
7298
7485
  useFormLoader,
7299
7486
  useFormSaver,
7487
+ useFormTitle,
7300
7488
  useFormValidator,
7301
7489
  useIsInControlField,
7302
7490
  useIsRegistered,