@pallasoft/ps-core-components 2.46.1 → 2.47.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.
Files changed (135) hide show
  1. package/dist/components/ps-data-boundary.d.ts +2 -1
  2. package/dist/components/ps-data-boundary.js +2 -2
  3. package/dist/components/ps-empty-value.d.ts +5 -0
  4. package/dist/components/ps-empty-value.js +8 -0
  5. package/dist/components/ps-image.d.ts +14 -0
  6. package/dist/components/ps-image.js +29 -0
  7. package/dist/components/ps-signed-value.d.ts +6 -0
  8. package/dist/components/ps-signed-value.js +9 -0
  9. package/dist/constants/ps-empty-value-config.d.ts +4 -0
  10. package/dist/constants/ps-empty-value-config.js +7 -0
  11. package/dist/constants/ps-image-config.d.ts +7 -0
  12. package/dist/constants/ps-image-config.js +10 -0
  13. package/dist/constants/ps-image-fit.d.ts +7 -0
  14. package/dist/constants/ps-image-fit.js +11 -0
  15. package/dist/constants/ps-image-status.d.ts +5 -0
  16. package/dist/constants/ps-image-status.js +9 -0
  17. package/dist/constants/ps-signed-value-classes.d.ts +2 -0
  18. package/dist/constants/ps-signed-value-classes.js +9 -0
  19. package/dist/esm/components/ps-data-boundary.js +2 -2
  20. package/dist/esm/components/ps-empty-value.js +4 -0
  21. package/dist/esm/components/ps-image.js +25 -0
  22. package/dist/esm/components/ps-signed-value.js +5 -0
  23. package/dist/esm/constants/ps-empty-value-config.js +4 -0
  24. package/dist/esm/constants/ps-image-config.js +7 -0
  25. package/dist/esm/constants/ps-image-fit.js +8 -0
  26. package/dist/esm/constants/ps-image-status.js +6 -0
  27. package/dist/esm/constants/ps-signed-value-classes.js +6 -0
  28. package/dist/esm/hooks/use-ps-cursor-pages.js +82 -0
  29. package/dist/esm/hooks/use-ps-draft-state.js +18 -0
  30. package/dist/esm/hooks/use-ps-optimistic-fetcher.js +2 -4
  31. package/dist/esm/hooks/use-ps-optimistic-save.js +1 -1
  32. package/dist/esm/hooks/use-ps-remote-read.js +31 -0
  33. package/dist/esm/hooks/use-ps-text-param.js +16 -0
  34. package/dist/esm/index.js +32 -12
  35. package/dist/esm/models/ps-image-state-data.js +1 -0
  36. package/dist/esm/models/ps-remote-read-state.js +1 -0
  37. package/dist/esm/models/ps-remote-settled-data.js +1 -0
  38. package/dist/esm/models/ps-text-param-data.js +1 -0
  39. package/dist/esm/models/ps-text-param-options.js +1 -0
  40. package/dist/esm/services/ps-cursor-pages-service.js +14 -0
  41. package/dist/esm/services/ps-draft-state-service.js +11 -0
  42. package/dist/esm/services/ps-image-service.js +11 -0
  43. package/dist/esm/services/ps-remote-read-service.js +19 -0
  44. package/dist/esm/services/ps-signed-value-service.js +13 -0
  45. package/dist/hooks/use-ps-cursor-pages.d.ts +3 -0
  46. package/dist/hooks/use-ps-cursor-pages.js +86 -0
  47. package/dist/hooks/use-ps-draft-state.d.ts +3 -0
  48. package/dist/hooks/use-ps-draft-state.js +22 -0
  49. package/dist/hooks/use-ps-optimistic-fetcher.js +7 -9
  50. package/dist/hooks/use-ps-optimistic-save.js +4 -4
  51. package/dist/hooks/use-ps-remote-read.d.ts +3 -0
  52. package/dist/hooks/use-ps-remote-read.js +35 -0
  53. package/dist/hooks/use-ps-text-param.d.ts +4 -0
  54. package/dist/hooks/use-ps-text-param.js +20 -0
  55. package/dist/index.d.ts +32 -12
  56. package/dist/index.js +39 -12
  57. package/dist/interfaces/ps-cursor-pages-input.d.ts +8 -0
  58. package/dist/interfaces/ps-cursor-pages-result.d.ts +7 -0
  59. package/dist/interfaces/ps-draft-state-options.d.ts +3 -0
  60. package/dist/interfaces/ps-draft-state-result.d.ts +7 -0
  61. package/dist/interfaces/ps-optimistic-failure.d.ts +1 -1
  62. package/dist/interfaces/ps-optimistic-save-input.d.ts +1 -1
  63. package/dist/interfaces/ps-remote-read-input.d.ts +5 -0
  64. package/dist/interfaces/ps-remote-read-result.d.ts +5 -0
  65. package/dist/models/ps-cursor-pages-state.d.ts +8 -0
  66. package/dist/models/ps-draft-state-data.d.ts +4 -0
  67. package/dist/models/ps-image-state-data.d.ts +5 -0
  68. package/dist/models/ps-image-state-data.js +2 -0
  69. package/dist/models/ps-remote-read-state.d.ts +6 -0
  70. package/dist/models/ps-remote-read-state.js +2 -0
  71. package/dist/models/ps-remote-settled-data.d.ts +4 -0
  72. package/dist/models/ps-remote-settled-data.js +2 -0
  73. package/dist/models/ps-text-param-data.d.ts +5 -0
  74. package/dist/models/ps-text-param-data.js +2 -0
  75. package/dist/models/ps-text-param-options.d.ts +5 -0
  76. package/dist/models/ps-text-param-options.js +2 -0
  77. package/dist/services/ps-cursor-pages-service.d.ts +6 -0
  78. package/dist/services/ps-cursor-pages-service.js +18 -0
  79. package/dist/services/ps-draft-state-service.d.ts +6 -0
  80. package/dist/services/ps-draft-state-service.js +15 -0
  81. package/dist/services/ps-image-service.d.ts +6 -0
  82. package/dist/services/ps-image-service.js +15 -0
  83. package/dist/services/ps-remote-read-service.d.ts +8 -0
  84. package/dist/services/ps-remote-read-service.js +23 -0
  85. package/dist/services/ps-signed-value-service.d.ts +5 -0
  86. package/dist/services/ps-signed-value-service.js +17 -0
  87. package/package.json +2 -2
  88. package/dist/constants/ps-optimistic-config.d.ts +0 -5
  89. package/dist/constants/ps-optimistic-config.js +0 -8
  90. package/dist/esm/constants/ps-optimistic-config.js +0 -5
  91. package/dist/esm/hooks/use-ps-change-queue.js +0 -36
  92. package/dist/esm/hooks/use-ps-debounced-value.js +0 -11
  93. package/dist/esm/hooks/use-ps-optimistic-rows.js +0 -29
  94. package/dist/esm/services/ps-deep-equal-service.js +0 -31
  95. package/dist/esm/services/ps-optimistic-fetcher-service.js +0 -12
  96. package/dist/esm/services/ps-optimistic-release-service.js +0 -38
  97. package/dist/esm/services/ps-optimistic-save-service.js +0 -64
  98. package/dist/hooks/use-ps-change-queue.d.ts +0 -3
  99. package/dist/hooks/use-ps-change-queue.js +0 -40
  100. package/dist/hooks/use-ps-debounced-value.d.ts +0 -1
  101. package/dist/hooks/use-ps-debounced-value.js +0 -15
  102. package/dist/hooks/use-ps-optimistic-rows.d.ts +0 -3
  103. package/dist/hooks/use-ps-optimistic-rows.js +0 -33
  104. package/dist/interfaces/ps-change-queue-input.d.ts +0 -5
  105. package/dist/interfaces/ps-change-queue-result.d.ts +0 -3
  106. package/dist/interfaces/ps-optimistic-changes.d.ts +0 -7
  107. package/dist/interfaces/ps-optimistic-failure-reason.d.ts +0 -1
  108. package/dist/interfaces/ps-optimistic-outcome.d.ts +0 -5
  109. package/dist/interfaces/ps-optimistic-rows-input.d.ts +0 -6
  110. package/dist/interfaces/ps-optimistic-rows-result.d.ts +0 -6
  111. package/dist/interfaces/ps-optimistic-save-spec.d.ts +0 -11
  112. package/dist/services/ps-deep-equal-service.d.ts +0 -5
  113. package/dist/services/ps-deep-equal-service.js +0 -35
  114. package/dist/services/ps-optimistic-fetcher-service.d.ts +0 -6
  115. package/dist/services/ps-optimistic-fetcher-service.js +0 -16
  116. package/dist/services/ps-optimistic-release-service.d.ts +0 -5
  117. package/dist/services/ps-optimistic-release-service.js +0 -42
  118. package/dist/services/ps-optimistic-save-service.d.ts +0 -11
  119. package/dist/services/ps-optimistic-save-service.js +0 -68
  120. /package/dist/esm/interfaces/{ps-change-queue-input.js → ps-cursor-pages-input.js} +0 -0
  121. /package/dist/esm/interfaces/{ps-change-queue-result.js → ps-cursor-pages-result.js} +0 -0
  122. /package/dist/esm/interfaces/{ps-optimistic-changes.js → ps-draft-state-options.js} +0 -0
  123. /package/dist/esm/interfaces/{ps-optimistic-failure-reason.js → ps-draft-state-result.js} +0 -0
  124. /package/dist/esm/interfaces/{ps-optimistic-outcome.js → ps-remote-read-input.js} +0 -0
  125. /package/dist/esm/interfaces/{ps-optimistic-rows-input.js → ps-remote-read-result.js} +0 -0
  126. /package/dist/esm/{interfaces/ps-optimistic-rows-result.js → models/ps-cursor-pages-state.js} +0 -0
  127. /package/dist/esm/{interfaces/ps-optimistic-save-spec.js → models/ps-draft-state-data.js} +0 -0
  128. /package/dist/interfaces/{ps-change-queue-input.js → ps-cursor-pages-input.js} +0 -0
  129. /package/dist/interfaces/{ps-change-queue-result.js → ps-cursor-pages-result.js} +0 -0
  130. /package/dist/interfaces/{ps-optimistic-changes.js → ps-draft-state-options.js} +0 -0
  131. /package/dist/interfaces/{ps-optimistic-failure-reason.js → ps-draft-state-result.js} +0 -0
  132. /package/dist/interfaces/{ps-optimistic-outcome.js → ps-remote-read-input.js} +0 -0
  133. /package/dist/interfaces/{ps-optimistic-rows-input.js → ps-remote-read-result.js} +0 -0
  134. /package/dist/{interfaces/ps-optimistic-rows-result.js → models/ps-cursor-pages-state.js} +0 -0
  135. /package/dist/{interfaces/ps-optimistic-save-spec.js → models/ps-draft-state-data.js} +0 -0
