@ostack.tech/ui-kform 0.12.5 → 0.13.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.
@@ -591,6 +591,12 @@
591
591
  opacity: 0.9;
592
592
  }
593
593
 
594
+ .o-ui-kform-issues-alert .o-ui-feedback {
595
+ color: inherit;
596
+ font-size: inherit;
597
+ line-height: inherit;
598
+ }
599
+
594
600
  .o-ui-kform-issues-panel {
595
601
  border-radius: var(--o-ui-border-radius-sm) var(--o-ui-border-radius-sm) 0 0;
596
602
  pointer-events: auto;
@@ -1,8 +1,8 @@
1
1
  import { jsx, jsxs, Fragment } from "react/jsx-runtime";
2
- import { usePrefix as usePrefix$1, useControllableState, useLatestValues, LocalizationProvider as LocalizationProvider$1, combineEventHandlers, 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, VisuallyHidden, Feedback, FeedbackList, FeedbackPopover, usePrintClassNames, useMeasure, Layer, Stack, useMediaBreakpointUp, DropdownMenu, DropdownMenuTrigger, Button, DropdownMenuContent, DropdownMenuRadioGroup, DropdownMenuGroup, DropdownMenuSub, DropdownMenuSubTrigger, DropdownMenuSubContent, DropdownMenuItem, useAlertDialog, DropdownMenuRadioItem, IconButton, controlStatusToAccent, Tab, boolDataAttr, TabList, combineAriaIds, useIsInTableCell, useDataTableColumnLabel, useOnFieldLabelChange, Checkbox, OptionsGroup, Option, CheckboxGroup, useDateTransformer, DateInput, DateRangeInput, Input, Dialog, Tooltip, DialogTrigger, ControlAddon, Icon, DialogContent, DialogHeader, DialogTitle, DialogBody, Alert, Popover, PopoverTrigger, PopoverContent, Container, Select, MenuListItem, MenuList, StepContent, Step, StepList, Stepper, StepperFinishTrigger, StepperNextTrigger, StepperPreviousTrigger, useKeyboardShortcut, CloseButton, useScrollPosition, setBoolDataAttr, Card, CardHeader, CardTitle, CardBody, useIntersectionObserver, NumericInput, Link, usePrint, usePrinterDocumentTitle, PrinterTrigger, RadioGroup, Radio, ButtonGroup, AlertDialog, AlertDialogTrigger, AlertDialogContent, AlertDialogHeader, AlertDialogTitle, AlertDialogBody, AlertDialogDescription, AlertDialogFooter, AlertDialogCancel, AlertDialogAction, DataTableCell, DataTableRow, useDataTableApiRef, DataTable, Slot, DataTableContent, DataTablePagination, DataTableRowsPerPage, TextArea } from "@ostack.tech/ui";
2
+ import { usePrefix as usePrefix$1, useControllableState, useLatestValues, LocalizationProvider as LocalizationProvider$1, combineEventHandlers, usePrinting, useConstant, VisuallyHidden, 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, usePrintClassNames, useMeasure, Layer, Stack, useMediaBreakpointUp, DropdownMenu, DropdownMenuTrigger, Button, DropdownMenuContent, DropdownMenuRadioGroup, DropdownMenuGroup, DropdownMenuSub, DropdownMenuSubTrigger, DropdownMenuSubContent, DropdownMenuItem, useAlertDialog, DropdownMenuRadioItem, IconButton, controlStatusToAccent, Tab, boolDataAttr, TabList, combineAriaIds, useIsInTableCell, useDataTableColumnLabel, useOnFieldLabelChange, Checkbox, OptionsGroup, Option, CheckboxGroup, useDateTransformer, DateInput, DateRangeInput, Input, Dialog, Tooltip, DialogTrigger, ControlAddon, Icon, DialogContent, DialogHeader, DialogTitle, DialogBody, Alert, Popover, PopoverTrigger, PopoverContent, Container, Select, MenuListItem, MenuList, StepContent, Step, StepList, Stepper, StepperFinishTrigger, StepperNextTrigger, StepperPreviousTrigger, useKeyboardShortcut, CloseButton, useScrollPosition, setBoolDataAttr, Card, CardHeader, CardTitle, CardBody, useIntersectionObserver, NumericInput, Link, usePrint, usePrinterDocumentTitle, PrinterTrigger, RadioGroup, Radio, ButtonGroup, AlertDialog, AlertDialogTrigger, AlertDialogContent, AlertDialogHeader, AlertDialogTitle, AlertDialogBody, AlertDialogDescription, AlertDialogFooter, AlertDialogCancel, AlertDialogAction, DataTableCell, DataTableRow, useDataTableApiRef, DataTable, Slot, DataTableContent, DataTablePagination, DataTableRowsPerPage, TextArea } 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
- import { useResolvedPath, equals, useFormController, useForm, FormContext, CurrentPath, useCurrentPath, useFormManager, useFormattedValue, InvalidPathError, AtPathError, useIssuesTracker, useFormContext, useInput, useListableInput, formatTemporalAsString, useTemporalInput, useFileInput, toFileList, useController, useNumericInput, formatNumericAsString, useFormatter } from "@ostack.tech/kform-react";
5
- import { createContext, useContext, useCallback, useMemo, useRef, useEffect, forwardRef, useState, useImperativeHandle, startTransition, Suspense, useDeferredValue, Children, isValidElement, useId, createElement, memo } from "react";
4
+ import { useResolvedPath, equals, CurrentPath, useFormController, useForm, FormContext, useCurrentPath, useFormManager, useFormattedValue, InvalidPathError, AtPathError, useIssuesTracker, useFormContext, useInput, useListableInput, formatTemporalAsString, useTemporalInput, useFileInput, toFileList, useController, useNumericInput, formatNumericAsString, useFormatter } from "@ostack.tech/kform-react";
5
+ import { createContext, useContext, useCallback, useMemo, useRef, useEffect, forwardRef, useState, useImperativeHandle, startTransition, Suspense, useDeferredValue, Children, isValidElement, useId, memo } from "react";
6
6
  import { createStore, useStore } from "zustand";
7
7
  import { subscribeWithSelector } from "zustand/middleware";
8
8
  import { useShallow } from "zustand/react/shallow";
@@ -166,6 +166,7 @@ function useCreateFormAppContext({
166
166
  readOnly,
167
167
  issuesDisplayMode,
168
168
  displayIssueCodes,
169
+ issueMessagesDataKey,
169
170
  formAppElement,
170
171
  onPathFocus
171
172
  }) {
@@ -382,6 +383,7 @@ function useCreateFormAppContext({
382
383
  readOnly,
383
384
  issuesDisplayMode,
384
385
  displayIssueCodes,
386
+ issueMessagesDataKey,
385
387
  formAppElement,
386
388
  store
387
389
  }),
@@ -390,6 +392,7 @@ function useCreateFormAppContext({
390
392
  displayIssueCodes,
391
393
  formAppElement,
392
394
  formTitle,
395
+ issueMessagesDataKey,
393
396
  issuesDisplayMode,
394
397
  readOnly,
395
398
  store
@@ -562,6 +565,51 @@ function useSetStartIssuesNavigation(fn) {
562
565
  }
563
566
  }, [fn, printing, store]);
564
567
  }
568
+ const DEFAULT_ISSUE_MESSAGE_DATA_KEY = "message";
569
+ function IssueMessage({
570
+ path,
571
+ issue,
572
+ schema,
573
+ displayIssueCode,
574
+ messageDataKey,
575
+ visuallyHiddenErrorCodePrefix,
576
+ visuallyHiddenWarningCodePrefix,
577
+ unknownErrorMessage,
578
+ unknownWarningMessage,
579
+ issueCodeProps
580
+ }) {
581
+ const { issueMessagesDataKey } = useFormAppContext();
582
+ messageDataKey ??= issueMessagesDataKey;
583
+ const [locale7] = useLocale();
584
+ visuallyHiddenErrorCodePrefix ??= locale7.IssueMessages.visuallyHiddenErrorCodePrefix;
585
+ visuallyHiddenWarningCodePrefix ??= locale7.IssueMessages.visuallyHiddenWarningCodePrefix;
586
+ unknownErrorMessage ??= locale7.IssueMessages.unknownErrorMessage;
587
+ unknownWarningMessage ??= locale7.IssueMessages.unknownWarningMessage;
588
+ let message = useRegisteredIssueMessage(path, issue.code) ?? issue.data[messageDataKey];
589
+ const unknownMessage = message == null;
590
+ if (unknownMessage) {
591
+ message = issue.severity === "error" ? unknownErrorMessage : unknownWarningMessage;
592
+ }
593
+ const globalDisplayIssueCodes = useDisplayIssueCodesInIssueMessages();
594
+ displayIssueCode ??= globalDisplayIssueCodes;
595
+ return /* @__PURE__ */ jsxs(CurrentPath, { path, children: [
596
+ typeof message === "function" ? message(issue.data ?? {}, schema, path) : message,
597
+ (displayIssueCode || unknownMessage) && /* @__PURE__ */ jsxs("span", { ...issueCodeProps, children: [
598
+ " ",
599
+ "(",
600
+ issue.severity === "error" && visuallyHiddenErrorCodePrefix && /* @__PURE__ */ jsxs(VisuallyHidden, { children: [
601
+ visuallyHiddenErrorCodePrefix,
602
+ " "
603
+ ] }),
604
+ issue.severity === "warning" && visuallyHiddenWarningCodePrefix && /* @__PURE__ */ jsxs(VisuallyHidden, { children: [
605
+ visuallyHiddenWarningCodePrefix,
606
+ " "
607
+ ] }),
608
+ issue.code,
609
+ ")"
610
+ ] })
611
+ ] });
612
+ }
565
613
  const FOCUSABLE_ELEMENTS = ["INPUT", "SELECT", "TEXTAREA"];
566
614
  function useControlAutofocus({ usePath, useExists }, enabled = true) {
567
615
  const controlRef = useRef(null);
@@ -784,6 +832,7 @@ const FormApp = forwardRef(function FormApp2({
784
832
  issueMessages,
785
833
  issuesDisplayMode = "inline",
786
834
  displayIssueCodes = false,
835
+ issueMessagesDataKey = DEFAULT_ISSUE_MESSAGE_DATA_KEY,
787
836
  defaultActivePath,
788
837
  activePath,
789
838
  onActivePathChange,
@@ -899,6 +948,7 @@ const FormApp = forwardRef(function FormApp2({
899
948
  readOnly,
900
949
  issuesDisplayMode,
901
950
  displayIssueCodes,
951
+ issueMessagesDataKey,
902
952
  controller,
903
953
  onPathFocus,
904
954
  formAppElement
@@ -1896,52 +1946,12 @@ const ControlField = forwardRef(function ControlField2({
1896
1946
  ]);
1897
1947
  return shown && /* @__PURE__ */ jsx(CurrentPath, { path, children: /* @__PURE__ */ jsx(ControlFieldContext.Provider, { value: store, children: /* @__PURE__ */ jsx(Field, { ...otherProps, ref: forwardedRef }) }) });
1898
1948
  });
1899
- function IssueMessage({
1900
- path,
1901
- issue,
1902
- schema,
1903
- displayIssueCode,
1904
- visuallyHiddenErrorCodePrefix,
1905
- visuallyHiddenWarningCodePrefix,
1906
- unknownErrorMessage,
1907
- unknownWarningMessage,
1908
- issueCodeProps
1909
- }) {
1910
- const [locale7] = useLocale();
1911
- visuallyHiddenErrorCodePrefix ??= locale7.IssueMessages.visuallyHiddenErrorCodePrefix;
1912
- visuallyHiddenWarningCodePrefix ??= locale7.IssueMessages.visuallyHiddenWarningCodePrefix;
1913
- unknownErrorMessage ??= locale7.IssueMessages.unknownErrorMessage;
1914
- unknownWarningMessage ??= locale7.IssueMessages.unknownWarningMessage;
1915
- let message = useRegisteredIssueMessage(path, issue.code);
1916
- const unknownIssue = message == null;
1917
- if (unknownIssue) {
1918
- message = issue.severity === "error" ? unknownErrorMessage : unknownWarningMessage;
1919
- }
1920
- const globalDisplayIssueCodes = useDisplayIssueCodesInIssueMessages();
1921
- displayIssueCode ??= globalDisplayIssueCodes;
1922
- return /* @__PURE__ */ jsxs(CurrentPath, { path, children: [
1923
- typeof message === "function" ? message(issue.data ?? {}, schema, path) : message,
1924
- (displayIssueCode || unknownIssue) && /* @__PURE__ */ jsxs("span", { ...issueCodeProps, children: [
1925
- " ",
1926
- "(",
1927
- issue.severity === "error" && visuallyHiddenErrorCodePrefix && /* @__PURE__ */ jsxs(VisuallyHidden, { children: [
1928
- visuallyHiddenErrorCodePrefix,
1929
- " "
1930
- ] }),
1931
- issue.severity === "warning" && visuallyHiddenWarningCodePrefix && /* @__PURE__ */ jsxs(VisuallyHidden, { children: [
1932
- visuallyHiddenWarningCodePrefix,
1933
- " "
1934
- ] }),
1935
- issue.code,
1936
- ")"
1937
- ] })
1938
- ] });
1939
- }
1940
1949
  const IssueMessages = forwardRef(function IssueMessages2({
1941
1950
  path,
1942
1951
  issues,
1943
1952
  messages,
1944
1953
  displayIssueCodes,
1954
+ messagesDataKey,
1945
1955
  visuallyHiddenErrorCodePrefix,
1946
1956
  visuallyHiddenWarningCodePrefix,
1947
1957
  unknownErrorMessage,
@@ -1993,6 +2003,7 @@ const IssueMessages = forwardRef(function IssueMessages2({
1993
2003
  issue,
1994
2004
  schema,
1995
2005
  displayIssueCode: displayIssueCodes,
2006
+ messageDataKey: messagesDataKey,
1996
2007
  visuallyHiddenErrorCodePrefix,
1997
2008
  visuallyHiddenWarningCodePrefix,
1998
2009
  unknownErrorMessage,
@@ -2005,6 +2016,7 @@ const IssueMessages = forwardRef(function IssueMessages2({
2005
2016
  absolutePath,
2006
2017
  schema,
2007
2018
  displayIssueCodes,
2019
+ messagesDataKey,
2008
2020
  visuallyHiddenErrorCodePrefix,
2009
2021
  visuallyHiddenWarningCodePrefix,
2010
2022
  unknownErrorMessage,
@@ -2099,9 +2111,10 @@ const TopBar = forwardRef(
2099
2111
  ) }) });
2100
2112
  }
2101
2113
  );
2102
- const TopBarActions = forwardRef(function TopBarActions2({ className, ...otherProps }, forwardedRef) {
2114
+ const TopBarActions = forwardRef(function TopBarActions2({ className, children, ...otherProps }, forwardedRef) {
2103
2115
  const prefix = usePrefix();
2104
- return /* @__PURE__ */ jsx(
2116
+ const issuesDisplayMode = useIssuesDisplayMode();
2117
+ return /* @__PURE__ */ jsxs(
2105
2118
  Stack,
2106
2119
  {
2107
2120
  className: cx(prefix("top-bar__actions"), className),
@@ -2109,7 +2122,11 @@ const TopBarActions = forwardRef(function TopBarActions2({ className, ...otherPr
2109
2122
  gap: 2,
2110
2123
  justifyContent: "flex-end",
2111
2124
  ...otherProps,
2112
- ref: forwardedRef
2125
+ ref: forwardedRef,
2126
+ children: [
2127
+ issuesDisplayMode === "inline" && /* @__PURE__ */ jsx(IssuesPopover, { children: /* @__PURE__ */ jsx(IssueMessages, {}) }),
2128
+ children
2129
+ ]
2113
2130
  }
2114
2131
  );
2115
2132
  });
@@ -5060,21 +5077,81 @@ const FormStepper = forwardRef(function FormStepper2({
5060
5077
  const FormStepperFinishTrigger = StepperFinishTrigger;
5061
5078
  const FormStepperNextTrigger = StepperNextTrigger;
5062
5079
  const FormStepperPreviousTrigger = StepperPreviousTrigger;
5063
- const IssueAlert = forwardRef(function IssueMessage2({ path, code, children, ...otherProps }, forwardedRef) {
5064
- const { info } = useIssuesTracker(path);
5065
- const relevantIssues = (info?.flatMap((info2) => info2.issues) ?? []).filter(
5066
- (issue) => issue.code === code
5080
+ const IssuesAlert = forwardRef(function IssuesAlert2({
5081
+ variant = "solid",
5082
+ path,
5083
+ issues,
5084
+ messages,
5085
+ displayIssueCodes,
5086
+ messagesDataKey,
5087
+ visuallyHiddenErrorCodePrefix,
5088
+ visuallyHiddenWarningCodePrefix,
5089
+ unknownErrorMessage,
5090
+ unknownWarningMessage,
5091
+ className,
5092
+ ...otherProps
5093
+ }, forwardedRef) {
5094
+ const prefix = usePrefix();
5095
+ const formManager = useFormManager();
5096
+ const absolutePath = useResolvedPath(path);
5097
+ const { info } = useIssuesTracker(absolutePath, {
5098
+ enabled: !issues
5099
+ });
5100
+ const messagesToRegister = useMemo(
5101
+ () => messages && { [absolutePath.toString()]: messages },
5102
+ [absolutePath, messages]
5103
+ );
5104
+ const deferredTrackedIssues = useDeferredValue(
5105
+ useMemo(() => info?.flatMap((info2) => info2.issues) ?? [], [info])
5106
+ );
5107
+ const deferredIssuesToDisplay = issues ?? deferredTrackedIssues;
5108
+ useReportValidationFailures(
5109
+ useMemo(
5110
+ () => [{ path: absolutePath, issues: deferredIssuesToDisplay }],
5111
+ [absolutePath, deferredIssuesToDisplay]
5112
+ )
5067
5113
  );
5068
- return /* @__PURE__ */ jsx(Fragment, { children: relevantIssues.map((issue, i) => /* @__PURE__ */ createElement(
5114
+ const severity = useMemo(
5115
+ () => deferredIssuesToDisplay.length === 0 ? void 0 : deferredIssuesToDisplay.every((issue) => issue.severity === "warning") ? "warning" : "danger",
5116
+ [deferredIssuesToDisplay]
5117
+ );
5118
+ const prevSeverityRef = useRef(severity);
5119
+ useEffect(() => {
5120
+ prevSeverityRef.current = severity;
5121
+ }, [severity]);
5122
+ const prevSeverity = prevSeverityRef.current;
5123
+ const schema = useMemo(
5124
+ () => formManager.schema(absolutePath),
5125
+ [absolutePath, formManager]
5126
+ );
5127
+ return /* @__PURE__ */ jsx(
5069
5128
  Alert,
5070
5129
  {
5130
+ className: cx(prefix("issues-alert"), className),
5131
+ open: deferredIssuesToDisplay.length > 0,
5132
+ variant,
5071
5133
  ...otherProps,
5072
- severity: issue.severity === "error" ? "danger" : "warning",
5134
+ severity: severity ?? prevSeverity,
5073
5135
  ref: forwardedRef,
5074
- key: i
5075
- },
5076
- typeof children === "function" ? children(issue.data ?? {}) : children
5077
- )) });
5136
+ children: /* @__PURE__ */ jsx(FormAppIssueMessages, { issueMessages: messagesToRegister, children: /* @__PURE__ */ jsx(FeedbackList, { children: deferredIssuesToDisplay.map((issue, i) => /* @__PURE__ */ jsx(Feedback, { type: issue.severity, children: /* @__PURE__ */ jsx(
5137
+ IssueMessage,
5138
+ {
5139
+ path: absolutePath,
5140
+ issue,
5141
+ schema,
5142
+ displayIssueCode: displayIssueCodes,
5143
+ messageDataKey: messagesDataKey,
5144
+ visuallyHiddenErrorCodePrefix,
5145
+ visuallyHiddenWarningCodePrefix,
5146
+ unknownErrorMessage,
5147
+ unknownWarningMessage,
5148
+ issueCodeProps: {
5149
+ className: prefix("issue-messages__issue-code")
5150
+ }
5151
+ }
5152
+ ) }, i)) }) })
5153
+ }
5154
+ );
5078
5155
  });
5079
5156
  function useFormValidator() {
5080
5157
  const startIssuesNavigation = useStartIssuesNavigation();
@@ -7869,7 +7946,7 @@ function useResetOnChange(toReset, {
7869
7946
  const formManager = useFormManager();
7870
7947
  const currentPath = useCurrentPath();
7871
7948
  const resettingValue = useRef(false);
7872
- return async function handleValueChange(event) {
7949
+ const handleValueChange = async (event) => {
7873
7950
  if (!resettingValue.current && when(event)) {
7874
7951
  let resolvedToReset = (Array.isArray(toReset) ? toReset : [toReset]).map(
7875
7952
  (path) => currentPath.resolve(path)
@@ -7886,15 +7963,14 @@ function useResetOnChange(toReset, {
7886
7963
  const { message, ...confirmOptions } = confirmation;
7887
7964
  if (await someIsDirty(formManager, resolvedToReset) && !await confirm(message, { color: "warning", ...confirmOptions })) {
7888
7965
  resettingValue.current = true;
7889
- setTimeout(
7890
- () => formManager.set(event.path, event.oldValue).finally(() => resettingValue.current = false)
7891
- );
7966
+ formManager.set(event.path, event.oldValue).finally(() => resettingValue.current = false);
7892
7967
  return;
7893
7968
  }
7894
7969
  }
7895
- void resetAll(formManager, resolvedToReset, setUntouched, setPristine);
7970
+ await resetAll(formManager, resolvedToReset, setUntouched, setPristine);
7896
7971
  }
7897
7972
  };
7973
+ return (event) => void handleValueChange(event);
7898
7974
  }
7899
7975
  function excludePaths(formManager, paths, exclude) {
7900
7976
  return paths.flatMap(
@@ -7956,8 +8032,8 @@ export {
7956
8032
  FormStepperFinishTrigger,
7957
8033
  FormStepperNextTrigger,
7958
8034
  FormStepperPreviousTrigger,
7959
- IssueAlert,
7960
8035
  IssueMessages,
8036
+ IssuesAlert,
7961
8037
  IssuesPanel,
7962
8038
  IssuesPopover,
7963
8039
  LoadAction,