@ngockhoi96/ctc 0.1.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.
@@ -0,0 +1,193 @@
1
+ //#region src/lib/types.d.ts
2
+ /**
3
+ * Error codes for browser utility operations.
4
+ */
5
+ type ErrorCode = "CLIPBOARD_NOT_SUPPORTED" | "CLIPBOARD_PERMISSION_DENIED" | "CLIPBOARD_WRITE_FAILED" | "CLIPBOARD_READ_FAILED" | "INSECURE_CONTEXT";
6
+ /**
7
+ * Structured error for browser utility operations.
8
+ *
9
+ * All clipboard functions accept an optional `onError` callback
10
+ * that receives this type with a specific error code.
11
+ */
12
+ interface BrowserUtilsError {
13
+ code: ErrorCode;
14
+ message: string;
15
+ cause?: unknown;
16
+ }
17
+ /**
18
+ * Callback invoked when a browser utility operation fails.
19
+ *
20
+ * @param error - Structured error with code and message
21
+ */
22
+ type OnErrorCallback = (error: BrowserUtilsError) => void;
23
+ //#endregion
24
+ //#region src/clipboard/types.d.ts
25
+ /**
26
+ * Options for clipboard operations.
27
+ */
28
+ interface ClipboardOptions {
29
+ /**
30
+ * Callback invoked when the clipboard operation fails.
31
+ * Receives a structured error with a specific error code.
32
+ */
33
+ onError?: OnErrorCallback | undefined;
34
+ }
35
+ //#endregion
36
+ //#region src/clipboard/copy.d.ts
37
+ /**
38
+ * Copy text to the clipboard using the modern Clipboard API.
39
+ *
40
+ * Requires a secure context (HTTPS or localhost) and must be called from
41
+ * within a user gesture handler (click, keydown, etc.).
42
+ *
43
+ * @param text - The text to copy to the clipboard
44
+ * @param options - Optional configuration including `onError` callback
45
+ * @returns `true` on success, `false` on any failure (never throws)
46
+ *
47
+ * @remarks
48
+ * **User gesture requirement:** Must be called synchronously within a user
49
+ * gesture handler. Programmatic calls from timers or microtasks will be
50
+ * rejected by the browser with `CLIPBOARD_PERMISSION_DENIED`.
51
+ *
52
+ * **Secure context:** Returns `false` on HTTP pages with `INSECURE_CONTEXT`
53
+ * error code. Use `copyToClipboardLegacy()` for HTTP environments.
54
+ *
55
+ * **Safari:** Calling any async operation before `writeText()` in the same
56
+ * microtask may break Safari's user activation window. Keep the call
57
+ * synchronous within the click handler.
58
+ *
59
+ * @example
60
+ * ```ts
61
+ * button.addEventListener('click', async () => {
62
+ * const success = await copyToClipboard('Hello, world!')
63
+ * if (!success) {
64
+ * showError('Copy failed — check HTTPS and permissions')
65
+ * }
66
+ * })
67
+ * ```
68
+ */
69
+ declare function copyToClipboard(text: string, options?: ClipboardOptions): Promise<boolean>;
70
+ //#endregion
71
+ //#region src/clipboard/detect.d.ts
72
+ /**
73
+ * Check if the Clipboard API is available and usable in the current context.
74
+ *
75
+ * Returns `true` only when `navigator.clipboard.writeText` exists AND the
76
+ * page is running in a secure context (HTTPS or localhost). Returns `false`
77
+ * in SSR environments, on HTTP pages, or when the Clipboard API is absent.
78
+ *
79
+ * @returns `true` if clipboard write operations are supported
80
+ *
81
+ * @remarks
82
+ * Permission state is not checked — a `true` result does not guarantee the
83
+ * user has granted clipboard access. Permission denial is surfaced at call
84
+ * time via the `CLIPBOARD_PERMISSION_DENIED` error code on `copyToClipboard`.
85
+ *
86
+ * @example
87
+ * ```ts
88
+ * if (isClipboardSupported()) {
89
+ * await copyToClipboard(text)
90
+ * } else {
91
+ * copyToClipboardLegacy(text)
92
+ * }
93
+ * ```
94
+ */
95
+ declare function isClipboardSupported(): boolean;
96
+ /**
97
+ * Check if clipboard read operations are available and usable in the current context.
98
+ *
99
+ * Returns `true` only when `navigator.clipboard.readText` exists AND the
100
+ * page is running in a secure context (HTTPS or localhost). Returns `false`
101
+ * in SSR environments, on HTTP pages, or when the read API is absent.
102
+ *
103
+ * @returns `true` if clipboard read operations are supported
104
+ *
105
+ * @remarks
106
+ * Permission state is not checked — a `true` result does not guarantee the
107
+ * user has granted clipboard read access. Permission denial is surfaced at
108
+ * call time via the `CLIPBOARD_PERMISSION_DENIED` error code on `readFromClipboard`.
109
+ *
110
+ * Firefox does not support the Permissions API `clipboard-read` query. This
111
+ * function uses synchronous feature detection only — no async permission
112
+ * queries are performed.
113
+ *
114
+ * @example
115
+ * ```ts
116
+ * if (isClipboardReadSupported()) {
117
+ * const text = await readFromClipboard()
118
+ * }
119
+ * ```
120
+ */
121
+ declare function isClipboardReadSupported(): boolean;
122
+ //#endregion
123
+ //#region src/clipboard/fallback.d.ts
124
+ /**
125
+ * Copy text to the clipboard using the legacy `document.execCommand` API.
126
+ *
127
+ * Use this function when the modern Clipboard API is unavailable — for
128
+ * example, on HTTP pages (non-HTTPS) or in browsers that do not support
129
+ * `navigator.clipboard`. For HTTPS pages, prefer `copyToClipboard()`.
130
+ *
131
+ * @param text - The text to copy to the clipboard
132
+ * @param options - Optional configuration including `onError` callback
133
+ * @returns `true` on success, `false` on any failure (never throws)
134
+ *
135
+ * @remarks
136
+ * This function uses the deprecated `document.execCommand('copy')` API,
137
+ * which is synchronous and text-only. It temporarily creates and removes a
138
+ * textarea element in the DOM to perform the copy operation.
139
+ *
140
+ * **No secure context requirement:** This function works on HTTP pages.
141
+ * This is by design — it exists for environments where `copyToClipboard()`
142
+ * is unavailable due to missing secure context.
143
+ *
144
+ * **iOS Safari:** `execCommand` copy is not reliably supported on iOS.
145
+ * This function may return `false` on iOS Safari without a usable fallback.
146
+ *
147
+ * @example
148
+ * ```ts
149
+ * if (isClipboardSupported()) {
150
+ * await copyToClipboard(text)
151
+ * } else {
152
+ * const success = copyToClipboardLegacy(text)
153
+ * if (!success) {
154
+ * showManualCopyInstructions()
155
+ * }
156
+ * }
157
+ * ```
158
+ */
159
+ declare function copyToClipboardLegacy(text: string, options?: ClipboardOptions): boolean;
160
+ //#endregion
161
+ //#region src/clipboard/read.d.ts
162
+ /**
163
+ * Read text from the clipboard using the modern Clipboard API.
164
+ *
165
+ * Requires a secure context (HTTPS or localhost). The browser may prompt
166
+ * the user for permission on the first call.
167
+ *
168
+ * @param options - Optional configuration including `onError` callback
169
+ * @returns The clipboard text on success, `null` on any failure (never throws)
170
+ *
171
+ * @remarks
172
+ * **Permission prompt:** Chrome prompts for `clipboard-read` permission on
173
+ * the first call. Firefox and Safari show a system-level paste prompt.
174
+ * Permission denial is reported via `CLIPBOARD_PERMISSION_DENIED`.
175
+ *
176
+ * **Non-text content:** If the clipboard contains only non-text content
177
+ * (e.g., an image), the browser throws `NotFoundError` which is reported
178
+ * as `CLIPBOARD_READ_FAILED`.
179
+ *
180
+ * @example
181
+ * ```ts
182
+ * button.addEventListener('click', async () => {
183
+ * const text = await readFromClipboard()
184
+ * if (text !== null) {
185
+ * input.value = text
186
+ * }
187
+ * })
188
+ * ```
189
+ */
190
+ declare function readFromClipboard(options?: ClipboardOptions): Promise<string | null>;
191
+ //#endregion
192
+ export { copyToClipboard as a, ErrorCode as c, isClipboardSupported as i, OnErrorCallback as l, copyToClipboardLegacy as n, ClipboardOptions as o, isClipboardReadSupported as r, BrowserUtilsError as s, readFromClipboard as t };
193
+ //# sourceMappingURL=index-CHCHjqWe.d.cts.map
package/dist/index.cjs ADDED
@@ -0,0 +1,7 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ const require_clipboard = require("./clipboard-Bs9DV14p.cjs");
3
+ exports.copyToClipboard = require_clipboard.copyToClipboard;
4
+ exports.copyToClipboardLegacy = require_clipboard.copyToClipboardLegacy;
5
+ exports.isClipboardReadSupported = require_clipboard.isClipboardReadSupported;
6
+ exports.isClipboardSupported = require_clipboard.isClipboardSupported;
7
+ exports.readFromClipboard = require_clipboard.readFromClipboard;
@@ -0,0 +1,2 @@
1
+ import { a as copyToClipboard, c as ErrorCode, i as isClipboardSupported, l as OnErrorCallback, n as copyToClipboardLegacy, o as ClipboardOptions, r as isClipboardReadSupported, s as BrowserUtilsError, t as readFromClipboard } from "./index-CHCHjqWe.cjs";
2
+ export { type BrowserUtilsError, type ClipboardOptions, type ErrorCode, type OnErrorCallback, copyToClipboard, copyToClipboardLegacy, isClipboardReadSupported, isClipboardSupported, readFromClipboard };
@@ -0,0 +1,2 @@
1
+ import { a as copyToClipboard, c as ErrorCode, i as isClipboardSupported, l as OnErrorCallback, n as copyToClipboardLegacy, o as ClipboardOptions, r as isClipboardReadSupported, s as BrowserUtilsError, t as readFromClipboard } from "./index-B7FFRy7e.mjs";
2
+ export { type BrowserUtilsError, type ClipboardOptions, type ErrorCode, type OnErrorCallback, copyToClipboard, copyToClipboardLegacy, isClipboardReadSupported, isClipboardSupported, readFromClipboard };
package/dist/index.mjs ADDED
@@ -0,0 +1,2 @@
1
+ import { a as copyToClipboard, i as isClipboardSupported, n as copyToClipboardLegacy, r as isClipboardReadSupported, t as readFromClipboard } from "./clipboard-OTP55cvN.mjs";
2
+ export { copyToClipboard, copyToClipboardLegacy, isClipboardReadSupported, isClipboardSupported, readFromClipboard };
package/package.json ADDED
@@ -0,0 +1,77 @@
1
+ {
2
+ "name": "@ngockhoi96/ctc",
3
+ "version": "0.1.0",
4
+ "license": "MIT",
5
+ "type": "module",
6
+ "description": "Modular, tree-shakeable browser utilities library",
7
+ "sideEffects": false,
8
+ "engines": {
9
+ "node": ">=20"
10
+ },
11
+ "scripts": {
12
+ "build": "tsdown",
13
+ "lint": "biome check",
14
+ "lint:fix": "biome check --fix",
15
+ "format": "biome format --write",
16
+ "test": "vitest run",
17
+ "test:watch": "vitest",
18
+ "test:e2e": "playwright test",
19
+ "size": "size-limit",
20
+ "validate": "publint && attw --pack",
21
+ "setup": "lefthook install",
22
+ "changeset": "changeset"
23
+ },
24
+ "files": [
25
+ "dist"
26
+ ],
27
+ "size-limit": [
28
+ {
29
+ "path": "dist/index.mjs",
30
+ "limit": "1 KB"
31
+ },
32
+ {
33
+ "path": "dist/clipboard/index.mjs",
34
+ "limit": "1 KB"
35
+ }
36
+ ],
37
+ "devDependencies": {
38
+ "@arethetypeswrong/cli": "0.18.2",
39
+ "@biomejs/biome": "2.4.10",
40
+ "@changesets/changelog-github": "0.6.0",
41
+ "@changesets/cli": "2.30.0",
42
+ "@commitlint/cli": "20.5.0",
43
+ "@commitlint/config-conventional": "20.5.0",
44
+ "@playwright/test": "^1.59.1",
45
+ "@size-limit/file": "12.0.1",
46
+ "@types/node": "^25.6.0",
47
+ "@vitest/coverage-v8": "4.1.3",
48
+ "http-server": "^14.1.1",
49
+ "lefthook": "2.1.5",
50
+ "publint": "0.3.18",
51
+ "size-limit": "12.0.1",
52
+ "tsdown": "0.21.7",
53
+ "typescript": "6.0.2",
54
+ "vitest": "4.1.3"
55
+ },
56
+ "main": "./dist/index.cjs",
57
+ "module": "./dist/index.mjs",
58
+ "types": "./dist/index.d.cts",
59
+ "typesVersions": {
60
+ "*": {
61
+ "clipboard": [
62
+ "./dist/clipboard/index.d.cts"
63
+ ]
64
+ }
65
+ },
66
+ "exports": {
67
+ ".": {
68
+ "import": "./dist/index.mjs",
69
+ "require": "./dist/index.cjs"
70
+ },
71
+ "./clipboard": {
72
+ "import": "./dist/clipboard/index.mjs",
73
+ "require": "./dist/clipboard/index.cjs"
74
+ },
75
+ "./package.json": "./package.json"
76
+ }
77
+ }