@pallasoft/ps-core-components 2.27.0 → 2.28.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.
- package/dist/components/ps-overview-card.d.ts +12 -0
- package/dist/components/ps-overview-card.js +7 -0
- package/dist/esm/components/ps-overview-card.js +3 -0
- package/dist/esm/hooks/use-ps-optimistic-fetcher.js +68 -0
- package/dist/esm/index.js +7 -0
- package/dist/esm/interfaces/ps-fetcher-like.js +1 -0
- package/dist/esm/interfaces/ps-fetcher-submit-options.js +1 -0
- package/dist/esm/interfaces/ps-optimistic-fetcher-input.js +1 -0
- package/dist/esm/interfaces/ps-optimistic-fetcher-result.js +1 -0
- package/dist/esm/interfaces/ps-revalidator-like.js +1 -0
- package/dist/hooks/use-ps-optimistic-fetcher.d.ts +3 -0
- package/dist/hooks/use-ps-optimistic-fetcher.js +72 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +7 -0
- package/dist/interfaces/ps-fetcher-like.d.ts +6 -0
- package/dist/interfaces/ps-fetcher-like.js +2 -0
- package/dist/interfaces/ps-fetcher-submit-options.d.ts +3 -0
- package/dist/interfaces/ps-fetcher-submit-options.js +2 -0
- package/dist/interfaces/ps-optimistic-fetcher-input.d.ts +11 -0
- package/dist/interfaces/ps-optimistic-fetcher-input.js +2 -0
- package/dist/interfaces/ps-optimistic-fetcher-result.d.ts +4 -0
- package/dist/interfaces/ps-optimistic-fetcher-result.js +2 -0
- package/dist/interfaces/ps-revalidator-like.d.ts +4 -0
- package/dist/interfaces/ps-revalidator-like.js +2 -0
- package/package.json +1 -1
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
export interface PsOverviewCardProps {
|
|
3
|
+
action?: ReactNode;
|
|
4
|
+
badge?: ReactNode;
|
|
5
|
+
children?: ReactNode;
|
|
6
|
+
className?: string;
|
|
7
|
+
footer?: ReactNode;
|
|
8
|
+
icon?: ReactNode;
|
|
9
|
+
summary?: string;
|
|
10
|
+
title: string;
|
|
11
|
+
}
|
|
12
|
+
export declare const PsOverviewCard: ({ action, badge, children, className, footer, icon, summary, title, }: PsOverviewCardProps) => import("react").JSX.Element;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.PsOverviewCard = void 0;
|
|
4
|
+
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
5
|
+
const ps_design_system_1 = require("@pallasoft/ps-design-system");
|
|
6
|
+
const PsOverviewCard = ({ action, badge, children, className, footer, icon, summary, title, }) => ((0, jsx_runtime_1.jsxs)("section", { className: ps_design_system_1.PallasoftClassNameService.merge('flex min-w-0 flex-col gap-4 rounded-ps-panel border border-line bg-surface p-5', className), children: [(0, jsx_runtime_1.jsxs)("header", { className: 'flex min-w-0 items-start gap-3', children: [icon ? (0, jsx_runtime_1.jsx)("span", { className: 'ps-icon-surface h-10 w-10 shrink-0', children: icon }) : null, (0, jsx_runtime_1.jsxs)("div", { className: 'flex min-w-0 flex-1 flex-col gap-1', children: [(0, jsx_runtime_1.jsxs)("div", { className: 'flex flex-wrap items-center gap-2', children: [(0, jsx_runtime_1.jsx)("h2", { className: 'text-base font-semibold text-ink', children: title }), badge] }), summary ? (0, jsx_runtime_1.jsx)("p", { className: 'break-words text-sm leading-6 text-ink/60', children: summary }) : null] }), action ? (0, jsx_runtime_1.jsx)("div", { className: 'flex shrink-0 items-center gap-2', children: action }) : null] }), children ? (0, jsx_runtime_1.jsx)("div", { className: 'flex min-w-0 flex-col gap-1', children: children }) : null, footer ? (0, jsx_runtime_1.jsx)("div", { className: 'flex flex-wrap items-center gap-2', children: footer }) : null] }));
|
|
7
|
+
exports.PsOverviewCard = PsOverviewCard;
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { PallasoftClassNameService } from '@pallasoft/ps-design-system';
|
|
3
|
+
export const PsOverviewCard = ({ action, badge, children, className, footer, icon, summary, title, }) => (_jsxs("section", { className: PallasoftClassNameService.merge('flex min-w-0 flex-col gap-4 rounded-ps-panel border border-line bg-surface p-5', className), children: [_jsxs("header", { className: 'flex min-w-0 items-start gap-3', children: [icon ? _jsx("span", { className: 'ps-icon-surface h-10 w-10 shrink-0', children: icon }) : null, _jsxs("div", { className: 'flex min-w-0 flex-1 flex-col gap-1', children: [_jsxs("div", { className: 'flex flex-wrap items-center gap-2', children: [_jsx("h2", { className: 'text-base font-semibold text-ink', children: title }), badge] }), summary ? _jsx("p", { className: 'break-words text-sm leading-6 text-ink/60', children: summary }) : null] }), action ? _jsx("div", { className: 'flex shrink-0 items-center gap-2', children: action }) : null] }), children ? _jsx("div", { className: 'flex min-w-0 flex-col gap-1', children: children }) : null, footer ? _jsx("div", { className: 'flex flex-wrap items-center gap-2', children: footer }) : null] }));
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { useCallback, useEffect, useRef, useState } from 'react';
|
|
2
|
+
import { usePsChangeQueue } from './use-ps-change-queue';
|
|
3
|
+
import { usePsOptimisticRows } from './use-ps-optimistic-rows';
|
|
4
|
+
export const usePsOptimisticFetcher = ({ apply, fetcher, isHolding = false, isSuccess, merge, revalidator, rows, }) => {
|
|
5
|
+
const [isUnsettled, setIsUnsettled] = useState(false);
|
|
6
|
+
const submitted = useRef(0);
|
|
7
|
+
const settle = useRef(null);
|
|
8
|
+
const sawBusy = useRef(false);
|
|
9
|
+
const dataBefore = useRef(fetcher.data);
|
|
10
|
+
const dataSeen = useRef(fetcher.data);
|
|
11
|
+
const { forgetLast, remember, rows: shown, } = usePsOptimisticRows({
|
|
12
|
+
apply,
|
|
13
|
+
isHolding,
|
|
14
|
+
isSaving: isUnsettled || fetcher.state !== 'idle' || revalidator.state !== 'idle',
|
|
15
|
+
rows,
|
|
16
|
+
});
|
|
17
|
+
useEffect(() => {
|
|
18
|
+
dataSeen.current = fetcher.data;
|
|
19
|
+
if (settle.current === null)
|
|
20
|
+
return;
|
|
21
|
+
if (fetcher.state !== 'idle') {
|
|
22
|
+
sawBusy.current = true;
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
if (!sawBusy.current && fetcher.data === dataBefore.current)
|
|
26
|
+
return;
|
|
27
|
+
const done = settle.current;
|
|
28
|
+
settle.current = null;
|
|
29
|
+
sawBusy.current = false;
|
|
30
|
+
done(fetcher.data);
|
|
31
|
+
}, [fetcher.data, fetcher.state]);
|
|
32
|
+
const submitOne = useCallback((values) => new Promise((resolve) => {
|
|
33
|
+
settle.current = resolve;
|
|
34
|
+
sawBusy.current = false;
|
|
35
|
+
dataBefore.current = dataSeen.current;
|
|
36
|
+
void fetcher.submit(values, { method: 'post' });
|
|
37
|
+
}), [fetcher]);
|
|
38
|
+
const send = useCallback(async (queued) => {
|
|
39
|
+
for (const submission of merge === undefined ? queued : merge(queued)) {
|
|
40
|
+
const result = await submitOne(submission);
|
|
41
|
+
if (!isSuccess(result))
|
|
42
|
+
throw result;
|
|
43
|
+
}
|
|
44
|
+
}, [isSuccess, merge, submitOne]);
|
|
45
|
+
const revalidate = useCallback(() => {
|
|
46
|
+
const through = submitted.current;
|
|
47
|
+
void Promise.resolve(revalidator.revalidate()).finally(() => {
|
|
48
|
+
if (submitted.current === through)
|
|
49
|
+
setIsUnsettled(false);
|
|
50
|
+
});
|
|
51
|
+
}, [revalidator]);
|
|
52
|
+
const forgetFailed = useCallback((failed, dropped) => {
|
|
53
|
+
for (let index = 0; index < failed.length + dropped.length; index += 1)
|
|
54
|
+
forgetLast();
|
|
55
|
+
}, [forgetLast]);
|
|
56
|
+
const queue = usePsChangeQueue({
|
|
57
|
+
onDrained: revalidate,
|
|
58
|
+
onFailed: forgetFailed,
|
|
59
|
+
send,
|
|
60
|
+
});
|
|
61
|
+
const submit = useCallback((values) => {
|
|
62
|
+
submitted.current += 1;
|
|
63
|
+
setIsUnsettled(true);
|
|
64
|
+
remember(values);
|
|
65
|
+
queue.enqueue(values);
|
|
66
|
+
}, [queue, remember]);
|
|
67
|
+
return { rows: shown, submit };
|
|
68
|
+
};
|
package/dist/esm/index.js
CHANGED
|
@@ -75,6 +75,12 @@ export * from './hooks/use-ps-change-queue';
|
|
|
75
75
|
export * from './interfaces/ps-change-queue-input';
|
|
76
76
|
export * from './interfaces/ps-change-queue-result';
|
|
77
77
|
export * from './hooks/use-ps-optimistic-rows';
|
|
78
|
+
export * from './hooks/use-ps-optimistic-fetcher';
|
|
79
|
+
export * from './interfaces/ps-fetcher-like';
|
|
80
|
+
export * from './interfaces/ps-fetcher-submit-options';
|
|
81
|
+
export * from './interfaces/ps-optimistic-fetcher-input';
|
|
82
|
+
export * from './interfaces/ps-optimistic-fetcher-result';
|
|
83
|
+
export * from './interfaces/ps-revalidator-like';
|
|
78
84
|
export * from './interfaces/ps-optimistic-rows-input';
|
|
79
85
|
export * from './interfaces/ps-optimistic-rows-result';
|
|
80
86
|
export * from './hooks/use-ps-navigation-progress';
|
|
@@ -129,6 +135,7 @@ export * from './models/ps-theme-mode-state';
|
|
|
129
135
|
export * from './models/ps-tool-card-data';
|
|
130
136
|
export * from './components/ps-capped-list';
|
|
131
137
|
export * from './components/ps-detail-list';
|
|
138
|
+
export * from './components/ps-overview-card';
|
|
132
139
|
export * from './components/ps-form-footer';
|
|
133
140
|
export * from './components/ps-start-highlight';
|
|
134
141
|
export * from './components/ps-start-panel';
|
|
@@ -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,3 @@
|
|
|
1
|
+
import type { PsOptimisticFetcherInput } from '../interfaces/ps-optimistic-fetcher-input';
|
|
2
|
+
import type { PsOptimisticFetcherResult } from '../interfaces/ps-optimistic-fetcher-result';
|
|
3
|
+
export declare const usePsOptimisticFetcher: <Row, Data>({ apply, fetcher, isHolding, isSuccess, merge, revalidator, rows, }: PsOptimisticFetcherInput<Row, Data>) => PsOptimisticFetcherResult<Row>;
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.usePsOptimisticFetcher = void 0;
|
|
4
|
+
const react_1 = require("react");
|
|
5
|
+
const use_ps_change_queue_1 = require("./use-ps-change-queue");
|
|
6
|
+
const use_ps_optimistic_rows_1 = require("./use-ps-optimistic-rows");
|
|
7
|
+
const usePsOptimisticFetcher = ({ apply, fetcher, isHolding = false, isSuccess, merge, revalidator, rows, }) => {
|
|
8
|
+
const [isUnsettled, setIsUnsettled] = (0, react_1.useState)(false);
|
|
9
|
+
const submitted = (0, react_1.useRef)(0);
|
|
10
|
+
const settle = (0, react_1.useRef)(null);
|
|
11
|
+
const sawBusy = (0, react_1.useRef)(false);
|
|
12
|
+
const dataBefore = (0, react_1.useRef)(fetcher.data);
|
|
13
|
+
const dataSeen = (0, react_1.useRef)(fetcher.data);
|
|
14
|
+
const { forgetLast, remember, rows: shown, } = (0, use_ps_optimistic_rows_1.usePsOptimisticRows)({
|
|
15
|
+
apply,
|
|
16
|
+
isHolding,
|
|
17
|
+
isSaving: isUnsettled || fetcher.state !== 'idle' || revalidator.state !== 'idle',
|
|
18
|
+
rows,
|
|
19
|
+
});
|
|
20
|
+
(0, react_1.useEffect)(() => {
|
|
21
|
+
dataSeen.current = fetcher.data;
|
|
22
|
+
if (settle.current === null)
|
|
23
|
+
return;
|
|
24
|
+
if (fetcher.state !== 'idle') {
|
|
25
|
+
sawBusy.current = true;
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
if (!sawBusy.current && fetcher.data === dataBefore.current)
|
|
29
|
+
return;
|
|
30
|
+
const done = settle.current;
|
|
31
|
+
settle.current = null;
|
|
32
|
+
sawBusy.current = false;
|
|
33
|
+
done(fetcher.data);
|
|
34
|
+
}, [fetcher.data, fetcher.state]);
|
|
35
|
+
const submitOne = (0, react_1.useCallback)((values) => new Promise((resolve) => {
|
|
36
|
+
settle.current = resolve;
|
|
37
|
+
sawBusy.current = false;
|
|
38
|
+
dataBefore.current = dataSeen.current;
|
|
39
|
+
void fetcher.submit(values, { method: 'post' });
|
|
40
|
+
}), [fetcher]);
|
|
41
|
+
const send = (0, react_1.useCallback)(async (queued) => {
|
|
42
|
+
for (const submission of merge === undefined ? queued : merge(queued)) {
|
|
43
|
+
const result = await submitOne(submission);
|
|
44
|
+
if (!isSuccess(result))
|
|
45
|
+
throw result;
|
|
46
|
+
}
|
|
47
|
+
}, [isSuccess, merge, submitOne]);
|
|
48
|
+
const revalidate = (0, react_1.useCallback)(() => {
|
|
49
|
+
const through = submitted.current;
|
|
50
|
+
void Promise.resolve(revalidator.revalidate()).finally(() => {
|
|
51
|
+
if (submitted.current === through)
|
|
52
|
+
setIsUnsettled(false);
|
|
53
|
+
});
|
|
54
|
+
}, [revalidator]);
|
|
55
|
+
const forgetFailed = (0, react_1.useCallback)((failed, dropped) => {
|
|
56
|
+
for (let index = 0; index < failed.length + dropped.length; index += 1)
|
|
57
|
+
forgetLast();
|
|
58
|
+
}, [forgetLast]);
|
|
59
|
+
const queue = (0, use_ps_change_queue_1.usePsChangeQueue)({
|
|
60
|
+
onDrained: revalidate,
|
|
61
|
+
onFailed: forgetFailed,
|
|
62
|
+
send,
|
|
63
|
+
});
|
|
64
|
+
const submit = (0, react_1.useCallback)((values) => {
|
|
65
|
+
submitted.current += 1;
|
|
66
|
+
setIsUnsettled(true);
|
|
67
|
+
remember(values);
|
|
68
|
+
queue.enqueue(values);
|
|
69
|
+
}, [queue, remember]);
|
|
70
|
+
return { rows: shown, submit };
|
|
71
|
+
};
|
|
72
|
+
exports.usePsOptimisticFetcher = usePsOptimisticFetcher;
|
package/dist/index.d.ts
CHANGED
|
@@ -75,6 +75,12 @@ export * from './hooks/use-ps-change-queue';
|
|
|
75
75
|
export * from './interfaces/ps-change-queue-input';
|
|
76
76
|
export * from './interfaces/ps-change-queue-result';
|
|
77
77
|
export * from './hooks/use-ps-optimistic-rows';
|
|
78
|
+
export * from './hooks/use-ps-optimistic-fetcher';
|
|
79
|
+
export * from './interfaces/ps-fetcher-like';
|
|
80
|
+
export * from './interfaces/ps-fetcher-submit-options';
|
|
81
|
+
export * from './interfaces/ps-optimistic-fetcher-input';
|
|
82
|
+
export * from './interfaces/ps-optimistic-fetcher-result';
|
|
83
|
+
export * from './interfaces/ps-revalidator-like';
|
|
78
84
|
export * from './interfaces/ps-optimistic-rows-input';
|
|
79
85
|
export * from './interfaces/ps-optimistic-rows-result';
|
|
80
86
|
export * from './hooks/use-ps-navigation-progress';
|
|
@@ -129,6 +135,7 @@ export * from './models/ps-theme-mode-state';
|
|
|
129
135
|
export * from './models/ps-tool-card-data';
|
|
130
136
|
export * from './components/ps-capped-list';
|
|
131
137
|
export * from './components/ps-detail-list';
|
|
138
|
+
export * from './components/ps-overview-card';
|
|
132
139
|
export * from './components/ps-form-footer';
|
|
133
140
|
export * from './components/ps-start-highlight';
|
|
134
141
|
export * from './components/ps-start-panel';
|
package/dist/index.js
CHANGED
|
@@ -91,6 +91,12 @@ __exportStar(require("./hooks/use-ps-change-queue"), exports);
|
|
|
91
91
|
__exportStar(require("./interfaces/ps-change-queue-input"), exports);
|
|
92
92
|
__exportStar(require("./interfaces/ps-change-queue-result"), exports);
|
|
93
93
|
__exportStar(require("./hooks/use-ps-optimistic-rows"), exports);
|
|
94
|
+
__exportStar(require("./hooks/use-ps-optimistic-fetcher"), exports);
|
|
95
|
+
__exportStar(require("./interfaces/ps-fetcher-like"), exports);
|
|
96
|
+
__exportStar(require("./interfaces/ps-fetcher-submit-options"), exports);
|
|
97
|
+
__exportStar(require("./interfaces/ps-optimistic-fetcher-input"), exports);
|
|
98
|
+
__exportStar(require("./interfaces/ps-optimistic-fetcher-result"), exports);
|
|
99
|
+
__exportStar(require("./interfaces/ps-revalidator-like"), exports);
|
|
94
100
|
__exportStar(require("./interfaces/ps-optimistic-rows-input"), exports);
|
|
95
101
|
__exportStar(require("./interfaces/ps-optimistic-rows-result"), exports);
|
|
96
102
|
__exportStar(require("./hooks/use-ps-navigation-progress"), exports);
|
|
@@ -145,6 +151,7 @@ __exportStar(require("./models/ps-theme-mode-state"), exports);
|
|
|
145
151
|
__exportStar(require("./models/ps-tool-card-data"), exports);
|
|
146
152
|
__exportStar(require("./components/ps-capped-list"), exports);
|
|
147
153
|
__exportStar(require("./components/ps-detail-list"), exports);
|
|
154
|
+
__exportStar(require("./components/ps-overview-card"), exports);
|
|
148
155
|
__exportStar(require("./components/ps-form-footer"), exports);
|
|
149
156
|
__exportStar(require("./components/ps-start-highlight"), exports);
|
|
150
157
|
__exportStar(require("./components/ps-start-panel"), exports);
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { PsFetcherLike } from './ps-fetcher-like';
|
|
2
|
+
import type { PsRevalidatorLike } from './ps-revalidator-like';
|
|
3
|
+
export interface PsOptimisticFetcherInput<Row, Data> {
|
|
4
|
+
apply: (rows: Row[], changes: Record<string, string>[]) => Row[];
|
|
5
|
+
fetcher: PsFetcherLike<Data>;
|
|
6
|
+
isHolding?: boolean;
|
|
7
|
+
isSuccess: (data: Data | undefined) => boolean;
|
|
8
|
+
merge?: (changes: Record<string, string>[]) => Record<string, string>[];
|
|
9
|
+
revalidator: PsRevalidatorLike;
|
|
10
|
+
rows: Row[];
|
|
11
|
+
}
|