@@ -4,6 +4,7 @@ export interface PsDataBoundaryProps<Data> {
4
4
  AwaitComponent: ElementType;
5
5
  children: (data: Data, isPending: boolean) => ReactNode;
6
6
  className?: string;
7
+ dimWhenPending?: boolean;
7
8
  errorElement: ReactNode;
8
9
  fallback: ReactNode;
9
10
  resolve: Promise<Data>;
@@ -11,4 +12,4 @@ export interface PsDataBoundaryProps<Data> {
11
12
  retainKey?: string;
12
13
  variant?: PsDataBoundaryVariant;
13
14
  }
14
- export declare const PsDataBoundary: <Data>({ AwaitComponent, children, className, errorElement, fallback, resolve, retain, retainKey, variant, }: PsDataBoundaryProps<Data>) => import("react").JSX.Element;
15
+ export declare const PsDataBoundary: <Data>({ AwaitComponent, children, className, dimWhenPending, errorElement, fallback, resolve, retain, retainKey, variant, }: PsDataBoundaryProps<Data>) => import("react").JSX.Element;
@@ -6,7 +6,7 @@ const react_1 = require("react");
6
6
  const ps_design_system_1 = require("@pallasoft/ps-design-system");
7
7
  const ps_data_boundary_config_1 = require("../constants/ps-data-boundary-config");
8
8
  const ps_data_boundary_variant_1 = require("../constants/ps-data-boundary-variant");
9
- const PsDataBoundary = ({ AwaitComponent, children, className, errorElement, fallback, resolve, retain = false, retainKey, variant = ps_data_boundary_variant_1.PsDataBoundaryVariant.Page, }) => {
9
+ const PsDataBoundary = ({ AwaitComponent, children, className, dimWhenPending = false, errorElement, fallback, resolve, retain = false, retainKey, variant = ps_data_boundary_variant_1.PsDataBoundaryVariant.Page, }) => {
10
10
  const deferred = (0, react_1.useDeferredValue)({ key: retainKey, resolve });
11
11
  const isRetaining = retain && deferred.key === retainKey;
12
12
  const shown = isRetaining ? deferred.resolve : resolve;
@@ -14,6 +14,6 @@ const PsDataBoundary = ({ AwaitComponent, children, className, errorElement, fal
14
14
  const content = ((0, jsx_runtime_1.jsx)(react_1.Suspense, { fallback: fallback, children: (0, jsx_runtime_1.jsx)(AwaitComponent, { errorElement: errorElement, resolve: shown, children: (data) => children(data, isPending) }) }));
15
15
  if (variant === ps_data_boundary_variant_1.PsDataBoundaryVariant.Page)
16
16
  return content;
17
- return ((0, jsx_runtime_1.jsx)("div", { "aria-busy": isPending, className: ps_design_system_1.PallasoftClassNameService.merge(ps_data_boundary_config_1.PsDataBoundaryConfig.sectionClassName, isPending ? ps_data_boundary_config_1.PsDataBoundaryConfig.pendingClassName : null, className), children: content }));
17
+ return ((0, jsx_runtime_1.jsx)("div", { "aria-busy": isPending, className: ps_design_system_1.PallasoftClassNameService.merge(ps_data_boundary_config_1.PsDataBoundaryConfig.sectionClassName, isPending && dimWhenPending ? ps_data_boundary_config_1.PsDataBoundaryConfig.pendingClassName : null, className), children: content }));
18
18
  };
19
19
  exports.PsDataBoundary = PsDataBoundary;
@@ -0,0 +1,5 @@
1
+ export interface PsEmptyValueProps {
2
+ className?: string;
3
+ label: string;
4
+ }
5
+ export declare const PsEmptyValue: ({ className, label }: PsEmptyValueProps) => import("react").JSX.Element;
@@ -0,0 +1,8 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PsEmptyValue = void 0;
4
+ const jsx_runtime_1 = require("react/jsx-runtime");
5
+ const ps_design_system_1 = require("@pallasoft/ps-design-system");
6
+ const ps_empty_value_config_1 = require("../constants/ps-empty-value-config");
7
+ const PsEmptyValue = ({ className, label }) => ((0, jsx_runtime_1.jsxs)("span", { className: ps_design_system_1.PallasoftClassNameService.merge(ps_empty_value_config_1.PsEmptyValueConfig.className, className), children: [(0, jsx_runtime_1.jsx)("span", { "aria-hidden": 'true', children: ps_empty_value_config_1.PsEmptyValueConfig.symbol }), (0, jsx_runtime_1.jsx)("span", { className: 'sr-only', children: label })] }));
8
+ exports.PsEmptyValue = PsEmptyValue;
@@ -0,0 +1,14 @@
1
+ import { type ImgHTMLAttributes, type ReactNode } from 'react';
2
+ import type { PsImageFit } from '../constants/ps-image-fit';
3
+ export interface PsImageProps {
4
+ alt: string;
5
+ className?: string;
6
+ errorFallback?: ReactNode;
7
+ fit?: PsImageFit;
8
+ height?: number | string;
9
+ loading?: ImgHTMLAttributes<HTMLImageElement>['loading'];
10
+ radius?: string;
11
+ src: string;
12
+ width?: number | string;
13
+ }
14
+ export declare const PsImage: ({ alt, className, errorFallback, fit, height, loading, radius, src, width, }: PsImageProps) => import("react").JSX.Element | null;
@@ -0,0 +1,29 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PsImage = void 0;
4
+ const jsx_runtime_1 = require("react/jsx-runtime");
5
+ const react_1 = require("react");
6
+ const ps_design_system_1 = require("@pallasoft/ps-design-system");
7
+ const ps_image_config_1 = require("../constants/ps-image-config");
8
+ const ps_image_status_1 = require("../constants/ps-image-status");
9
+ const ps_skeleton_shape_1 = require("../constants/ps-skeleton-shape");
10
+ const use_ps_browser_layout_effect_1 = require("../hooks/use-ps-browser-layout-effect");
11
+ const ps_image_service_1 = require("../services/ps-image-service");
12
+ const ps_skeleton_1 = require("./ps-skeleton");
13
+ const PsImage = ({ alt, className, errorFallback, fit, height, loading, radius, src, width, }) => {
14
+ const element = (0, react_1.useRef)(null);
15
+ const [state, setState] = (0, react_1.useState)({ src, status: ps_image_status_1.PsImageStatus.Loading });
16
+ const status = ps_image_service_1.PsImageService.resolve(state, src);
17
+ (0, use_ps_browser_layout_effect_1.usePsBrowserLayoutEffect)(() => {
18
+ if (element.current === null)
19
+ return;
20
+ const found = ps_image_service_1.PsImageService.statusOf(element.current);
21
+ if (found !== ps_image_status_1.PsImageStatus.Loading)
22
+ setState({ src, status: found });
23
+ }, [src]);
24
+ if (status === ps_image_status_1.PsImageStatus.Error)
25
+ return errorFallback === undefined ? null : (0, jsx_runtime_1.jsx)(jsx_runtime_1.Fragment, { children: errorFallback });
26
+ const isLoaded = status === ps_image_status_1.PsImageStatus.Loaded;
27
+ return ((0, jsx_runtime_1.jsxs)("span", { className: ps_image_config_1.PsImageConfig.rootClassName, style: { borderRadius: radius }, children: [isLoaded ? null : ((0, jsx_runtime_1.jsx)(ps_skeleton_1.PsSkeleton, { className: ps_image_config_1.PsImageConfig.skeletonClassName, shape: ps_skeleton_shape_1.PsSkeletonShape.Block })), (0, jsx_runtime_1.jsx)("img", { alt: alt, className: ps_design_system_1.PallasoftClassNameService.merge(ps_image_config_1.PsImageConfig.imageClassName, isLoaded ? ps_image_config_1.PsImageConfig.loadedClassName : ps_image_config_1.PsImageConfig.hiddenClassName, className), decoding: 'async', height: height, loading: loading, onError: () => setState({ src, status: ps_image_status_1.PsImageStatus.Error }), onLoad: () => setState({ src, status: ps_image_status_1.PsImageStatus.Loaded }), ref: element, src: src, style: fit === undefined ? undefined : { objectFit: fit }, width: width })] }));
28
+ };
29
+ exports.PsImage = PsImage;
@@ -0,0 +1,6 @@
1
+ export interface PsSignedValueProps {
2
+ className?: string;
3
+ format?: (value: string) => string;
4
+ value: string;
5
+ }
6
+ export declare const PsSignedValue: ({ className, format, value }: PsSignedValueProps) => import("react").JSX.Element;
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PsSignedValue = void 0;
4
+ const jsx_runtime_1 = require("react/jsx-runtime");
5
+ const ps_design_system_1 = require("@pallasoft/ps-design-system");
6
+ const ps_signed_value_classes_1 = require("../constants/ps-signed-value-classes");
7
+ const ps_signed_value_service_1 = require("../services/ps-signed-value-service");
8
+ const PsSignedValue = ({ className, format, value }) => ((0, jsx_runtime_1.jsx)("span", { className: ps_design_system_1.PallasoftClassNameService.merge(ps_signed_value_classes_1.PsSignedValueClasses[ps_signed_value_service_1.PsSignedValueService.direction(value)], className), children: ps_signed_value_service_1.PsSignedValueService.text(value, format) }));
9
+ exports.PsSignedValue = PsSignedValue;
@@ -0,0 +1,4 @@
1
+ export declare const PsEmptyValueConfig: {
2
+ readonly className: "text-ink/40";
3
+ readonly symbol: "—";
4
+ };
@@ -0,0 +1,7 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PsEmptyValueConfig = void 0;
4
+ exports.PsEmptyValueConfig = {
5
+ className: 'text-ink/40',
6
+ symbol: '—',
7
+ };
@@ -0,0 +1,7 @@
1
+ export declare const PsImageConfig: {
2
+ readonly hiddenClassName: "opacity-0";
3
+ readonly imageClassName: "col-start-1 row-start-1";
4
+ readonly loadedClassName: "opacity-100 animate-ps-fade-in motion-reduce:animate-none";
5
+ readonly rootClassName: "inline-grid shrink-0 max-w-full overflow-hidden align-middle";
6
+ readonly skeletonClassName: "col-start-1 row-start-1 h-full w-full rounded-[inherit]";
7
+ };
@@ -0,0 +1,10 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PsImageConfig = void 0;
4
+ exports.PsImageConfig = {
5
+ hiddenClassName: 'opacity-0',
6
+ imageClassName: 'col-start-1 row-start-1',
7
+ loadedClassName: 'opacity-100 animate-ps-fade-in motion-reduce:animate-none',
8
+ rootClassName: 'inline-grid shrink-0 max-w-full overflow-hidden align-middle',
9
+ skeletonClassName: 'col-start-1 row-start-1 h-full w-full rounded-[inherit]',
10
+ };
@@ -0,0 +1,7 @@
1
+ export declare enum PsImageFit {
2
+ Contain = "contain",
3
+ Cover = "cover",
4
+ Fill = "fill",
5
+ None = "none",
6
+ ScaleDown = "scale-down"
7
+ }
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PsImageFit = void 0;
4
+ var PsImageFit;
5
+ (function (PsImageFit) {
6
+ PsImageFit["Contain"] = "contain";
7
+ PsImageFit["Cover"] = "cover";
8
+ PsImageFit["Fill"] = "fill";
9
+ PsImageFit["None"] = "none";
10
+ PsImageFit["ScaleDown"] = "scale-down";
11
+ })(PsImageFit || (exports.PsImageFit = PsImageFit = {}));
@@ -0,0 +1,5 @@
1
+ export declare enum PsImageStatus {
2
+ Error = "error",
3
+ Loaded = "loaded",
4
+ Loading = "loading"
5
+ }
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PsImageStatus = void 0;
4
+ var PsImageStatus;
5
+ (function (PsImageStatus) {
6
+ PsImageStatus["Error"] = "error";
7
+ PsImageStatus["Loaded"] = "loaded";
8
+ PsImageStatus["Loading"] = "loading";
9
+ })(PsImageStatus || (exports.PsImageStatus = PsImageStatus = {}));
@@ -0,0 +1,2 @@
1
+ import { AmountDirection } from '@pallasoft/ps-utilities';
2
+ export declare const PsSignedValueClasses: Record<AmountDirection, string>;
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PsSignedValueClasses = void 0;
4
+ const ps_utilities_1 = require("@pallasoft/ps-utilities");
5
+ exports.PsSignedValueClasses = {
6
+ [ps_utilities_1.AmountDirection.In]: 'tabular-nums text-success',
7
+ [ps_utilities_1.AmountDirection.Neutral]: 'tabular-nums text-ink',
8
+ [ps_utilities_1.AmountDirection.Out]: 'tabular-nums text-danger',
9
+ };
@@ -3,7 +3,7 @@ import { Suspense, useDeferredValue } from 'react';
3
3
  import { PallasoftClassNameService } from '@pallasoft/ps-design-system';
4
4
  import { PsDataBoundaryConfig } from '../constants/ps-data-boundary-config.js';
5
5
  import { PsDataBoundaryVariant } from '../constants/ps-data-boundary-variant.js';
6
- export const PsDataBoundary = ({ AwaitComponent, children, className, errorElement, fallback, resolve, retain = false, retainKey, variant = PsDataBoundaryVariant.Page, }) => {
6
+ export const PsDataBoundary = ({ AwaitComponent, children, className, dimWhenPending = false, errorElement, fallback, resolve, retain = false, retainKey, variant = PsDataBoundaryVariant.Page, }) => {
7
7
  const deferred = useDeferredValue({ key: retainKey, resolve });
8
8
  const isRetaining = retain && deferred.key === retainKey;
9
9
  const shown = isRetaining ? deferred.resolve : resolve;
@@ -11,5 +11,5 @@ export const PsDataBoundary = ({ AwaitComponent, children, className, errorEleme
11
11
  const content = (_jsx(Suspense, { fallback: fallback, children: _jsx(AwaitComponent, { errorElement: errorElement, resolve: shown, children: (data) => children(data, isPending) }) }));
12
12
  if (variant === PsDataBoundaryVariant.Page)
13
13
  return content;
14
- return (_jsx("div", { "aria-busy": isPending, className: PallasoftClassNameService.merge(PsDataBoundaryConfig.sectionClassName, isPending ? PsDataBoundaryConfig.pendingClassName : null, className), children: content }));
14
+ return (_jsx("div", { "aria-busy": isPending, className: PallasoftClassNameService.merge(PsDataBoundaryConfig.sectionClassName, isPending && dimWhenPending ? PsDataBoundaryConfig.pendingClassName : null, className), children: content }));
15
15
  };
@@ -0,0 +1,4 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { PallasoftClassNameService } from '@pallasoft/ps-design-system';
3
+ import { PsEmptyValueConfig } from '../constants/ps-empty-value-config.js';
4
+ export const PsEmptyValue = ({ className, label }) => (_jsxs("span", { className: PallasoftClassNameService.merge(PsEmptyValueConfig.className, className), children: [_jsx("span", { "aria-hidden": 'true', children: PsEmptyValueConfig.symbol }), _jsx("span", { className: 'sr-only', children: label })] }));
@@ -0,0 +1,25 @@
1
+ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useRef, useState } from 'react';
3
+ import { PallasoftClassNameService } from '@pallasoft/ps-design-system';
4
+ import { PsImageConfig } from '../constants/ps-image-config.js';
5
+ import { PsImageStatus } from '../constants/ps-image-status.js';
6
+ import { PsSkeletonShape } from '../constants/ps-skeleton-shape.js';
7
+ import { usePsBrowserLayoutEffect } from '../hooks/use-ps-browser-layout-effect.js';
8
+ import { PsImageService } from '../services/ps-image-service.js';
9
+ import { PsSkeleton } from './ps-skeleton.js';
10
+ export const PsImage = ({ alt, className, errorFallback, fit, height, loading, radius, src, width, }) => {
11
+ const element = useRef(null);
12
+ const [state, setState] = useState({ src, status: PsImageStatus.Loading });
13
+ const status = PsImageService.resolve(state, src);
14
+ usePsBrowserLayoutEffect(() => {
15
+ if (element.current === null)
16
+ return;
17
+ const found = PsImageService.statusOf(element.current);
18
+ if (found !== PsImageStatus.Loading)
19
+ setState({ src, status: found });
20
+ }, [src]);
21
+ if (status === PsImageStatus.Error)
22
+ return errorFallback === undefined ? null : _jsx(_Fragment, { children: errorFallback });
23
+ const isLoaded = status === PsImageStatus.Loaded;
24
+ return (_jsxs("span", { className: PsImageConfig.rootClassName, style: { borderRadius: radius }, children: [isLoaded ? null : (_jsx(PsSkeleton, { className: PsImageConfig.skeletonClassName, shape: PsSkeletonShape.Block })), _jsx("img", { alt: alt, className: PallasoftClassNameService.merge(PsImageConfig.imageClassName, isLoaded ? PsImageConfig.loadedClassName : PsImageConfig.hiddenClassName, className), decoding: 'async', height: height, loading: loading, onError: () => setState({ src, status: PsImageStatus.Error }), onLoad: () => setState({ src, status: PsImageStatus.Loaded }), ref: element, src: src, style: fit === undefined ? undefined : { objectFit: fit }, width: width })] }));
25
+ };
@@ -0,0 +1,5 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { PallasoftClassNameService } from '@pallasoft/ps-design-system';
3
+ import { PsSignedValueClasses } from '../constants/ps-signed-value-classes.js';
4
+ import { PsSignedValueService } from '../services/ps-signed-value-service.js';
5
+ export const PsSignedValue = ({ className, format, value }) => (_jsx("span", { className: PallasoftClassNameService.merge(PsSignedValueClasses[PsSignedValueService.direction(value)], className), children: PsSignedValueService.text(value, format) }));
@@ -0,0 +1,4 @@
1
+ export const PsEmptyValueConfig = {
2
+ className: 'text-ink/40',
3
+ symbol: '—',
4
+ };
@@ -0,0 +1,7 @@
1
+ export const PsImageConfig = {
2
+ hiddenClassName: 'opacity-0',
3
+ imageClassName: 'col-start-1 row-start-1',
4
+ loadedClassName: 'opacity-100 animate-ps-fade-in motion-reduce:animate-none',
5
+ rootClassName: 'inline-grid shrink-0 max-w-full overflow-hidden align-middle',
6
+ skeletonClassName: 'col-start-1 row-start-1 h-full w-full rounded-[inherit]',
7
+ };
@@ -0,0 +1,8 @@
1
+ export var PsImageFit;
2
+ (function (PsImageFit) {
3
+ PsImageFit["Contain"] = "contain";
4
+ PsImageFit["Cover"] = "cover";
5
+ PsImageFit["Fill"] = "fill";
6
+ PsImageFit["None"] = "none";
7
+ PsImageFit["ScaleDown"] = "scale-down";
8
+ })(PsImageFit || (PsImageFit = {}));
@@ -0,0 +1,6 @@
1
+ export var PsImageStatus;
2
+ (function (PsImageStatus) {
3
+ PsImageStatus["Error"] = "error";
4
+ PsImageStatus["Loaded"] = "loaded";
5
+ PsImageStatus["Loading"] = "loading";
6
+ })(PsImageStatus || (PsImageStatus = {}));
@@ -0,0 +1,6 @@
1
+ import { AmountDirection } from '@pallasoft/ps-utilities';
2
+ export const PsSignedValueClasses = {
3
+ [AmountDirection.In]: 'tabular-nums text-success',
4
+ [AmountDirection.Neutral]: 'tabular-nums text-ink',
5
+ [AmountDirection.Out]: 'tabular-nums text-danger',
6
+ };
@@ -0,0 +1,82 @@
1
+ import { useCallback, useEffect, useRef, useState } from 'react';
2
+ import { PsCursorPagesService } from '../services/ps-cursor-pages-service.js';
3
+ import { PsRemoteReadService } from '../services/ps-remote-read-service.js';
4
+ export const usePsCursorPages = (input) => {
5
+ const { reloadKey } = input;
6
+ const firstUrl = input.url(null);
7
+ const [state, setState] = useState(() => PsCursorPagesService.initialState());
8
+ const inputRef = useRef(input);
9
+ const stateRef = useRef(state);
10
+ const inflight = useRef(null);
11
+ inputRef.current = input;
12
+ stateRef.current = state;
13
+ useEffect(() => {
14
+ setState((current) => (current.isLoadingMore ? { ...current, isLoadingMore: false } : current));
15
+ if (firstUrl === null)
16
+ return;
17
+ const controller = new AbortController();
18
+ inflight.current = controller;
19
+ PsRemoteReadService.read(firstUrl, inputRef.current.parse, controller.signal).then((page) => {
20
+ if (controller.signal.aborted)
21
+ return;
22
+ inflight.current = null;
23
+ setState({
24
+ error: null,
25
+ hasMore: PsCursorPagesService.hasMore(page.length, inputRef.current.pageSize),
26
+ isLoadingMore: false,
27
+ rows: page,
28
+ settled: { reloadKey, url: firstUrl },
29
+ });
30
+ }, (failure) => {
31
+ if (controller.signal.aborted)
32
+ return;
33
+ inflight.current = null;
34
+ setState({
35
+ error: failure,
36
+ hasMore: false,
37
+ isLoadingMore: false,
38
+ rows: [],
39
+ settled: { reloadKey, url: firstUrl },
40
+ });
41
+ });
42
+ return () => {
43
+ controller.abort();
44
+ inflight.current = null;
45
+ };
46
+ }, [firstUrl, reloadKey]);
47
+ const loadMore = useCallback(() => {
48
+ const current = stateRef.current;
49
+ const latest = inputRef.current;
50
+ if (!current.hasMore || inflight.current !== null)
51
+ return;
52
+ const nextUrl = latest.url(latest.cursorOf(current.rows));
53
+ if (nextUrl === null)
54
+ return;
55
+ const controller = new AbortController();
56
+ inflight.current = controller;
57
+ setState((existing) => ({ ...existing, error: null, isLoadingMore: true }));
58
+ PsRemoteReadService.read(nextUrl, latest.parse, controller.signal).then((page) => {
59
+ if (controller.signal.aborted)
60
+ return;
61
+ inflight.current = null;
62
+ setState((existing) => ({
63
+ ...existing,
64
+ hasMore: PsCursorPagesService.hasMore(page.length, inputRef.current.pageSize),
65
+ isLoadingMore: false,
66
+ rows: PsCursorPagesService.append(existing.rows, page, inputRef.current.keyOf),
67
+ }));
68
+ }, (failure) => {
69
+ if (controller.signal.aborted)
70
+ return;
71
+ inflight.current = null;
72
+ setState((existing) => ({ ...existing, error: failure, isLoadingMore: false }));
73
+ });
74
+ }, []);
75
+ return {
76
+ error: state.error,
77
+ hasMore: state.hasMore,
78
+ isLoading: PsRemoteReadService.isPending(state.settled, firstUrl, reloadKey) || state.isLoadingMore,
79
+ loadMore,
80
+ rows: state.rows,
81
+ };
82
+ };
@@ -0,0 +1,18 @@
1
+ import { useCallback, useState } from 'react';
2
+ import { PsDraftStateService } from '../services/ps-draft-state-service.js';
3
+ export const usePsDraftState = (initial, options) => {
4
+ const [state, setState] = useState(() => PsDraftStateService.fresh(initial));
5
+ const isCurrent = PsDraftStateService.isEqual(initial, state.baseline, options);
6
+ if (!isCurrent)
7
+ setState(PsDraftStateService.fresh(initial));
8
+ const setValue = useCallback((next) => setState((current) => ({ ...current, value: next })), []);
9
+ const update = useCallback((updater) => setState((current) => ({ ...current, value: updater(current.value) })), []);
10
+ const reset = useCallback(() => setState((current) => ({ ...current, value: structuredClone(current.baseline) })), []);
11
+ return {
12
+ isDirty: !PsDraftStateService.isEqual(state.value, state.baseline, options),
13
+ reset,
14
+ setValue,
15
+ update,
16
+ value: state.value,
17
+ };
18
+ };
@@ -1,8 +1,6 @@
1
1
  import { useCallback, useEffect, useRef, useState } from 'react';
2
- import { PsOptimisticConfig } from '../constants/ps-optimistic-config.js';
3
- import { PsOptimisticFetcherService } from '../services/ps-optimistic-fetcher-service.js';
4
- import { usePsChangeQueue } from './use-ps-change-queue.js';
5
- import { usePsOptimisticRows } from './use-ps-optimistic-rows.js';
2
+ import { PsOptimisticConfig, PsOptimisticFetcherService, } from '@pallasoft/ps-utilities';
3
+ import { usePsChangeQueue, usePsOptimisticRows } from '@pallasoft/ps-utilities/react';
6
4
  export const usePsOptimisticFetcher = ({ apply, fetcher, isHolding = false, isSuccess, merge, onError, revalidator, rows, }) => {
7
5
  const [isUnsettled, setIsUnsettled] = useState(false);
8
6
  const submitted = useRef(0);
@@ -1,5 +1,5 @@
1
1
  import { useCallback } from 'react';
2
- import { PsOptimisticSaveService } from '../services/ps-optimistic-save-service.js';
2
+ import { PsOptimisticSaveService } from '@pallasoft/ps-utilities';
3
3
  import { usePsOptimisticFetcher } from './use-ps-optimistic-fetcher.js';
4
4
  export const usePsOptimisticSave = ({ fetcher, isSuccess, onError, revalidator, rows, scopeId, spec, }) => {
5
5
  const apply = useCallback((base, changes) => PsOptimisticSaveService.apply(base, changes, spec), [spec]);
@@ -0,0 +1,31 @@
1
+ import { useEffect, useRef, useState } from 'react';
2
+ import { PsRemoteReadService } from '../services/ps-remote-read-service.js';
3
+ export const usePsRemoteRead = ({ parse, reloadKey, url, }) => {
4
+ const [state, setState] = useState(() => PsRemoteReadService.initialState());
5
+ const parseRef = useRef(parse);
6
+ parseRef.current = parse;
7
+ useEffect(() => {
8
+ if (url === null)
9
+ return;
10
+ const controller = new AbortController();
11
+ PsRemoteReadService.read(url, parseRef.current, controller.signal).then((data) => {
12
+ if (controller.signal.aborted)
13
+ return;
14
+ setState({ data, error: null, settled: { reloadKey, url } });
15
+ }, (failure) => {
16
+ if (controller.signal.aborted)
17
+ return;
18
+ setState((current) => ({
19
+ data: current.data,
20
+ error: failure,
21
+ settled: { reloadKey, url },
22
+ }));
23
+ });
24
+ return () => controller.abort();
25
+ }, [reloadKey, url]);
26
+ return {
27
+ data: state.data,
28
+ error: state.error,
29
+ isLoading: PsRemoteReadService.isPending(state.settled, url, reloadKey),
30
+ };
31
+ };
@@ -0,0 +1,16 @@
1
+ import { useEffect, useState } from 'react';
2
+ import { usePsDebouncedValue } from '@pallasoft/ps-utilities/react';
3
+ import { PsQueryParamConfig } from '../constants/ps-query-param-config.js';
4
+ import { PsQueryParamService } from '../services/ps-query-param-service.js';
5
+ export const usePsTextParam = ([searchParams, setSearchParams], { debounceMs, name, resetParams }) => {
6
+ const raw = searchParams.get(name);
7
+ const committed = raw === null ? '' : raw;
8
+ const [value, setValue] = useState(committed);
9
+ const settled = usePsDebouncedValue(value, debounceMs);
10
+ useEffect(() => {
11
+ if (settled === committed)
12
+ return;
13
+ setSearchParams((current) => PsQueryParamService.withChoice(current, name, settled, '', resetParams), PsQueryParamConfig.setOptions);
14
+ }, [settled]);
15
+ return { committed, onChange: setValue, value };
16
+ };
package/dist/esm/index.js CHANGED
@@ -90,21 +90,13 @@ export * from './interfaces/ps-component-props.js';
90
90
  export * from './models/ps-element-size.js';
91
91
  export * from './models/ps-voice-orb.js';
92
92
  export * from './models/ps-navigation-progress.js';
93
- export * from './hooks/use-ps-debounced-value.js';
94
- export * from './hooks/use-ps-change-queue.js';
95
- export * from './interfaces/ps-change-queue-input.js';
96
- export * from './interfaces/ps-change-queue-result.js';
97
93
  export * from './hooks/use-ps-live.js';
98
94
  export * from './hooks/use-ps-debounced-revalidate.js';
99
- export * from './hooks/use-ps-optimistic-rows.js';
100
95
  export * from './hooks/use-ps-optimistic-fetcher.js';
101
96
  export * from './hooks/use-ps-optimistic-save.js';
102
- export * from './constants/ps-optimistic-config.js';
103
97
  export * from './interfaces/ps-optimistic-save-input.js';
104
98
  export * from './interfaces/ps-optimistic-save-result.js';
105
- export * from './interfaces/ps-optimistic-save-spec.js';
106
99
  export * from './interfaces/ps-revalidation-args.js';
107
- export * from './services/ps-optimistic-save-service.js';
108
100
  export * from './services/ps-client-param-revalidation-service.js';
109
101
  export * from './interfaces/ps-fetcher-like.js';
110
102
  export * from './interfaces/ps-fetcher-submit-options.js';
@@ -114,10 +106,7 @@ export * from './interfaces/ps-live-open-options.js';
114
106
  export * from './interfaces/ps-optimistic-fetcher-input.js';
115
107
  export * from './interfaces/ps-optimistic-fetcher-result.js';
116
108
  export * from './interfaces/ps-optimistic-failure.js';
117
- export * from './interfaces/ps-optimistic-failure-reason.js';
118
109
  export * from './interfaces/ps-revalidator-like.js';
119
- export * from './interfaces/ps-optimistic-rows-input.js';
120
- export * from './interfaces/ps-optimistic-rows-result.js';
121
110
  export * from './hooks/use-ps-navigation-progress.js';
122
111
  export * from './models/ps-draggable-grid.js';
123
112
  export * from './constants/ps-draggable-grid.js';
@@ -132,7 +121,6 @@ export * from './constants/ps-data-boundary-variant.js';
132
121
  export * from './hooks/use-ps-retained-promise.js';
133
122
  export * from './hooks/use-ps-promise-value.js';
134
123
  export * from './interfaces/ps-retained-promise-data.js';
135
- export * from './services/ps-deep-equal-service.js';
136
124
  export * from './components/ps-faq-answer.js';
137
125
  export * from './components/ps-feature-grid.js';
138
126
  export * from './components/ps-feature-card.js';
@@ -228,3 +216,35 @@ export * from './hooks/use-ps-choice-param.js';
228
216
  export * from './hooks/use-ps-flag-param.js';
229
217
  export * from './constants/ps-rerender-config.js';
230
218
  export * from './hooks/use-ps-rerender-at.js';
219
+ export * from './models/ps-remote-settled-data.js';
220
+ export * from './models/ps-remote-read-state.js';
221
+ export * from './interfaces/ps-remote-read-input.js';
222
+ export * from './interfaces/ps-remote-read-result.js';
223
+ export * from './services/ps-remote-read-service.js';
224
+ export * from './hooks/use-ps-remote-read.js';
225
+ export * from './interfaces/ps-cursor-pages-input.js';
226
+ export * from './interfaces/ps-cursor-pages-result.js';
227
+ export * from './models/ps-cursor-pages-state.js';
228
+ export * from './services/ps-cursor-pages-service.js';
229
+ export * from './hooks/use-ps-cursor-pages.js';
230
+ export * from './models/ps-text-param-options.js';
231
+ export * from './models/ps-text-param-data.js';
232
+ export * from './hooks/use-ps-text-param.js';
233
+ export * from './interfaces/ps-draft-state-options.js';
234
+ export * from './interfaces/ps-draft-state-result.js';
235
+ export * from './models/ps-draft-state-data.js';
236
+ export * from './services/ps-draft-state-service.js';
237
+ export * from './hooks/use-ps-draft-state.js';
238
+ export * from './constants/ps-empty-value-config.js';
239
+ export * from './components/ps-empty-value.js';
240
+ export * from './constants/ps-signed-value-classes.js';
241
+ export * from './services/ps-signed-value-service.js';
242
+ export * from './components/ps-signed-value.js';
243
+ export * from './constants/ps-image-status.js';
244
+ export * from './constants/ps-image-fit.js';
245
+ export * from './constants/ps-image-config.js';
246
+ export * from './models/ps-image-state-data.js';
247
+ export * from './services/ps-image-service.js';
248
+ export * from './components/ps-image.js';
249
+ export { PsDeepEqualService, PsOptimisticConfig, PsOptimisticSaveService, } from '@pallasoft/ps-utilities';
250
+ export { usePsChangeQueue, usePsDebouncedValue, usePsOptimisticRows, } from '@pallasoft/ps-utilities/react';
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,14 @@
1
+ export class PsCursorPagesService {
2
+ static append(existing, page, keyOf) {
3
+ if (keyOf === undefined)
4
+ return [...existing, ...page];
5
+ const known = new Set(existing.map(keyOf));
6
+ return [...existing, ...page.filter((row) => !known.has(keyOf(row)))];
7
+ }
8
+ static hasMore(pageLength, pageSize) {
9
+ return pageLength >= pageSize;
10
+ }
11
+ static initialState() {
12
+ return { error: null, hasMore: false, isLoadingMore: false, rows: [], settled: null };
13
+ }
14
+ }
@@ -0,0 +1,11 @@
1
+ import { PsDeepEqualService } from '@pallasoft/ps-utilities';
2
+ export class PsDraftStateService {
3
+ static fresh(initial) {
4
+ return { baseline: initial, value: structuredClone(initial) };
5
+ }
6
+ static isEqual(left, right, options) {
7
+ if (options !== undefined && options.isEqual !== undefined)
8
+ return options.isEqual(left, right);
9
+ return PsDeepEqualService.isEqual(left, right);
10
+ }
11
+ }
@@ -0,0 +1,11 @@
1
+ import { PsImageStatus } from '../constants/ps-image-status.js';
2
+ export class PsImageService {
3
+ static resolve(state, src) {
4
+ return state.src === src ? state.status : PsImageStatus.Loading;
5
+ }
6
+ static statusOf(element) {
7
+ if (!element.complete)
8
+ return PsImageStatus.Loading;
9
+ return element.naturalWidth > 0 ? PsImageStatus.Loaded : PsImageStatus.Error;
10
+ }
11
+ }