@ashley-shrok/viewmodel-shell 0.3.13 → 0.3.14
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/browser.d.ts +1 -0
- package/dist/browser.js +48 -0
- package/dist/index.d.ts +10 -1
- package/package.json +1 -1
package/dist/browser.d.ts
CHANGED
package/dist/browser.js
CHANGED
|
@@ -1,3 +1,19 @@
|
|
|
1
|
+
function legacyCopy(text) {
|
|
2
|
+
try {
|
|
3
|
+
const ta = document.createElement("textarea");
|
|
4
|
+
ta.value = text;
|
|
5
|
+
ta.style.position = "fixed";
|
|
6
|
+
ta.style.opacity = "0";
|
|
7
|
+
document.body.appendChild(ta);
|
|
8
|
+
ta.select();
|
|
9
|
+
const ok = document.execCommand("copy");
|
|
10
|
+
document.body.removeChild(ta);
|
|
11
|
+
return ok;
|
|
12
|
+
}
|
|
13
|
+
catch {
|
|
14
|
+
return false;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
1
17
|
export class BrowserAdapter {
|
|
2
18
|
container;
|
|
3
19
|
fileRegistry = new Map();
|
|
@@ -142,6 +158,7 @@ export class BrowserAdapter {
|
|
|
142
158
|
case "progress": return this.progress(n, parent);
|
|
143
159
|
case "modal": return this.modal(n, parent, on);
|
|
144
160
|
case "table": return this.table(n, parent, on);
|
|
161
|
+
case "copy-button": return this.copyButton(n, parent);
|
|
145
162
|
}
|
|
146
163
|
}
|
|
147
164
|
kids(nodes, parent, on) {
|
|
@@ -617,4 +634,35 @@ export class BrowserAdapter {
|
|
|
617
634
|
wrapper.appendChild(table);
|
|
618
635
|
parent.appendChild(wrapper);
|
|
619
636
|
}
|
|
637
|
+
copyButton(n, parent) {
|
|
638
|
+
const btn = document.createElement("button");
|
|
639
|
+
btn.type = "button";
|
|
640
|
+
btn.className = "vms-button";
|
|
641
|
+
btn.textContent = n.label ?? "Copy";
|
|
642
|
+
btn.addEventListener("click", () => {
|
|
643
|
+
const write = navigator.clipboard?.writeText(n.text);
|
|
644
|
+
if (write) {
|
|
645
|
+
write.then(() => {
|
|
646
|
+
btn.textContent = n.copiedLabel ?? "Copied!";
|
|
647
|
+
setTimeout(() => { btn.textContent = n.label ?? "Copy"; }, 1500);
|
|
648
|
+
}).catch(() => {
|
|
649
|
+
// primary failed — try legacy execCommand fallback
|
|
650
|
+
if (legacyCopy(n.text)) {
|
|
651
|
+
btn.textContent = n.copiedLabel ?? "Copied!";
|
|
652
|
+
setTimeout(() => { btn.textContent = n.label ?? "Copy"; }, 1500);
|
|
653
|
+
}
|
|
654
|
+
// both paths failed: silent, no confirmation
|
|
655
|
+
});
|
|
656
|
+
}
|
|
657
|
+
else {
|
|
658
|
+
// navigator.clipboard absent — try legacy
|
|
659
|
+
if (legacyCopy(n.text)) {
|
|
660
|
+
btn.textContent = n.copiedLabel ?? "Copied!";
|
|
661
|
+
setTimeout(() => { btn.textContent = n.label ?? "Copy"; }, 1500);
|
|
662
|
+
}
|
|
663
|
+
// else: silent
|
|
664
|
+
}
|
|
665
|
+
});
|
|
666
|
+
parent.appendChild(btn);
|
|
667
|
+
}
|
|
620
668
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -24,7 +24,7 @@ export interface Adapter {
|
|
|
24
24
|
onUploadProgress?: (sent: number, total: number) => void;
|
|
25
25
|
}): Promise<Response>;
|
|
26
26
|
}
|
|
27
|
-
export type ViewNode = PageNode | SectionNode | ListNode | ListItemNode | FormNode | FieldNode | CheckboxNode | ButtonNode | TextNode | LinkNode | StatBarNode | TabsNode | ProgressNode | ModalNode | TableNode;
|
|
27
|
+
export type ViewNode = PageNode | SectionNode | ListNode | ListItemNode | FormNode | FieldNode | CheckboxNode | ButtonNode | TextNode | LinkNode | StatBarNode | TabsNode | ProgressNode | ModalNode | TableNode | CopyButtonNode;
|
|
28
28
|
export interface PageNode {
|
|
29
29
|
type: "page";
|
|
30
30
|
title?: string;
|
|
@@ -160,6 +160,15 @@ export interface TableNode {
|
|
|
160
160
|
/** Base action. Adapter merges { column, value, filters } into context on Enter. */
|
|
161
161
|
filterAction?: ActionEvent;
|
|
162
162
|
}
|
|
163
|
+
export interface CopyButtonNode {
|
|
164
|
+
type: "copy-button";
|
|
165
|
+
/** The string to write to the clipboard on click. */
|
|
166
|
+
text: string;
|
|
167
|
+
/** Label shown on the button before copying. Adapter default: "Copy". */
|
|
168
|
+
label?: string;
|
|
169
|
+
/** Ephemeral label shown after a successful copy, reverts after ~1.5 s. Adapter default: "Copied!". */
|
|
170
|
+
copiedLabel?: string;
|
|
171
|
+
}
|
|
163
172
|
export interface ShellOptions {
|
|
164
173
|
endpoint: string;
|
|
165
174
|
actionEndpoint: string;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ashley-shrok/viewmodel-shell",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.14",
|
|
4
4
|
"description": "A server-driven UI framework where the wire format is structured enough that agents can build full-stack apps without ever opening a browser and all UI tests are pure unit tests with no browser runtime. Server returns a JSON tree of typed nodes; a thin TypeScript adapter renders it to DOM. Backend-agnostic — a .NET reference backend ships with the repo, but any language can produce the JSON contract.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|