@kopexa/button 8.0.0 → 8.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/chunk-JU7NAIA6.mjs +118 -0
- package/dist/copy-button.d.mts +22 -0
- package/dist/copy-button.d.ts +22 -0
- package/dist/copy-button.js +243 -0
- package/dist/copy-button.mjs +8 -0
- package/dist/icon-button.d.mts +1 -1
- package/dist/icon-button.d.ts +1 -1
- package/dist/index.d.mts +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +118 -6
- package/dist/index.mjs +4 -0
- package/package.json +6 -5
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import {
|
|
3
|
+
Button
|
|
4
|
+
} from "./chunk-TWIY5JCA.mjs";
|
|
5
|
+
|
|
6
|
+
// src/copy-button.tsx
|
|
7
|
+
import { CopyIcon } from "@kopexa/icons";
|
|
8
|
+
import { callAllHandlers } from "@kopexa/shared-utils";
|
|
9
|
+
import { Tooltip } from "@kopexa/tooltip";
|
|
10
|
+
import { useEffect, useMemo, useRef, useState } from "react";
|
|
11
|
+
import { jsx } from "react/jsx-runtime";
|
|
12
|
+
var CopyButton = ({
|
|
13
|
+
children,
|
|
14
|
+
variant = "ghost",
|
|
15
|
+
value,
|
|
16
|
+
onCopy,
|
|
17
|
+
translations,
|
|
18
|
+
resetDelay = 1200,
|
|
19
|
+
disabled,
|
|
20
|
+
onClick,
|
|
21
|
+
...restProps
|
|
22
|
+
}) => {
|
|
23
|
+
var _a;
|
|
24
|
+
const [state, setState] = useState("idle");
|
|
25
|
+
const timerRef = useRef(null);
|
|
26
|
+
const resolveValue = () => {
|
|
27
|
+
var _a2;
|
|
28
|
+
if (typeof value === "function") return (_a2 = value()) != null ? _a2 : "";
|
|
29
|
+
if (typeof value === "string") return value;
|
|
30
|
+
if (typeof children === "string") return children;
|
|
31
|
+
return "";
|
|
32
|
+
};
|
|
33
|
+
const tooltipContent = useMemo(() => {
|
|
34
|
+
var _a2, _b, _c;
|
|
35
|
+
if (state === "copied") return (_a2 = translations == null ? void 0 : translations.copied) != null ? _a2 : "Copied";
|
|
36
|
+
if (state === "error") return (_b = translations == null ? void 0 : translations.error) != null ? _b : "Copy failed";
|
|
37
|
+
return (_c = translations == null ? void 0 : translations.copy) != null ? _c : "Copy";
|
|
38
|
+
}, [state, translations]);
|
|
39
|
+
useEffect(() => {
|
|
40
|
+
return () => {
|
|
41
|
+
if (timerRef.current) window.clearTimeout(timerRef.current);
|
|
42
|
+
};
|
|
43
|
+
}, []);
|
|
44
|
+
const resetLater = () => {
|
|
45
|
+
if (timerRef.current) window.clearTimeout(timerRef.current);
|
|
46
|
+
timerRef.current = window.setTimeout(
|
|
47
|
+
() => setState("idle"),
|
|
48
|
+
resetDelay
|
|
49
|
+
);
|
|
50
|
+
};
|
|
51
|
+
const copyFallback = async (text) => {
|
|
52
|
+
const ta = document.createElement("textarea");
|
|
53
|
+
ta.value = text;
|
|
54
|
+
ta.setAttribute("readonly", "");
|
|
55
|
+
ta.style.position = "absolute";
|
|
56
|
+
ta.style.left = "-9999px";
|
|
57
|
+
document.body.appendChild(ta);
|
|
58
|
+
const selection = document.getSelection();
|
|
59
|
+
const selected = selection && selection.rangeCount > 0 ? selection.getRangeAt(0) : null;
|
|
60
|
+
ta.select();
|
|
61
|
+
let ok = false;
|
|
62
|
+
try {
|
|
63
|
+
ok = document.execCommand("copy");
|
|
64
|
+
} finally {
|
|
65
|
+
document.body.removeChild(ta);
|
|
66
|
+
if (selected && selection) {
|
|
67
|
+
selection.removeAllRanges();
|
|
68
|
+
selection.addRange(selected);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
return ok;
|
|
72
|
+
};
|
|
73
|
+
const handleCopy = async () => {
|
|
74
|
+
var _a2;
|
|
75
|
+
if (disabled) return;
|
|
76
|
+
const text = resolveValue();
|
|
77
|
+
if (!text) {
|
|
78
|
+
setState("error");
|
|
79
|
+
onCopy == null ? void 0 : onCopy(text, false, new Error("No copy value"));
|
|
80
|
+
resetLater();
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
try {
|
|
84
|
+
if ((_a2 = navigator == null ? void 0 : navigator.clipboard) == null ? void 0 : _a2.writeText) {
|
|
85
|
+
await navigator.clipboard.writeText(text);
|
|
86
|
+
setState("copied");
|
|
87
|
+
onCopy == null ? void 0 : onCopy(text, true);
|
|
88
|
+
} else {
|
|
89
|
+
const ok = await copyFallback(text);
|
|
90
|
+
setState(ok ? "copied" : "error");
|
|
91
|
+
onCopy == null ? void 0 : onCopy(text, ok, ok ? void 0 : new Error("Fallback copy failed"));
|
|
92
|
+
}
|
|
93
|
+
} catch (err) {
|
|
94
|
+
setState("error");
|
|
95
|
+
onCopy == null ? void 0 : onCopy(text, false, err);
|
|
96
|
+
} finally {
|
|
97
|
+
resetLater();
|
|
98
|
+
}
|
|
99
|
+
};
|
|
100
|
+
const isIconOnly = !children;
|
|
101
|
+
return /* @__PURE__ */ jsx(Tooltip, { content: tooltipContent, children: /* @__PURE__ */ jsx(
|
|
102
|
+
Button,
|
|
103
|
+
{
|
|
104
|
+
"aria-label": isIconOnly ? (_a = translations == null ? void 0 : translations.copy) != null ? _a : "Copy" : void 0,
|
|
105
|
+
isIconOnly,
|
|
106
|
+
startContent: !isIconOnly ? /* @__PURE__ */ jsx(CopyIcon, {}) : void 0,
|
|
107
|
+
variant,
|
|
108
|
+
disabled,
|
|
109
|
+
...restProps,
|
|
110
|
+
onClick: callAllHandlers(handleCopy, onClick),
|
|
111
|
+
children: isIconOnly ? /* @__PURE__ */ jsx(CopyIcon, {}) : children
|
|
112
|
+
}
|
|
113
|
+
) });
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
export {
|
|
117
|
+
CopyButton
|
|
118
|
+
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import { ButtonProps } from './button.mjs';
|
|
3
|
+
import '@kopexa/theme';
|
|
4
|
+
import 'react';
|
|
5
|
+
|
|
6
|
+
type CopyButtonProps = Omit<ButtonProps, "isIconOnly"> & {
|
|
7
|
+
/** Tooltip translations. */
|
|
8
|
+
translations?: {
|
|
9
|
+
copy?: string;
|
|
10
|
+
copied?: string;
|
|
11
|
+
error?: string;
|
|
12
|
+
};
|
|
13
|
+
/** The text to copy. Can also be a function that returns the text at click time. */
|
|
14
|
+
value?: string | (() => string);
|
|
15
|
+
/** Optional callback after copy attempt. */
|
|
16
|
+
onCopy?: (value: string, ok: boolean, error?: unknown) => void;
|
|
17
|
+
/** Milliseconds until tooltip resets back to "Copy". */
|
|
18
|
+
resetDelay?: number;
|
|
19
|
+
};
|
|
20
|
+
declare const CopyButton: ({ children, variant, value, onCopy, translations, resetDelay, disabled, onClick, ...restProps }: CopyButtonProps) => react_jsx_runtime.JSX.Element;
|
|
21
|
+
|
|
22
|
+
export { CopyButton, type CopyButtonProps };
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import { ButtonProps } from './button.js';
|
|
3
|
+
import '@kopexa/theme';
|
|
4
|
+
import 'react';
|
|
5
|
+
|
|
6
|
+
type CopyButtonProps = Omit<ButtonProps, "isIconOnly"> & {
|
|
7
|
+
/** Tooltip translations. */
|
|
8
|
+
translations?: {
|
|
9
|
+
copy?: string;
|
|
10
|
+
copied?: string;
|
|
11
|
+
error?: string;
|
|
12
|
+
};
|
|
13
|
+
/** The text to copy. Can also be a function that returns the text at click time. */
|
|
14
|
+
value?: string | (() => string);
|
|
15
|
+
/** Optional callback after copy attempt. */
|
|
16
|
+
onCopy?: (value: string, ok: boolean, error?: unknown) => void;
|
|
17
|
+
/** Milliseconds until tooltip resets back to "Copy". */
|
|
18
|
+
resetDelay?: number;
|
|
19
|
+
};
|
|
20
|
+
declare const CopyButton: ({ children, variant, value, onCopy, translations, resetDelay, disabled, onClick, ...restProps }: CopyButtonProps) => react_jsx_runtime.JSX.Element;
|
|
21
|
+
|
|
22
|
+
export { CopyButton, type CopyButtonProps };
|
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
"use strict";
|
|
3
|
+
var __create = Object.create;
|
|
4
|
+
var __defProp = Object.defineProperty;
|
|
5
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
6
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
8
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
9
|
+
var __export = (target, all) => {
|
|
10
|
+
for (var name in all)
|
|
11
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
12
|
+
};
|
|
13
|
+
var __copyProps = (to, from, except, desc) => {
|
|
14
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
15
|
+
for (let key of __getOwnPropNames(from))
|
|
16
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
17
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
18
|
+
}
|
|
19
|
+
return to;
|
|
20
|
+
};
|
|
21
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
22
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
23
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
24
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
25
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
26
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
27
|
+
mod
|
|
28
|
+
));
|
|
29
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
30
|
+
|
|
31
|
+
// src/copy-button.tsx
|
|
32
|
+
var copy_button_exports = {};
|
|
33
|
+
__export(copy_button_exports, {
|
|
34
|
+
CopyButton: () => CopyButton
|
|
35
|
+
});
|
|
36
|
+
module.exports = __toCommonJS(copy_button_exports);
|
|
37
|
+
var import_icons = require("@kopexa/icons");
|
|
38
|
+
var import_shared_utils2 = require("@kopexa/shared-utils");
|
|
39
|
+
var import_tooltip = require("@kopexa/tooltip");
|
|
40
|
+
var import_react2 = require("react");
|
|
41
|
+
|
|
42
|
+
// src/button.tsx
|
|
43
|
+
var import_react_utils = require("@kopexa/react-utils");
|
|
44
|
+
var import_ripple = require("@kopexa/ripple");
|
|
45
|
+
var import_shared_utils = require("@kopexa/shared-utils");
|
|
46
|
+
var import_spinner = require("@kopexa/spinner");
|
|
47
|
+
var import_theme = require("@kopexa/theme");
|
|
48
|
+
var Slot = __toESM(require("@radix-ui/react-slot"));
|
|
49
|
+
var import_react = require("react");
|
|
50
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
51
|
+
var Button = (props) => {
|
|
52
|
+
const {
|
|
53
|
+
type = "button",
|
|
54
|
+
asChild,
|
|
55
|
+
children,
|
|
56
|
+
onClick,
|
|
57
|
+
disabled,
|
|
58
|
+
disableRipple,
|
|
59
|
+
ref,
|
|
60
|
+
isLoading,
|
|
61
|
+
variant,
|
|
62
|
+
size = "sm",
|
|
63
|
+
className,
|
|
64
|
+
color,
|
|
65
|
+
radius,
|
|
66
|
+
fullWidth,
|
|
67
|
+
startContent,
|
|
68
|
+
endContent,
|
|
69
|
+
isIconOnly,
|
|
70
|
+
spinnerPlacement = "start",
|
|
71
|
+
...rest
|
|
72
|
+
} = props;
|
|
73
|
+
const Comp = asChild ? Slot.Root : "button";
|
|
74
|
+
const domRef = (0, import_react.useRef)(null);
|
|
75
|
+
const isDisabled = disabled || isLoading;
|
|
76
|
+
const {
|
|
77
|
+
onClick: onRippleClickHandler,
|
|
78
|
+
onClear: onClearRipple,
|
|
79
|
+
ripples
|
|
80
|
+
} = (0, import_ripple.useRipple)();
|
|
81
|
+
const styles = (0, import_react.useMemo)(() => {
|
|
82
|
+
return (0, import_theme.button)({
|
|
83
|
+
variant,
|
|
84
|
+
size,
|
|
85
|
+
color,
|
|
86
|
+
radius,
|
|
87
|
+
fullWidth,
|
|
88
|
+
isIconOnly,
|
|
89
|
+
className
|
|
90
|
+
});
|
|
91
|
+
}, [variant, size, color, radius, isIconOnly, fullWidth, className]);
|
|
92
|
+
const handleClick = (0, import_react.useCallback)(
|
|
93
|
+
(e) => {
|
|
94
|
+
if (disableRipple || isDisabled) return;
|
|
95
|
+
domRef.current && onRippleClickHandler(e);
|
|
96
|
+
onClick == null ? void 0 : onClick(e);
|
|
97
|
+
},
|
|
98
|
+
[onClick, disableRipple, isDisabled, onRippleClickHandler]
|
|
99
|
+
);
|
|
100
|
+
const getRippleProps = (0, import_react.useCallback)(
|
|
101
|
+
() => ({ ripples, onClear: onClearRipple }),
|
|
102
|
+
[ripples, onClearRipple]
|
|
103
|
+
);
|
|
104
|
+
const spinnerSize = (0, import_react.useMemo)(() => {
|
|
105
|
+
const buttonSpinnerSizeMap = {
|
|
106
|
+
sm: "xs",
|
|
107
|
+
md: "sm",
|
|
108
|
+
lg: "md"
|
|
109
|
+
};
|
|
110
|
+
return buttonSpinnerSizeMap[size];
|
|
111
|
+
}, [size]);
|
|
112
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
113
|
+
Comp,
|
|
114
|
+
{
|
|
115
|
+
type,
|
|
116
|
+
className: styles,
|
|
117
|
+
onClick: handleClick,
|
|
118
|
+
ref: (0, import_react_utils.mergeRefs)(domRef, ref),
|
|
119
|
+
disabled: isDisabled,
|
|
120
|
+
"data-disabled": (0, import_shared_utils.dataAttr)(isDisabled),
|
|
121
|
+
"data-loading": (0, import_shared_utils.dataAttr)(isLoading),
|
|
122
|
+
"aria-disabled": isDisabled,
|
|
123
|
+
tabIndex: isDisabled ? -1 : void 0,
|
|
124
|
+
...rest,
|
|
125
|
+
children: [
|
|
126
|
+
isLoading && spinnerPlacement === "start" ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_spinner.Spinner, { color: "current", size: spinnerSize }) : startContent,
|
|
127
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Slot.Slottable, { children }),
|
|
128
|
+
isLoading && spinnerPlacement === "end" ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_spinner.Spinner, { color: "current", size: spinnerSize }) : endContent,
|
|
129
|
+
!disableRipple && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_ripple.Ripple, { ...getRippleProps() })
|
|
130
|
+
]
|
|
131
|
+
}
|
|
132
|
+
);
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
// src/copy-button.tsx
|
|
136
|
+
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
137
|
+
var CopyButton = ({
|
|
138
|
+
children,
|
|
139
|
+
variant = "ghost",
|
|
140
|
+
value,
|
|
141
|
+
onCopy,
|
|
142
|
+
translations,
|
|
143
|
+
resetDelay = 1200,
|
|
144
|
+
disabled,
|
|
145
|
+
onClick,
|
|
146
|
+
...restProps
|
|
147
|
+
}) => {
|
|
148
|
+
var _a;
|
|
149
|
+
const [state, setState] = (0, import_react2.useState)("idle");
|
|
150
|
+
const timerRef = (0, import_react2.useRef)(null);
|
|
151
|
+
const resolveValue = () => {
|
|
152
|
+
var _a2;
|
|
153
|
+
if (typeof value === "function") return (_a2 = value()) != null ? _a2 : "";
|
|
154
|
+
if (typeof value === "string") return value;
|
|
155
|
+
if (typeof children === "string") return children;
|
|
156
|
+
return "";
|
|
157
|
+
};
|
|
158
|
+
const tooltipContent = (0, import_react2.useMemo)(() => {
|
|
159
|
+
var _a2, _b, _c;
|
|
160
|
+
if (state === "copied") return (_a2 = translations == null ? void 0 : translations.copied) != null ? _a2 : "Copied";
|
|
161
|
+
if (state === "error") return (_b = translations == null ? void 0 : translations.error) != null ? _b : "Copy failed";
|
|
162
|
+
return (_c = translations == null ? void 0 : translations.copy) != null ? _c : "Copy";
|
|
163
|
+
}, [state, translations]);
|
|
164
|
+
(0, import_react2.useEffect)(() => {
|
|
165
|
+
return () => {
|
|
166
|
+
if (timerRef.current) window.clearTimeout(timerRef.current);
|
|
167
|
+
};
|
|
168
|
+
}, []);
|
|
169
|
+
const resetLater = () => {
|
|
170
|
+
if (timerRef.current) window.clearTimeout(timerRef.current);
|
|
171
|
+
timerRef.current = window.setTimeout(
|
|
172
|
+
() => setState("idle"),
|
|
173
|
+
resetDelay
|
|
174
|
+
);
|
|
175
|
+
};
|
|
176
|
+
const copyFallback = async (text) => {
|
|
177
|
+
const ta = document.createElement("textarea");
|
|
178
|
+
ta.value = text;
|
|
179
|
+
ta.setAttribute("readonly", "");
|
|
180
|
+
ta.style.position = "absolute";
|
|
181
|
+
ta.style.left = "-9999px";
|
|
182
|
+
document.body.appendChild(ta);
|
|
183
|
+
const selection = document.getSelection();
|
|
184
|
+
const selected = selection && selection.rangeCount > 0 ? selection.getRangeAt(0) : null;
|
|
185
|
+
ta.select();
|
|
186
|
+
let ok = false;
|
|
187
|
+
try {
|
|
188
|
+
ok = document.execCommand("copy");
|
|
189
|
+
} finally {
|
|
190
|
+
document.body.removeChild(ta);
|
|
191
|
+
if (selected && selection) {
|
|
192
|
+
selection.removeAllRanges();
|
|
193
|
+
selection.addRange(selected);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
return ok;
|
|
197
|
+
};
|
|
198
|
+
const handleCopy = async () => {
|
|
199
|
+
var _a2;
|
|
200
|
+
if (disabled) return;
|
|
201
|
+
const text = resolveValue();
|
|
202
|
+
if (!text) {
|
|
203
|
+
setState("error");
|
|
204
|
+
onCopy == null ? void 0 : onCopy(text, false, new Error("No copy value"));
|
|
205
|
+
resetLater();
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
try {
|
|
209
|
+
if ((_a2 = navigator == null ? void 0 : navigator.clipboard) == null ? void 0 : _a2.writeText) {
|
|
210
|
+
await navigator.clipboard.writeText(text);
|
|
211
|
+
setState("copied");
|
|
212
|
+
onCopy == null ? void 0 : onCopy(text, true);
|
|
213
|
+
} else {
|
|
214
|
+
const ok = await copyFallback(text);
|
|
215
|
+
setState(ok ? "copied" : "error");
|
|
216
|
+
onCopy == null ? void 0 : onCopy(text, ok, ok ? void 0 : new Error("Fallback copy failed"));
|
|
217
|
+
}
|
|
218
|
+
} catch (err) {
|
|
219
|
+
setState("error");
|
|
220
|
+
onCopy == null ? void 0 : onCopy(text, false, err);
|
|
221
|
+
} finally {
|
|
222
|
+
resetLater();
|
|
223
|
+
}
|
|
224
|
+
};
|
|
225
|
+
const isIconOnly = !children;
|
|
226
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_tooltip.Tooltip, { content: tooltipContent, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
227
|
+
Button,
|
|
228
|
+
{
|
|
229
|
+
"aria-label": isIconOnly ? (_a = translations == null ? void 0 : translations.copy) != null ? _a : "Copy" : void 0,
|
|
230
|
+
isIconOnly,
|
|
231
|
+
startContent: !isIconOnly ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_icons.CopyIcon, {}) : void 0,
|
|
232
|
+
variant,
|
|
233
|
+
disabled,
|
|
234
|
+
...restProps,
|
|
235
|
+
onClick: (0, import_shared_utils2.callAllHandlers)(handleCopy, onClick),
|
|
236
|
+
children: isIconOnly ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_icons.CopyIcon, {}) : children
|
|
237
|
+
}
|
|
238
|
+
) });
|
|
239
|
+
};
|
|
240
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
241
|
+
0 && (module.exports = {
|
|
242
|
+
CopyButton
|
|
243
|
+
});
|
package/dist/icon-button.d.mts
CHANGED
package/dist/icon-button.d.ts
CHANGED
package/dist/index.d.mts
CHANGED
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -32,6 +32,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
32
32
|
var index_exports = {};
|
|
33
33
|
__export(index_exports, {
|
|
34
34
|
Button: () => Button,
|
|
35
|
+
CopyButton: () => CopyButton,
|
|
35
36
|
IconButton: () => IconButton
|
|
36
37
|
});
|
|
37
38
|
module.exports = __toCommonJS(index_exports);
|
|
@@ -129,30 +130,141 @@ var Button = (props) => {
|
|
|
129
130
|
);
|
|
130
131
|
};
|
|
131
132
|
|
|
132
|
-
// src/
|
|
133
|
+
// src/copy-button.tsx
|
|
134
|
+
var import_icons = require("@kopexa/icons");
|
|
135
|
+
var import_shared_utils2 = require("@kopexa/shared-utils");
|
|
133
136
|
var import_tooltip = require("@kopexa/tooltip");
|
|
134
137
|
var import_react2 = require("react");
|
|
135
138
|
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
139
|
+
var CopyButton = ({
|
|
140
|
+
children,
|
|
141
|
+
variant = "ghost",
|
|
142
|
+
value,
|
|
143
|
+
onCopy,
|
|
144
|
+
translations,
|
|
145
|
+
resetDelay = 1200,
|
|
146
|
+
disabled,
|
|
147
|
+
onClick,
|
|
148
|
+
...restProps
|
|
149
|
+
}) => {
|
|
150
|
+
var _a;
|
|
151
|
+
const [state, setState] = (0, import_react2.useState)("idle");
|
|
152
|
+
const timerRef = (0, import_react2.useRef)(null);
|
|
153
|
+
const resolveValue = () => {
|
|
154
|
+
var _a2;
|
|
155
|
+
if (typeof value === "function") return (_a2 = value()) != null ? _a2 : "";
|
|
156
|
+
if (typeof value === "string") return value;
|
|
157
|
+
if (typeof children === "string") return children;
|
|
158
|
+
return "";
|
|
159
|
+
};
|
|
160
|
+
const tooltipContent = (0, import_react2.useMemo)(() => {
|
|
161
|
+
var _a2, _b, _c;
|
|
162
|
+
if (state === "copied") return (_a2 = translations == null ? void 0 : translations.copied) != null ? _a2 : "Copied";
|
|
163
|
+
if (state === "error") return (_b = translations == null ? void 0 : translations.error) != null ? _b : "Copy failed";
|
|
164
|
+
return (_c = translations == null ? void 0 : translations.copy) != null ? _c : "Copy";
|
|
165
|
+
}, [state, translations]);
|
|
166
|
+
(0, import_react2.useEffect)(() => {
|
|
167
|
+
return () => {
|
|
168
|
+
if (timerRef.current) window.clearTimeout(timerRef.current);
|
|
169
|
+
};
|
|
170
|
+
}, []);
|
|
171
|
+
const resetLater = () => {
|
|
172
|
+
if (timerRef.current) window.clearTimeout(timerRef.current);
|
|
173
|
+
timerRef.current = window.setTimeout(
|
|
174
|
+
() => setState("idle"),
|
|
175
|
+
resetDelay
|
|
176
|
+
);
|
|
177
|
+
};
|
|
178
|
+
const copyFallback = async (text) => {
|
|
179
|
+
const ta = document.createElement("textarea");
|
|
180
|
+
ta.value = text;
|
|
181
|
+
ta.setAttribute("readonly", "");
|
|
182
|
+
ta.style.position = "absolute";
|
|
183
|
+
ta.style.left = "-9999px";
|
|
184
|
+
document.body.appendChild(ta);
|
|
185
|
+
const selection = document.getSelection();
|
|
186
|
+
const selected = selection && selection.rangeCount > 0 ? selection.getRangeAt(0) : null;
|
|
187
|
+
ta.select();
|
|
188
|
+
let ok = false;
|
|
189
|
+
try {
|
|
190
|
+
ok = document.execCommand("copy");
|
|
191
|
+
} finally {
|
|
192
|
+
document.body.removeChild(ta);
|
|
193
|
+
if (selected && selection) {
|
|
194
|
+
selection.removeAllRanges();
|
|
195
|
+
selection.addRange(selected);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
return ok;
|
|
199
|
+
};
|
|
200
|
+
const handleCopy = async () => {
|
|
201
|
+
var _a2;
|
|
202
|
+
if (disabled) return;
|
|
203
|
+
const text = resolveValue();
|
|
204
|
+
if (!text) {
|
|
205
|
+
setState("error");
|
|
206
|
+
onCopy == null ? void 0 : onCopy(text, false, new Error("No copy value"));
|
|
207
|
+
resetLater();
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
try {
|
|
211
|
+
if ((_a2 = navigator == null ? void 0 : navigator.clipboard) == null ? void 0 : _a2.writeText) {
|
|
212
|
+
await navigator.clipboard.writeText(text);
|
|
213
|
+
setState("copied");
|
|
214
|
+
onCopy == null ? void 0 : onCopy(text, true);
|
|
215
|
+
} else {
|
|
216
|
+
const ok = await copyFallback(text);
|
|
217
|
+
setState(ok ? "copied" : "error");
|
|
218
|
+
onCopy == null ? void 0 : onCopy(text, ok, ok ? void 0 : new Error("Fallback copy failed"));
|
|
219
|
+
}
|
|
220
|
+
} catch (err) {
|
|
221
|
+
setState("error");
|
|
222
|
+
onCopy == null ? void 0 : onCopy(text, false, err);
|
|
223
|
+
} finally {
|
|
224
|
+
resetLater();
|
|
225
|
+
}
|
|
226
|
+
};
|
|
227
|
+
const isIconOnly = !children;
|
|
228
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_tooltip.Tooltip, { content: tooltipContent, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
229
|
+
Button,
|
|
230
|
+
{
|
|
231
|
+
"aria-label": isIconOnly ? (_a = translations == null ? void 0 : translations.copy) != null ? _a : "Copy" : void 0,
|
|
232
|
+
isIconOnly,
|
|
233
|
+
startContent: !isIconOnly ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_icons.CopyIcon, {}) : void 0,
|
|
234
|
+
variant,
|
|
235
|
+
disabled,
|
|
236
|
+
...restProps,
|
|
237
|
+
onClick: (0, import_shared_utils2.callAllHandlers)(handleCopy, onClick),
|
|
238
|
+
children: isIconOnly ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_icons.CopyIcon, {}) : children
|
|
239
|
+
}
|
|
240
|
+
) });
|
|
241
|
+
};
|
|
242
|
+
|
|
243
|
+
// src/icon-button.tsx
|
|
244
|
+
var import_tooltip2 = require("@kopexa/tooltip");
|
|
245
|
+
var import_react3 = require("react");
|
|
246
|
+
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
136
247
|
var IconButton = (props) => {
|
|
137
248
|
const { "aria-label": ariaLabel, children, ...rest } = props;
|
|
138
249
|
const label = ariaLabel || children;
|
|
139
|
-
const toolip = (0,
|
|
250
|
+
const toolip = (0, import_react3.useMemo)(() => {
|
|
140
251
|
if (label && typeof label === "string") {
|
|
141
252
|
return label;
|
|
142
253
|
}
|
|
143
254
|
return void 0;
|
|
144
255
|
}, [label]);
|
|
145
|
-
const clonedChildren = (0,
|
|
256
|
+
const clonedChildren = (0, import_react3.isValidElement)(children) ? (
|
|
146
257
|
// biome-ignore lint/suspicious/noExplicitAny: forcing type to any
|
|
147
|
-
(0,
|
|
258
|
+
(0, import_react3.cloneElement)(children, { "aria-hidden": true })
|
|
148
259
|
) : children;
|
|
149
260
|
if (toolip) {
|
|
150
|
-
return /* @__PURE__ */ (0,
|
|
261
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_tooltip2.Tooltip, { content: toolip, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Button, { ...rest, "aria-label": ariaLabel, isIconOnly: true, children: clonedChildren }) });
|
|
151
262
|
}
|
|
152
|
-
return /* @__PURE__ */ (0,
|
|
263
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Button, { ...rest, "aria-label": ariaLabel, isIconOnly: true, children: clonedChildren });
|
|
153
264
|
};
|
|
154
265
|
// Annotate the CommonJS export names for ESM import in node:
|
|
155
266
|
0 && (module.exports = {
|
|
156
267
|
Button,
|
|
268
|
+
CopyButton,
|
|
157
269
|
IconButton
|
|
158
270
|
});
|
package/dist/index.mjs
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kopexa/button",
|
|
3
|
-
"version": "8.0.
|
|
3
|
+
"version": "8.0.2",
|
|
4
4
|
"description": "Buttons allow users to perform actions and choose with a single tap.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"button"
|
|
@@ -28,15 +28,16 @@
|
|
|
28
28
|
"motion": ">=12.23.6",
|
|
29
29
|
"react": ">=19.0.0-rc.0",
|
|
30
30
|
"react-dom": ">=19.0.0-rc.0",
|
|
31
|
-
"@kopexa/theme": "1.7.
|
|
31
|
+
"@kopexa/theme": "1.7.2"
|
|
32
32
|
},
|
|
33
33
|
"dependencies": {
|
|
34
34
|
"@radix-ui/react-slot": "^1.2.3",
|
|
35
35
|
"@kopexa/shared-utils": "1.1.5",
|
|
36
36
|
"@kopexa/react-utils": "2.0.6",
|
|
37
|
-
"@kopexa/spinner": "6.0.
|
|
38
|
-
"@kopexa/tooltip": "6.0.
|
|
39
|
-
"@kopexa/ripple": "10.0.
|
|
37
|
+
"@kopexa/spinner": "6.0.2",
|
|
38
|
+
"@kopexa/tooltip": "6.0.2",
|
|
39
|
+
"@kopexa/ripple": "10.0.2",
|
|
40
|
+
"@kopexa/icons": "10.0.2"
|
|
40
41
|
},
|
|
41
42
|
"clean-package": "../../../clean-package.config.json",
|
|
42
43
|
"module": "dist/index.mjs",
|