@ostack.tech/ui-kform 0.11.3 → 0.12.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.
@@ -8,7 +8,7 @@ import { IssueMessagesByCode } from '../IssueMessages';
8
8
  /** Mode of displaying issue messages. */
9
9
  export type IssuesDisplayMode = "inline" | "panel";
10
10
  /** Properties of the form app component. */
11
- export type FormAppProps<T = any> = Pick<ComponentPropsWithoutRef<typeof Root>, "enableErrorReporting" | "reportError" | "errorReportingUrl" | "errorReportingMethod" | "encodeErrorReport" | "encodedErrorReportMimeType" | "errorReportingOptions" | "baseDocumentTitle" | "documentTitleBaseSeparator" | "documentTitleBreadcrumbsSeparator" | "portalsContainer" | "tooltipsDelayDuration" | "tooltipsSkipDelayDuration" | "disableTooltipsHoverableContent" | "toastsLabel" | "toastsDuration" | "toastsSwipeDirection" | "toastsSwipeThreshold" | "toastViewportHotkey" | "toastViewportLabel" | "toastViewportProps" | "errorBoundaryProps"> & FormOptions<T> & Omit<ComponentPropsWithoutRef<"form">, "onSubmit" | "onReset"> & {
11
+ export type FormAppProps<T = any> = Pick<ComponentPropsWithoutRef<typeof Root>, "enableErrorReporting" | "reportError" | "errorReportingUrl" | "errorReportingMethod" | "encodeErrorReport" | "encodedErrorReportMimeType" | "errorReportingOptions" | "baseDocumentTitle" | "documentTitleBaseSeparator" | "documentTitleBreadcrumbsSeparator" | "portalsContainer" | "tooltipsDelayDuration" | "tooltipsSkipDelayDuration" | "disableTooltipsHoverableContent" | "toastsLabel" | "toastsDuration" | "toastsSwipeDirection" | "toastsSwipeThreshold" | "toastViewportPosition" | "toastViewportHotkey" | "toastViewportLabel" | "toastViewportProps" | "errorBoundaryProps"> & FormOptions<T> & Omit<ComponentPropsWithoutRef<"form">, "onSubmit" | "onReset"> & {
12
12
  /** Schema of the form. */
13
13
  schema: Schema<T> | SchemaKt;
14
14
  /** Title of the form. */
@@ -145,7 +145,7 @@ export type FormAppApi<T = unknown> = Controller<T> & {
145
145
  * ostack/UI's `locale` is automatically provided to the ostack/UI `Root`
146
146
  * component from the provided `FormApp` `locale`.
147
147
  */
148
- export declare const FormApp: import('react').ForwardRefExoticComponent<Pick<Omit<import('@ostack.tech/ui').RootProps & import('react').RefAttributes<HTMLDivElement>, "ref">, "reportError" | "errorReportingUrl" | "errorReportingMethod" | "encodeErrorReport" | "encodedErrorReportMimeType" | "errorReportingOptions" | "baseDocumentTitle" | "enableErrorReporting" | "documentTitleBaseSeparator" | "documentTitleBreadcrumbsSeparator" | "portalsContainer" | "tooltipsDelayDuration" | "tooltipsSkipDelayDuration" | "disableTooltipsHoverableContent" | "toastsLabel" | "toastsDuration" | "toastsSwipeDirection" | "toastsSwipeThreshold" | "toastViewportHotkey" | "toastViewportLabel" | "toastViewportProps" | "errorBoundaryProps"> & Omit<import('@ostack.tech/kform-react').ControllerOptions<any, import('@ostack.tech/kform-react').FormControllerState<any>>, "formManager"> & import('@ostack.tech/kform-react').FormOwnOptions<any, unknown> & Omit<Omit<import('react').DetailedHTMLProps<import('react').FormHTMLAttributes<HTMLFormElement>, HTMLFormElement>, "ref">, "onReset" | "onSubmit"> & {
148
+ export declare const FormApp: import('react').ForwardRefExoticComponent<Pick<Omit<import('@ostack.tech/ui').RootProps & import('react').RefAttributes<HTMLDivElement>, "ref">, "reportError" | "errorReportingUrl" | "errorReportingMethod" | "encodeErrorReport" | "encodedErrorReportMimeType" | "errorReportingOptions" | "baseDocumentTitle" | "enableErrorReporting" | "documentTitleBaseSeparator" | "documentTitleBreadcrumbsSeparator" | "portalsContainer" | "tooltipsDelayDuration" | "tooltipsSkipDelayDuration" | "disableTooltipsHoverableContent" | "toastsLabel" | "toastsDuration" | "toastsSwipeDirection" | "toastsSwipeThreshold" | "toastViewportPosition" | "toastViewportHotkey" | "toastViewportLabel" | "toastViewportProps" | "errorBoundaryProps"> & Omit<import('@ostack.tech/kform-react').ControllerOptions<any, import('@ostack.tech/kform-react').FormControllerState<any>>, "formManager"> & import('@ostack.tech/kform-react').FormOwnOptions<any, unknown> & Omit<Omit<import('react').DetailedHTMLProps<import('react').FormHTMLAttributes<HTMLFormElement>, HTMLFormElement>, "ref">, "onReset" | "onSubmit"> & {
149
149
  /** Schema of the form. */
150
150
  schema: SchemaKt | Schema<any>;
151
151
  /** Title of the form. */
@@ -19,11 +19,13 @@ export type TableControlRowController<T = unknown> = Controller<T> & {
19
19
  index: number;
20
20
  };
21
21
  /** Column of a table control. */
22
- export interface TableControlColumn<T = unknown, TValue = any> extends Omit<DataTableColumn<T, TValue>, "subColumns" | "getValue" | "format" | "render" | "compare" | "filterable" | "sortable"> {
22
+ export interface TableControlColumn<T = unknown, TValue = any> extends Omit<DataTableColumn<T, TValue>, "subColumns" | "getValue" | "format" | "render" | "compare" | "filterable" | "sortable" | "footer"> {
23
23
  /** Sub columns of this column. */
24
24
  subColumns?: TableControlColumns<T>;
25
25
  /** Function used to render the cell's content. */
26
26
  render?: (rowController: TableControlRowController<T>) => ReactNode;
27
+ /** Optional footer content to be rendered in the column footer. */
28
+ footer?: ReactNode;
27
29
  }
28
30
  /**
29
31
  * Pre-configured column used to display the index of each row. By default, it
@@ -37,7 +39,7 @@ export declare function tableControlIndexColumn<T = unknown, TValue = any>(overr
37
39
  * Pre-configured column used to display row actions. By default, it sticks to
38
40
  * the right of the table and renders the `TableControlRemoveRow` component.
39
41
  *
40
- * Its configuration can be overriden to show other actions, for example, an
42
+ * Its configuration can be overridden to show other actions, for example, an
41
43
  * edit button:
42
44
  *
43
45
  * ```tsx
@@ -0,0 +1,8 @@
1
+ /** Value of the top bar context. */
2
+ export interface TopBarContextValue {
3
+ topBarEl: HTMLElement | null;
4
+ }
5
+ /** Context of the top bar component. */
6
+ export declare const TopBarContext: import('react').Context<TopBarContextValue | null>;
7
+ /** Provides access to the top bar element within the context. */
8
+ export declare function useTopBarElement(): HTMLElement | null;
@@ -1,2 +1,3 @@
1
1
  export * from './TopBar.tsx';
2
2
  export * from './TopBarActions.tsx';
3
+ export { useTopBarElement } from './TopBarContext.tsx';
@@ -36,3 +36,4 @@ export * from './utils/useFormLoader.tsx';
36
36
  export * from './utils/useFormSaver.tsx';
37
37
  export * from './utils/useFormValidator.ts';
38
38
  export * from './utils/useRegisterControl.tsx';
39
+ export * from './utils/useResetOnChange.tsx';
@@ -0,0 +1,98 @@
1
+ import { Path, SealedValueEvent } from '@ostack.tech/kform';
2
+ import { AlertDialogContentColor, ConfirmDialogOptions } from '@ostack.tech/ui';
3
+ import { ReactNode } from 'react';
4
+ /** Options of the reset confirmation dialog. */
5
+ export interface ResetConfirmDialogOption extends ConfirmDialogOptions {
6
+ /** Message of the confirmation dialog. */
7
+ message: ReactNode;
8
+ /**
9
+ * Confirmation dialog content color.
10
+ *
11
+ * @default "warning"
12
+ */
13
+ color?: AlertDialogContentColor;
14
+ }
15
+ /** Options of the `useResetOnChange` hook. */
16
+ export interface UseResetOnChangeOptions<T = unknown> {
17
+ /**
18
+ * Function which determines whether to reset the fields when the value
19
+ * changes. By default, fields are reset whenever the value changes.
20
+ *
21
+ * @param event Value event.
22
+ */
23
+ when?: (event: SealedValueEvent<T>) => boolean;
24
+ /**
25
+ * Fields in `toReset` that should be excluded from being reset (relative to
26
+ * the current path). This is useful when using wildcards in `toReset` and you
27
+ * want to exclude some of the fields that match the wildcard.
28
+ *
29
+ * E.g. `{ toReset: ["/a/*"], excludeFromReset: ["/a/b"] }` will reset all
30
+ * children of `/a` except `/a/b`.
31
+ */
32
+ exclude?: string | Path | (string | Path)[];
33
+ /**
34
+ * Confirmation dialog options. When provided, a confirmation dialog will be
35
+ * presented to the user before resetting the fields.
36
+ *
37
+ * If this option is **not** provided, the fields will be reset without
38
+ * confirmation.
39
+ */
40
+ confirmation?: ResetConfirmDialogOption;
41
+ /**
42
+ * Whether to set the fields as untouched when resetting.
43
+ *
44
+ * @default true
45
+ */
46
+ setUntouched?: boolean;
47
+ /**
48
+ * Whether to set the fields as pristine when resetting.
49
+ *
50
+ * @default true
51
+ */
52
+ setPristine?: boolean;
53
+ }
54
+ /** Event handler returned by the `useResetOnChange` hook. */
55
+ export type UseResetOnChangeResult = (event: SealedValueEvent<any>) => Promise<void>;
56
+ /**
57
+ * Hook which returns an `onValueChange` event handler which resets the fields
58
+ * at the provided `toReset` paths to their initial value when the value changes
59
+ * (according to the `when` function).
60
+ *
61
+ * Optionally requests user-confirmation via dialog if `confirmation` is
62
+ * provided.
63
+ *
64
+ * When using wildcards in `toReset`, certain fields may be excluded via
65
+ * `exclude`.
66
+ *
67
+ * Example usage:
68
+ *
69
+ * ```tsx
70
+ * function NoTransactionsControl() {
71
+ * const handleOnChange = useResetOnChange("/transactions/*", {
72
+ * when: ({ value }) => value,
73
+ * confirmation: {
74
+ * title: "Confirm no transactions",
75
+ * message: (
76
+ * <>
77
+ * By checking this box, all fields in section “Transactions” will
78
+ * be cleared. Are you sure you want to continue?
79
+ * </>
80
+ * ),
81
+ * okText: "Confirm",
82
+ * },
83
+ * });
84
+ *
85
+ * return (
86
+ * <CheckboxControl
87
+ * path="noTransactions"
88
+ * onValueChange={handleOnChange}
89
+ * />
90
+ * );
91
+ * }
92
+ * ```
93
+ *
94
+ * @param toReset Paths to reset up when the value changes (relative to the
95
+ * current path). Wildcards in paths (`*` or `**`) are supported.
96
+ * @param options Hook options. See {@link UseResetOnChangeOptions}.
97
+ */
98
+ export declare function useResetOnChange<T = unknown>(toReset: string | Path | (string | Path)[], { when, exclude, confirmation, setUntouched, setPristine, }?: UseResetOnChangeOptions<T>): UseResetOnChangeResult;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@ostack.tech/ui-kform",
3
3
  "description": "Integration of ostack/UI with ostack/KForm.",
4
- "version": "0.11.3",
4
+ "version": "0.12.1",
5
5
  "homepage": "https://ui.ostack.tech/",
6
6
  "author": {
7
7
  "name": "Opensoft",
@@ -50,7 +50,7 @@
50
50
  "@fortawesome/free-solid-svg-icons": "^6.2.0 || ^7.0.0",
51
51
  "@ostack.tech/kform": "~0.32.0",
52
52
  "@ostack.tech/kform-react": "~0.32.0",
53
- "@ostack.tech/ui": "~0.11.3",
53
+ "@ostack.tech/ui": "~0.12.1",
54
54
  "@types/react": "^18.0.0 || ^19.0.0",
55
55
  "@types/react-dom": "^18.0.0 || ^19.0.0",
56
56
  "date-fns": "^4.1.0",
package/scss/_utils.scss CHANGED
@@ -5,3 +5,4 @@
5
5
  @forward "components/FormApp/FormApp-variables";
6
6
  @forward "components/FormPages/FormPages-variables";
7
7
  @forward "components/IssuesPanel/IssuesPanel-variables";
8
+ @forward "components/TopBar/TopBar-variables";
@@ -3,6 +3,13 @@
3
3
  // Manager
4
4
  $annexes-manager-min-width: 200px !default;
5
5
 
6
+ // Menu trigger
7
+ $annexes-menu-trigger-height: 44px !default;
8
+ $annexes-menu-trigger-open-z-index: calc(
9
+ var(--#{o-ui.$prefix}layer-z-index, 0) +
10
+ var(--#{o-ui.$prefix}z-index-dropdown) + 1
11
+ ) !default;
12
+
6
13
  // Tab issues
7
14
  $annexes-tab-issues-popover-button-icon-border-width: 1px !default;
8
15
  $annexes-tab-issues-popover-button-padding: calc(
@@ -4,8 +4,6 @@
4
4
  @use "../../scss/base-variables" as *;
5
5
 
6
6
  .#{$prefix}annexes {
7
- $tab-height: 44px;
8
-
9
7
  display: flex;
10
8
  flex-direction: column;
11
9
 
@@ -38,7 +36,7 @@
38
36
  margin-left: o-ui.spacing(-4);
39
37
  margin-right: o-ui.spacing(7);
40
38
  padding-top: o-ui.spacing(0.5);
41
- height: $tab-height;
39
+ height: $annexes-menu-trigger-height;
42
40
  }
43
41
 
44
42
  &__tab-list-container {
@@ -47,7 +45,7 @@
47
45
  }
48
46
 
49
47
  &__menu-trigger {
50
- height: $tab-height;
48
+ height: $annexes-menu-trigger-height;
51
49
  border-bottom-left-radius: 0;
52
50
  border-bottom-right-radius: 0;
53
51
  color: var(--#{o-ui.$prefix}primary-9) !important;
@@ -57,7 +55,7 @@
57
55
  border-bottom-color: transparent;
58
56
  background-color: var(--#{o-ui.$prefix}background-color) !important;
59
57
  position: relative;
60
- z-index: o-ui.$z-index-dropdown + 1;
58
+ z-index: $annexes-menu-trigger-open-z-index;
61
59
  }
62
60
  }
63
61
 
@@ -158,7 +156,7 @@
158
156
  }
159
157
 
160
158
  &__tab-inner {
161
- min-height: $tab-height;
159
+ min-height: $annexes-menu-trigger-height;
162
160
  }
163
161
 
164
162
  &__tab-text {
@@ -7,9 +7,6 @@ $form-pages-sidebar-border-radius: null !default;
7
7
  $form-pages-sidebar-background-color: var(--#{o-ui.$prefix}primary-a3) !default;
8
8
  $form-pages-sidebar-border-width: 1px !default;
9
9
  $form-pages-sidebar-border-color: var(--#{o-ui.$prefix}primary-4) !default;
10
- $form-pages-sidebar-z-index: calc(
11
- var(--#{o-ui.$prefix}z-index-sticky) + 1
12
- ) !default;
13
10
 
14
11
  // Sidebar item code
15
12
  $form-pages-sidebar-item-code-min-size: 20px;
@@ -49,9 +46,6 @@ $form-pages-sidebar-item-code-status-color: var(
49
46
  ) !default;
50
47
 
51
48
  // Select
52
- $form-pages-select-z-index: calc(
53
- var(--#{o-ui.$prefix}z-index-sticky) + 2
54
- ) !default;
55
49
  $form-pages-select-box-shadow: 0 2px 4px rgba(0, 0, 0, 0.15) !default;
56
50
  $form-pages-select-menu-background-color: var(
57
51
  --#{o-ui.$prefix}primary-2
@@ -38,7 +38,6 @@
38
38
  var(--#{$prefix}form-app-base-sticky-top, 0px) +
39
39
  var(--#{$prefix}top-bar-height)
40
40
  );
41
- z-index: $form-pages-sidebar-z-index;
42
41
 
43
42
  max-height: calc(100dvh - var(--#{$prefix}top-bar-height));
44
43
  overflow: auto;
@@ -90,7 +89,6 @@
90
89
  var(--#{$prefix}form-app-base-sticky-top, 0px) +
91
90
  var(--#{$prefix}top-bar-height)
92
91
  );
93
- z-index: $form-pages-select-z-index;
94
92
  box-shadow: $form-pages-select-box-shadow;
95
93
  }
96
94
 
@@ -188,7 +186,6 @@
188
186
  var(--#{$prefix}form-app-base-sticky-top, 0px) +
189
187
  var(--#{$prefix}top-bar-height)
190
188
  );
191
- z-index: o-ui.$z-index-sticky + 1;
192
189
 
193
190
  display: flex;
194
191
  align-items: center;
@@ -286,14 +283,6 @@
286
283
  }
287
284
 
288
285
  &__page-content {
289
- position: sticky;
290
- top: calc(
291
- var(--#{$prefix}form-app-base-sticky-top, 0px) +
292
- var(--#{$prefix}top-bar-height) +
293
- var(--#{$prefix}form-pages-page-header-height)
294
- );
295
- z-index: o-ui.$z-index-sticky;
296
-
297
286
  padding: o-ui.spacing(4);
298
287
 
299
288
  @include o-ui.media-breakpoint-up(sm) {
@@ -3,7 +3,6 @@
3
3
  $issues-panel-margin-x: o-ui.spacing(4) !default;
4
4
  $issues-panel-padding-y: o-ui.spacing(3) !default;
5
5
  $issues-panel-padding-x: o-ui.spacing(4) !default;
6
- $issues-panel-z-index: o-ui.$z-index-sticky + 1 !default;
7
6
 
8
7
  $issues-panel-border-radius: o-ui.$card-border-radius o-ui.$card-border-radius 0
9
8
  0 !default;
@@ -19,7 +18,6 @@ $issues-panel-stuck-border-width-sm: null !default;
19
18
  // Issues panel header
20
19
  $issues-panel-header-padding-x: $issues-panel-padding-x !default;
21
20
  $issues-panel-header-padding-bottom: o-ui.spacing(2) !default;
22
- $issues-panel-header-z-index: o-ui.$z-index-sticky !default;
23
21
  $issues-panel-header-stuck-shadow-size: 8px !default;
24
22
  $issues-panel-header-stuck-shadow-color: rgba(0, 0, 0, 0.1) !default;
25
23
  $issues-panel-header-stuck-shadow-gradient:
@@ -28,7 +28,6 @@
28
28
  &__container {
29
29
  position: sticky;
30
30
  bottom: 0;
31
- z-index: $issues-panel-z-index;
32
31
  display: flex;
33
32
  justify-content: center;
34
33
  pointer-events: none;
@@ -77,7 +76,6 @@
77
76
  // Sticky
78
77
  position: sticky;
79
78
  top: 0;
80
- z-index: $issues-panel-header-z-index;
81
79
 
82
80
  &[data-stuck]::before {
83
81
  content: "";
@@ -0,0 +1,13 @@
1
+ @use "@ostack.tech/ui/scss/utils" as o-ui;
2
+ @use "../../scss/base-variables" as *;
3
+
4
+ $top-bar-top: var(--#{$prefix}form-app-base-sticky-top, 0px) !default;
5
+
6
+ $top-bar-padding-top: o-ui.spacing(1) !default;
7
+ $top-bar-padding-x: o-ui.spacing(1) !default;
8
+ $top-bar-border-bottom-width: 2px !default;
9
+ $top-bar-border-bottom-color: var(--#{o-ui.$prefix}primary-9) !default;
10
+ $top-bar-background-color: var(--#{o-ui.$prefix}background-color) !default;
11
+
12
+ // Actions
13
+ $top-bar-actions-margin: 0 0 $top-bar-padding-top auto !default;
@@ -1,23 +1,18 @@
1
1
  @use "@ostack.tech/ui/scss/utils" as o-ui;
2
+ @use "TopBar-variables" as *;
2
3
  @use "../../scss/base-variables" as *;
3
4
 
4
5
  .#{$prefix}top-bar {
5
- $annexes-menu-container: ".#{$prefix}annexes__menu-container";
6
- $annexes-tab-list-root: ".#{$prefix}annexes__tab-list-root";
7
- $annexes-tab: ".#{$prefix}annexes__tab";
8
-
9
6
  display: flex;
10
7
  align-items: flex-end;
11
8
  justify-content: space-between;
12
9
 
13
10
  position: sticky;
14
- top: var(--#{$prefix}form-app-base-sticky-top, 0px);
15
- z-index: o-ui.$z-index-sticky + 3;
16
-
17
- padding: o-ui.spacing(1) o-ui.spacing(1) 0;
18
- border-bottom: 2px solid o-ui.$primary-9;
11
+ top: $top-bar-top;
19
12
 
20
- background-color: var(--#{o-ui.$prefix}background-color);
13
+ padding: $top-bar-padding-top $top-bar-padding-x 0;
14
+ border-bottom: $top-bar-border-bottom-width solid $top-bar-border-bottom-color;
15
+ background-color: $top-bar-background-color;
21
16
 
22
17
  // TODO: Simplify this
23
18
  // Deal with double border (since the annex manager already comes with a
@@ -26,13 +21,13 @@
26
21
  // screens (e.g. 125% browser zoom, or 125% screen scaling in Windows), so we
27
22
  // instead remove the border completely from the manager, which forces us to
28
23
  // override the focus styles of the tabs to show a bottom border.
29
- & #{$annexes-menu-container},
30
- & #{$annexes-tab-list-root} {
24
+ & .#{$prefix}annexes__menu-container,
25
+ & .#{$prefix}annexes__tab-list-root {
31
26
  box-shadow: none;
32
27
  margin-bottom: 0;
33
28
  }
34
29
 
35
- & #{$annexes-tab}:focus-visible:not(:disabled):not([data-disabled]) {
30
+ & .#{$prefix}annexes__tab:focus-visible:not(:disabled):not([data-disabled]) {
36
31
  box-shadow:
37
32
  inset -1px 0 0 0 o-ui.$neutral-12,
38
33
  inset 0 1px 0 0 o-ui.$neutral-12,
@@ -48,6 +43,6 @@
48
43
  }
49
44
 
50
45
  &__actions {
51
- margin: 0 0 o-ui.spacing(1) auto;
46
+ margin: $top-bar-actions-margin;
52
47
  }
53
48
  }