@nadicodeai/ui 6.0.1 → 6.0.2
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/hooks/use-confirm-action.d.ts +0 -6
- package/dist/hooks/use-confirm-action.d.ts.map +1 -1
- package/dist/hooks/use-confirm-action.js +5 -12
- package/dist/lib/use-copy-to-clipboard.d.ts +0 -41
- package/dist/lib/use-copy-to-clipboard.d.ts.map +1 -1
- package/dist/lib/use-copy-to-clipboard.js +6 -15
- package/docs/contract.md +1 -1
- package/package.json +2 -2
|
@@ -1,9 +1,3 @@
|
|
|
1
|
-
export interface ConfirmActionGate {
|
|
2
|
-
busy: boolean;
|
|
3
|
-
}
|
|
4
|
-
export declare function requestConfirmAction<T>(gate: ConfirmActionGate, value: T, setPending: (value: T | null) => void): void;
|
|
5
|
-
export declare function cancelConfirmAction<T>(gate: ConfirmActionGate, setPending: (value: T | null) => void): void;
|
|
6
|
-
export declare function runConfirmAction<T>(gate: ConfirmActionGate, pending: T | null, onConfirm: (value: T) => void | Promise<void>, setPending: (value: T | null) => void, setBusy: (busy: boolean) => void): Promise<void>;
|
|
7
1
|
export declare function useConfirmAction<T>({ onConfirm, }: {
|
|
8
2
|
onConfirm: (value: T) => void | Promise<void>;
|
|
9
3
|
}): {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-confirm-action.d.ts","sourceRoot":"","sources":["../../src/hooks/use-confirm-action.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"use-confirm-action.d.ts","sourceRoot":"","sources":["../../src/hooks/use-confirm-action.ts"],"names":[],"mappings":"AAwDA,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,EAClC,SAAS,GACV,EAAE;IACD,SAAS,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC/C;8BAK2C,CAAC;;;;;;EAqB5C"}
|
|
@@ -1,25 +1,18 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import * as React from "react";
|
|
3
|
-
|
|
4
|
-
// flight so the pending value cannot change under a running action.
|
|
5
|
-
export function requestConfirmAction(gate, value, setPending) {
|
|
3
|
+
function requestConfirmAction(gate, value, setPending) {
|
|
6
4
|
if (gate.busy) {
|
|
7
5
|
return;
|
|
8
6
|
}
|
|
9
7
|
setPending(value);
|
|
10
8
|
}
|
|
11
|
-
|
|
12
|
-
// so the dialog cannot be dismissed mid-action.
|
|
13
|
-
export function cancelConfirmAction(gate, setPending) {
|
|
9
|
+
function cancelConfirmAction(gate, setPending) {
|
|
14
10
|
if (gate.busy) {
|
|
15
11
|
return;
|
|
16
12
|
}
|
|
17
13
|
setPending(null);
|
|
18
14
|
}
|
|
19
|
-
|
|
20
|
-
// success. A thrown error is swallowed so the dialog stays open (the caller
|
|
21
|
-
// surfaces the error inside `onConfirm`); busy always resets in `finally`.
|
|
22
|
-
export async function runConfirmAction(gate, pending, onConfirm, setPending, setBusy) {
|
|
15
|
+
async function confirmOrKeepOpen(gate, pending, onConfirm, setPending, setBusy) {
|
|
23
16
|
if (gate.busy || pending === null) {
|
|
24
17
|
return;
|
|
25
18
|
}
|
|
@@ -30,7 +23,7 @@ export async function runConfirmAction(gate, pending, onConfirm, setPending, set
|
|
|
30
23
|
setPending(null);
|
|
31
24
|
}
|
|
32
25
|
catch {
|
|
33
|
-
|
|
26
|
+
return;
|
|
34
27
|
}
|
|
35
28
|
finally {
|
|
36
29
|
gate.busy = false;
|
|
@@ -47,7 +40,7 @@ export function useConfirmAction({ onConfirm, }) {
|
|
|
47
40
|
const cancel = React.useCallback(() => {
|
|
48
41
|
cancelConfirmAction(gateRef.current, setPending);
|
|
49
42
|
}, []);
|
|
50
|
-
const confirm = React.useCallback(() =>
|
|
43
|
+
const confirm = React.useCallback(() => confirmOrKeepOpen(gateRef.current, pending, onConfirm, setPending, setIsBusy), [pending, onConfirm]);
|
|
51
44
|
return {
|
|
52
45
|
request,
|
|
53
46
|
cancel,
|
|
@@ -1,44 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The copy affordance behind every "copy" button in the package.
|
|
3
|
-
*
|
|
4
|
-
* The decision half and the timer half are exported as plain functions, with the
|
|
5
|
-
* hook a thin binding over them (the shape `use-confirm-action` established), so
|
|
6
|
-
* both are testable in the package's node-only default suite instead of needing a
|
|
7
|
-
* DOM render harness.
|
|
8
|
-
*/
|
|
9
|
-
export type CopyAttempt =
|
|
10
|
-
/** No clipboard to write to — an insecure origin, typically. */
|
|
11
|
-
{
|
|
12
|
-
kind: "unavailable";
|
|
13
|
-
error: Error;
|
|
14
|
-
}
|
|
15
|
-
/** Already showing "copied" and the caller asked not to repeat. */
|
|
16
|
-
| {
|
|
17
|
-
kind: "skipped";
|
|
18
|
-
} | {
|
|
19
|
-
kind: "copied";
|
|
20
|
-
} | {
|
|
21
|
-
kind: "failed";
|
|
22
|
-
error: Error;
|
|
23
|
-
};
|
|
24
|
-
/** Attempts the write and classifies the result; performs no state or timer work. */
|
|
25
|
-
export declare function attemptCopy(input: {
|
|
26
|
-
text: string;
|
|
27
|
-
isCopied: boolean;
|
|
28
|
-
skipWhileCopied: boolean;
|
|
29
|
-
writeText: ((text: string) => Promise<void>) | undefined;
|
|
30
|
-
}): Promise<CopyAttempt>;
|
|
31
|
-
export type ResetTimers = {
|
|
32
|
-
clear: (handle: number) => void;
|
|
33
|
-
set: (onReset: () => void, timeout: number) => number;
|
|
34
|
-
};
|
|
35
|
-
/**
|
|
36
|
-
* Starts the "copied" reset window, dropping whichever reset was already
|
|
37
|
-
* pending. Without the clear, an earlier press's timer keeps its own schedule and
|
|
38
|
-
* fires part-way through this press's window, so the feedback disappears early.
|
|
39
|
-
* Returns the new handle for the caller to hold.
|
|
40
|
-
*/
|
|
41
|
-
export declare function restartResetTimer(timers: ResetTimers, pendingHandle: number, onReset: () => void, timeout: number): number;
|
|
42
1
|
export declare function useCopyToClipboard({ text, onCopy, onError, timeout, skipWhileCopied, }: {
|
|
43
2
|
text: string;
|
|
44
3
|
onCopy?: () => void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-copy-to-clipboard.d.ts","sourceRoot":"","sources":["../../src/lib/use-copy-to-clipboard.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"use-copy-to-clipboard.d.ts","sourceRoot":"","sources":["../../src/lib/use-copy-to-clipboard.ts"],"names":[],"mappings":"AA4BA,wBAAgB,kBAAkB,CAAC,EACjC,IAAI,EACJ,MAAM,EACN,OAAO,EACP,OAAO,EACP,eAAuB,GACxB,EAAE;IACD,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;IACpB,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IACjC,OAAO,EAAE,MAAM,CAAC;IAChB,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B;;;EAsCA"}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { useCallback, useEffect, useRef, useState } from "react";
|
|
2
|
-
|
|
3
|
-
export async function attemptCopy(input) {
|
|
2
|
+
async function attemptCopy(input) {
|
|
4
3
|
if (!input.writeText) {
|
|
5
4
|
return { kind: "unavailable", error: new Error("Clipboard API not available") };
|
|
6
5
|
}
|
|
@@ -15,18 +14,9 @@ export async function attemptCopy(input) {
|
|
|
15
14
|
return { kind: "failed", error: error };
|
|
16
15
|
}
|
|
17
16
|
}
|
|
18
|
-
/**
|
|
19
|
-
* Starts the "copied" reset window, dropping whichever reset was already
|
|
20
|
-
* pending. Without the clear, an earlier press's timer keeps its own schedule and
|
|
21
|
-
* fires part-way through this press's window, so the feedback disappears early.
|
|
22
|
-
* Returns the new handle for the caller to hold.
|
|
23
|
-
*/
|
|
24
|
-
export function restartResetTimer(timers, pendingHandle, onReset, timeout) {
|
|
25
|
-
timers.clear(pendingHandle);
|
|
26
|
-
return timers.set(onReset, timeout);
|
|
27
|
-
}
|
|
28
17
|
export function useCopyToClipboard({ text, onCopy, onError, timeout, skipWhileCopied = false, }) {
|
|
29
|
-
const [
|
|
18
|
+
const [copiedText, setCopiedText] = useState(null);
|
|
19
|
+
const isCopied = copiedText === text;
|
|
30
20
|
const timeoutRef = useRef(0);
|
|
31
21
|
const copyToClipboard = useCallback(async () => {
|
|
32
22
|
const attempt = await attemptCopy({
|
|
@@ -44,9 +34,10 @@ export function useCopyToClipboard({ text, onCopy, onError, timeout, skipWhileCo
|
|
|
44
34
|
if (attempt.kind === "skipped") {
|
|
45
35
|
return;
|
|
46
36
|
}
|
|
47
|
-
|
|
37
|
+
setCopiedText(text);
|
|
48
38
|
onCopy?.();
|
|
49
|
-
|
|
39
|
+
window.clearTimeout(timeoutRef.current);
|
|
40
|
+
timeoutRef.current = window.setTimeout(() => setCopiedText(null), timeout);
|
|
50
41
|
}, [isCopied, onCopy, onError, skipWhileCopied, text, timeout]);
|
|
51
42
|
useEffect(() => () => {
|
|
52
43
|
window.clearTimeout(timeoutRef.current);
|
package/docs/contract.md
CHANGED
|
@@ -135,7 +135,7 @@ package.
|
|
|
135
135
|
|
|
136
136
|
## Accessibility Invariant
|
|
137
137
|
|
|
138
|
-
**Tier-1 accessibility is tested, browser-free.**
|
|
138
|
+
**Tier-1 accessibility is tested, browser-free.** Rendering component tests use the package `expectAccessible` helper to check the rendered DOM. The jsdom tier is structural: rendered contrast, landmark context, focus, and keyboard behavior belong to real-browser Playwright coverage. The shared library ESLint configuration is the executable authority for static JSX accessibility rules, and the repository quality doctrine owns their policy; this contract does not copy the rule inventory.
|
|
139
139
|
|
|
140
140
|
## Reusable Sections
|
|
141
141
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nadicodeai/ui",
|
|
3
|
-
"version": "6.0.
|
|
3
|
+
"version": "6.0.2",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -70,7 +70,7 @@
|
|
|
70
70
|
"@assistant-ui/react": "0.15.18",
|
|
71
71
|
"@assistant-ui/react-markdown": "0.14.14",
|
|
72
72
|
"@base-ui/react": "^1.8.0",
|
|
73
|
-
"@nadicodeai/design-system": "6.0.
|
|
73
|
+
"@nadicodeai/design-system": "6.0.2",
|
|
74
74
|
"@paper-design/shaders": "0.0.80",
|
|
75
75
|
"class-variance-authority": "^0.7.1",
|
|
76
76
|
"clsx": "^2.1.1",
|