niuma-ui 1.3.2 → 1.3.4
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/CHANGELOG.md +12 -0
- package/dist/components/RsLog.css +53 -39
- package/dist/components/RsLog.impl.js +13 -1
- package/dist/components/RsLog.js +1 -1
- package/dist/locale/messages.js +2 -0
- package/dist/utils/rs-clipboard.d.ts +3 -1
- package/dist/utils/rs-clipboard.js +13 -3
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,18 @@
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
## [1.3.4] - 2026-09-11
|
|
10
|
+
|
|
11
|
+
### 修复
|
|
12
|
+
|
|
13
|
+
- `RsLog` 在 HTTP(非安全上下文)下复制:不再先走会失败的 Clipboard API(`await` 会丢掉用户手势),改为同步 `execCommand`;级别/行号不可选中,避免复制出「输出」「信息」。失败时工具栏提示复制失败。
|
|
14
|
+
|
|
15
|
+
## [1.3.3] - 2026-09-09
|
|
16
|
+
|
|
17
|
+
### 修复
|
|
18
|
+
|
|
19
|
+
- `RsLog` 开启 `wrap` 时不再把每一行拉成整栏高度,避免日志区上半空白、正文挤在底部。Playground `/log` 增加撑满栏折行示例;`/#/visual/rs-log` + `pnpm test:visual` 用几何断言锁行高(jsdom 测不到)。
|
|
20
|
+
|
|
9
21
|
## [1.3.2] - 2026-09-09
|
|
10
22
|
|
|
11
23
|
### 修复
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
|
|
2
|
-
.rs-log[data-v-
|
|
2
|
+
.rs-log[data-v-0c4db684] {
|
|
3
3
|
display: flex;
|
|
4
4
|
flex-direction: column;
|
|
5
5
|
min-height: 0;
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
line-height: 1.45;
|
|
14
14
|
height: var(--rs-log-box-height, 280px);
|
|
15
15
|
}
|
|
16
|
-
.rs-log__chrome[data-v-
|
|
16
|
+
.rs-log__chrome[data-v-0c4db684] {
|
|
17
17
|
display: flex;
|
|
18
18
|
flex-wrap: wrap;
|
|
19
19
|
gap: 0.45rem;
|
|
@@ -22,15 +22,15 @@
|
|
|
22
22
|
border-bottom: 1px solid var(--rs-log-border, var(--rs-border));
|
|
23
23
|
background: color-mix(in srgb, var(--rs-log-bg, var(--rs-surface)) 88%, var(--rs-surface-hover));
|
|
24
24
|
}
|
|
25
|
-
.rs-log__search[data-v-
|
|
25
|
+
.rs-log__search[data-v-0c4db684] {
|
|
26
26
|
min-width: 10rem;
|
|
27
27
|
flex: 1 1 12rem;
|
|
28
28
|
}
|
|
29
|
-
.rs-log__copy[data-v-
|
|
29
|
+
.rs-log__copy[data-v-0c4db684] {
|
|
30
30
|
flex-shrink: 0;
|
|
31
31
|
margin-inline-start: auto;
|
|
32
32
|
}
|
|
33
|
-
.rs-log__filters[data-v-
|
|
33
|
+
.rs-log__filters[data-v-0c4db684] {
|
|
34
34
|
display: flex;
|
|
35
35
|
flex-wrap: wrap;
|
|
36
36
|
gap: 0.3rem;
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
border: 0;
|
|
40
40
|
min-inline-size: 0;
|
|
41
41
|
}
|
|
42
|
-
.rs-log__chip[data-v-
|
|
42
|
+
.rs-log__chip[data-v-0c4db684] {
|
|
43
43
|
margin: 0;
|
|
44
44
|
padding: 0.1rem 0.4rem;
|
|
45
45
|
border: 1px solid var(--rs-log-border, var(--rs-border));
|
|
@@ -50,54 +50,63 @@
|
|
|
50
50
|
font-size: var(--rs-font-size-xs);
|
|
51
51
|
cursor: pointer;
|
|
52
52
|
}
|
|
53
|
-
.rs-log__chip--on[data-v-
|
|
53
|
+
.rs-log__chip--on[data-v-0c4db684] {
|
|
54
54
|
color: var(--rs-log-fg, var(--rs-text));
|
|
55
55
|
border-color: color-mix(in srgb, var(--rs-primary) 45%, var(--rs-log-border, var(--rs-border)));
|
|
56
56
|
background: color-mix(in srgb, var(--rs-primary) 14%, transparent);
|
|
57
57
|
}
|
|
58
|
-
.rs-log__viewport[data-v-
|
|
58
|
+
.rs-log__viewport[data-v-0c4db684] {
|
|
59
59
|
display: flex;
|
|
60
60
|
flex-direction: column;
|
|
61
61
|
flex: 1;
|
|
62
62
|
min-height: 0;
|
|
63
63
|
outline: none;
|
|
64
64
|
}
|
|
65
|
-
.rs-log__viewport[data-v-
|
|
65
|
+
.rs-log__viewport[data-v-0c4db684]:focus-visible {
|
|
66
66
|
box-shadow: inset 0 0 0 var(--rs-focus-ring-width, 2px) var(--rs-focus-border);
|
|
67
67
|
}
|
|
68
|
-
.rs-log__list[data-v-
|
|
69
|
-
.rs-log__plain[data-v-
|
|
68
|
+
.rs-log__list[data-v-0c4db684],
|
|
69
|
+
.rs-log__plain[data-v-0c4db684] {
|
|
70
70
|
flex: 1;
|
|
71
71
|
min-height: 0;
|
|
72
72
|
border: 0;
|
|
73
73
|
background: transparent;
|
|
74
74
|
}
|
|
75
|
-
.rs-log__plain[data-v-
|
|
75
|
+
.rs-log__plain[data-v-0c4db684] {
|
|
76
76
|
overflow: auto;
|
|
77
77
|
}
|
|
78
|
-
.rs-log__row[data-v-
|
|
78
|
+
.rs-log__row[data-v-0c4db684] {
|
|
79
79
|
display: flex;
|
|
80
80
|
align-items: flex-start;
|
|
81
81
|
gap: 0.55rem;
|
|
82
82
|
box-sizing: border-box;
|
|
83
|
-
min-height: 100%;
|
|
84
83
|
padding: 0 0.7rem;
|
|
85
84
|
white-space: nowrap;
|
|
86
85
|
color: var(--rs-log-row-fg, var(--rs-log-fg));
|
|
87
86
|
}
|
|
88
|
-
.rs-log--wrap .rs-log__row[data-v-
|
|
87
|
+
.rs-log:not(.rs-log--wrap) .rs-log__list .rs-log__row[data-v-0c4db684] {
|
|
88
|
+
min-height: 100%;
|
|
89
|
+
}
|
|
90
|
+
.rs-log--wrap .rs-log__plain[data-v-0c4db684] {
|
|
91
|
+
display: block;
|
|
92
|
+
}
|
|
93
|
+
.rs-log--wrap .rs-log__row[data-v-0c4db684] {
|
|
94
|
+
height: auto;
|
|
95
|
+
max-height: none;
|
|
96
|
+
min-height: 0;
|
|
89
97
|
white-space: pre-wrap;
|
|
90
98
|
overflow-wrap: anywhere;
|
|
99
|
+
word-break: break-word;
|
|
91
100
|
padding-block: 0.25rem;
|
|
92
101
|
}
|
|
93
|
-
.rs-log--zebra .rs-log__row--odd[data-v-
|
|
102
|
+
.rs-log--zebra .rs-log__row--odd[data-v-0c4db684] {
|
|
94
103
|
background: var(--rs-log-stripe, transparent);
|
|
95
104
|
}
|
|
96
|
-
.rs-log__row--active[data-v-
|
|
105
|
+
.rs-log__row--active[data-v-0c4db684] {
|
|
97
106
|
background: color-mix(in srgb, var(--rs-primary) 12%, var(--rs-log-bg, transparent));
|
|
98
107
|
box-shadow: inset 2px 0 0 var(--rs-primary);
|
|
99
108
|
}
|
|
100
|
-
.rs-log__marker[data-v-
|
|
109
|
+
.rs-log__marker[data-v-0c4db684] {
|
|
101
110
|
flex-shrink: 0;
|
|
102
111
|
width: 0.2rem;
|
|
103
112
|
align-self: stretch;
|
|
@@ -105,42 +114,47 @@
|
|
|
105
114
|
margin-block: 0.2rem;
|
|
106
115
|
border-radius: 99px;
|
|
107
116
|
background: currentColor;
|
|
117
|
+
user-select: none;
|
|
108
118
|
}
|
|
109
|
-
.rs-log__no[data-v-
|
|
110
|
-
.rs-log__time[data-v-
|
|
119
|
+
.rs-log__no[data-v-0c4db684],
|
|
120
|
+
.rs-log__time[data-v-0c4db684] {
|
|
111
121
|
flex-shrink: 0;
|
|
112
122
|
color: var(--rs-log-muted, var(--rs-text-muted));
|
|
113
123
|
font-variant-numeric: tabular-nums;
|
|
114
124
|
unicode-bidi: isolate;
|
|
125
|
+
user-select: none;
|
|
115
126
|
}
|
|
116
|
-
.rs-log__level[data-v-
|
|
127
|
+
.rs-log__level[data-v-0c4db684] {
|
|
117
128
|
flex-shrink: 0;
|
|
118
129
|
min-width: 3.6rem;
|
|
119
130
|
font-weight: var(--rs-font-weight-semibold);
|
|
120
131
|
letter-spacing: 0.02em;
|
|
121
132
|
unicode-bidi: isolate;
|
|
133
|
+
user-select: none;
|
|
122
134
|
}
|
|
123
|
-
.rs-log__text[data-v-
|
|
135
|
+
.rs-log__text[data-v-0c4db684] {
|
|
124
136
|
min-width: 0;
|
|
125
137
|
flex: 1;
|
|
126
138
|
font-weight: inherit;
|
|
127
139
|
unicode-bidi: plaintext;
|
|
128
140
|
user-select: text;
|
|
129
141
|
}
|
|
130
|
-
.rs-log--wrap .rs-log__text[data-v-
|
|
131
|
-
overflow:
|
|
142
|
+
.rs-log--wrap .rs-log__text[data-v-0c4db684] {
|
|
143
|
+
overflow: visible;
|
|
144
|
+
height: auto;
|
|
145
|
+
min-height: 0;
|
|
132
146
|
}
|
|
133
|
-
.rs-log:not(.rs-log--wrap) .rs-log__text[data-v-
|
|
147
|
+
.rs-log:not(.rs-log--wrap) .rs-log__text[data-v-0c4db684] {
|
|
134
148
|
overflow: hidden;
|
|
135
149
|
text-overflow: ellipsis;
|
|
136
150
|
}
|
|
137
|
-
.rs-log__hit[data-v-
|
|
151
|
+
.rs-log__hit[data-v-0c4db684] {
|
|
138
152
|
padding: 0 0.1em;
|
|
139
153
|
background: var(--rs-log-hit-bg);
|
|
140
154
|
color: var(--rs-log-hit-fg);
|
|
141
155
|
font: inherit;
|
|
142
156
|
}
|
|
143
|
-
.rs-log__sr-only[data-v-
|
|
157
|
+
.rs-log__sr-only[data-v-0c4db684] {
|
|
144
158
|
position: absolute;
|
|
145
159
|
width: 1px;
|
|
146
160
|
height: 1px;
|
|
@@ -151,47 +165,47 @@
|
|
|
151
165
|
white-space: nowrap;
|
|
152
166
|
border: 0;
|
|
153
167
|
}
|
|
154
|
-
.rs-log__row--plain[data-v-
|
|
168
|
+
.rs-log__row--plain[data-v-0c4db684] {
|
|
155
169
|
--rs-log-row-fg: var(--rs-log-fg);
|
|
156
170
|
font-weight: var(--rs-font-weight-regular);
|
|
157
171
|
}
|
|
158
|
-
.rs-log__row--trace[data-v-
|
|
172
|
+
.rs-log__row--trace[data-v-0c4db684] {
|
|
159
173
|
--rs-log-row-fg: var(--rs-log-trace);
|
|
160
174
|
font-weight: var(--rs-font-weight-regular);
|
|
161
175
|
}
|
|
162
|
-
.rs-log__row--debug[data-v-
|
|
176
|
+
.rs-log__row--debug[data-v-0c4db684] {
|
|
163
177
|
--rs-log-row-fg: var(--rs-log-debug);
|
|
164
178
|
font-weight: var(--rs-font-weight-regular);
|
|
165
179
|
}
|
|
166
|
-
.rs-log__row--info[data-v-
|
|
167
|
-
.rs-log__row--notice[data-v-
|
|
180
|
+
.rs-log__row--info[data-v-0c4db684],
|
|
181
|
+
.rs-log__row--notice[data-v-0c4db684] {
|
|
168
182
|
--rs-log-row-fg: var(--rs-log-info);
|
|
169
183
|
font-weight: var(--rs-font-weight-medium);
|
|
170
184
|
}
|
|
171
|
-
.rs-log__row--notice[data-v-
|
|
185
|
+
.rs-log__row--notice[data-v-0c4db684] {
|
|
172
186
|
--rs-log-row-fg: var(--rs-log-notice);
|
|
173
187
|
}
|
|
174
|
-
.rs-log__row--success[data-v-
|
|
188
|
+
.rs-log__row--success[data-v-0c4db684] {
|
|
175
189
|
--rs-log-row-fg: var(--rs-log-success);
|
|
176
190
|
font-weight: var(--rs-font-weight-medium);
|
|
177
191
|
}
|
|
178
|
-
.rs-log__row--warn[data-v-
|
|
192
|
+
.rs-log__row--warn[data-v-0c4db684] {
|
|
179
193
|
--rs-log-row-fg: var(--rs-log-warn);
|
|
180
194
|
font-weight: var(--rs-font-weight-semibold);
|
|
181
195
|
}
|
|
182
|
-
.rs-log__row--error[data-v-
|
|
196
|
+
.rs-log__row--error[data-v-0c4db684] {
|
|
183
197
|
--rs-log-row-fg: var(--rs-log-error);
|
|
184
198
|
font-weight: var(--rs-font-weight-bold);
|
|
185
199
|
}
|
|
186
|
-
.rs-log__row--fatal[data-v-
|
|
200
|
+
.rs-log__row--fatal[data-v-0c4db684] {
|
|
187
201
|
--rs-log-row-fg: var(--rs-log-fatal);
|
|
188
202
|
font-weight: var(--rs-font-weight-bold);
|
|
189
203
|
}
|
|
190
204
|
@media (forced-colors: active) {
|
|
191
|
-
.rs-log__marker[data-v-
|
|
205
|
+
.rs-log__marker[data-v-0c4db684] {
|
|
192
206
|
background: ButtonText;
|
|
193
207
|
}
|
|
194
|
-
.rs-log__row--active[data-v-
|
|
208
|
+
.rs-log__row--active[data-v-0c4db684] {
|
|
195
209
|
outline: 2px solid Highlight;
|
|
196
210
|
outline-offset: -2px;
|
|
197
211
|
}
|
|
@@ -209,8 +209,10 @@ var RsLog_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defineComp
|
|
|
209
209
|
const emptyLabel = computed(() => props.emptyText || t("log.empty", "No log output"));
|
|
210
210
|
const regionLabel = computed(() => props.ariaLabel || t("log.label", "Log"));
|
|
211
211
|
const hasChrome = computed(() => props.showSearch || props.showCopy || props.showFilter || Boolean(slots.toolbar));
|
|
212
|
+
const copyFailed = ref(false);
|
|
212
213
|
const copyTip = computed(() => {
|
|
213
214
|
if (copied.value) return t("log.copied", "Copied");
|
|
215
|
+
if (copyFailed.value) return t("log.copyFailed", "Copy failed");
|
|
214
216
|
return t("log.copy", "Copy");
|
|
215
217
|
});
|
|
216
218
|
const rootStyle = computed(() => ({
|
|
@@ -292,12 +294,22 @@ var RsLog_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defineComp
|
|
|
292
294
|
}
|
|
293
295
|
function markCopied() {
|
|
294
296
|
copied.value = true;
|
|
297
|
+
copyFailed.value = false;
|
|
295
298
|
if (copiedTimer) window.clearTimeout(copiedTimer);
|
|
296
299
|
copiedTimer = window.setTimeout(() => {
|
|
297
300
|
copied.value = false;
|
|
298
301
|
copiedTimer = 0;
|
|
299
302
|
}, 1500);
|
|
300
303
|
}
|
|
304
|
+
function markCopyFailed() {
|
|
305
|
+
copyFailed.value = true;
|
|
306
|
+
copied.value = false;
|
|
307
|
+
if (copiedTimer) window.clearTimeout(copiedTimer);
|
|
308
|
+
copiedTimer = window.setTimeout(() => {
|
|
309
|
+
copyFailed.value = false;
|
|
310
|
+
copiedTimer = 0;
|
|
311
|
+
}, 2500);
|
|
312
|
+
}
|
|
301
313
|
async function writeCopy(text, source) {
|
|
302
314
|
if (!text) return false;
|
|
303
315
|
const ok = await copyTextToClipboard(text);
|
|
@@ -307,7 +319,7 @@ var RsLog_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defineComp
|
|
|
307
319
|
text,
|
|
308
320
|
source
|
|
309
321
|
});
|
|
310
|
-
}
|
|
322
|
+
} else markCopyFailed();
|
|
311
323
|
return ok;
|
|
312
324
|
}
|
|
313
325
|
async function copy() {
|
package/dist/components/RsLog.js
CHANGED
|
@@ -3,6 +3,6 @@ import _plugin_vue_export_helper_default from "../_virtual/_plugin-vue_export-he
|
|
|
3
3
|
import RsLog_vue_vue_type_script_setup_true_lang_default from "./RsLog.impl.js";
|
|
4
4
|
|
|
5
5
|
//#region src/components/RsLog.vue
|
|
6
|
-
var RsLog_default = /*#__PURE__*/ _plugin_vue_export_helper_default(RsLog_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-
|
|
6
|
+
var RsLog_default = /*#__PURE__*/ _plugin_vue_export_helper_default(RsLog_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-0c4db684"]]);
|
|
7
7
|
//#endregion
|
|
8
8
|
export { RsLog_default as default };
|
package/dist/locale/messages.js
CHANGED
|
@@ -162,6 +162,7 @@ var zhCN = {
|
|
|
162
162
|
"log.copy": "复制全文",
|
|
163
163
|
"log.copyMatches": "复制匹配行",
|
|
164
164
|
"log.copied": "已复制",
|
|
165
|
+
"log.copyFailed": "复制失败,请用 HTTPS 或手动选择正文",
|
|
165
166
|
"log.filter": "按级别过滤",
|
|
166
167
|
"log.newLines": "新增 {count} 行",
|
|
167
168
|
"log.lineNo": "第 {n} 行",
|
|
@@ -391,6 +392,7 @@ var enUS = {
|
|
|
391
392
|
"log.copy": "Copy all",
|
|
392
393
|
"log.copyMatches": "Copy matching lines",
|
|
393
394
|
"log.copied": "Copied",
|
|
395
|
+
"log.copyFailed": "Copy failed. Use HTTPS or select the log text.",
|
|
394
396
|
"log.filter": "Filter levels",
|
|
395
397
|
"log.newLines": "{count} new lines",
|
|
396
398
|
"log.lineNo": "Line {n}",
|
|
@@ -11,7 +11,9 @@ export declare function readClipboardText(): Promise<string | null>;
|
|
|
11
11
|
export declare function writeClipboardText(text: string): Promise<boolean>;
|
|
12
12
|
/** execCommand 兜底:CEF / 无 Clipboard API 权限时菜单复制仍可用 */
|
|
13
13
|
export declare function copyTextWithExecCommand(text: string): boolean;
|
|
14
|
-
/**
|
|
14
|
+
/** HTTP / 非安全上下文没有 Clipboard API,writeText 会 SecurityError。 */
|
|
15
|
+
export declare function isInsecureClipboardContext(): boolean;
|
|
16
|
+
/** 写入系统剪贴板。HTTP 先同步 execCommand,避免 await 丢掉用户手势。 */
|
|
15
17
|
export declare function copyTextToClipboard(text: string): Promise<boolean>;
|
|
16
18
|
/** @internal vitest 用 */
|
|
17
19
|
export declare function __resetClipboardStateForTests(): void;
|
|
@@ -165,9 +165,11 @@ function copyTextWithExecCommand(text) {
|
|
|
165
165
|
const textarea = document.createElement("textarea");
|
|
166
166
|
textarea.value = text;
|
|
167
167
|
textarea.setAttribute("readonly", "");
|
|
168
|
-
textarea.style.cssText = "position:fixed;left
|
|
168
|
+
textarea.style.cssText = "position:fixed;left:0;top:0;width:1px;height:1px;padding:0;border:0;opacity:0.01";
|
|
169
169
|
document.body.appendChild(textarea);
|
|
170
|
+
if (typeof textarea.focus === "function") textarea.focus();
|
|
170
171
|
textarea.select();
|
|
172
|
+
if (typeof textarea.setSelectionRange === "function") textarea.setSelectionRange(0, text.length);
|
|
171
173
|
const ok = document.execCommand("copy");
|
|
172
174
|
textarea.remove();
|
|
173
175
|
return ok;
|
|
@@ -175,13 +177,21 @@ function copyTextWithExecCommand(text) {
|
|
|
175
177
|
return false;
|
|
176
178
|
}
|
|
177
179
|
}
|
|
178
|
-
/**
|
|
180
|
+
/** HTTP / 非安全上下文没有 Clipboard API,writeText 会 SecurityError。 */
|
|
181
|
+
function isInsecureClipboardContext() {
|
|
182
|
+
return typeof globalThis !== "undefined" && globalThis.isSecureContext === false;
|
|
183
|
+
}
|
|
184
|
+
/** 写入系统剪贴板。HTTP 先同步 execCommand,避免 await 丢掉用户手势。 */
|
|
179
185
|
async function copyTextToClipboard(text) {
|
|
180
186
|
if (!text) return false;
|
|
187
|
+
if (isInsecureClipboardContext()) {
|
|
188
|
+
if (copyTextWithExecCommand(text)) return true;
|
|
189
|
+
return writeClipboardViaShell(text);
|
|
190
|
+
}
|
|
181
191
|
await syncClipboardPermissionState();
|
|
182
192
|
if (!writeApiBlocked && await writeClipboardText(text)) return true;
|
|
183
193
|
if (copyTextWithExecCommand(text)) return true;
|
|
184
194
|
return writeClipboardViaShell(text);
|
|
185
195
|
}
|
|
186
196
|
//#endregion
|
|
187
|
-
export { beginClipboardPrefetch, copyTextToClipboard, copyTextWithExecCommand, prefetchClipboardText, readClipboardText, waitClipboardPrefetch, writeClipboardText };
|
|
197
|
+
export { beginClipboardPrefetch, copyTextToClipboard, copyTextWithExecCommand, isInsecureClipboardContext, prefetchClipboardText, readClipboardText, waitClipboardPrefetch, writeClipboardText };
|