@pure-ds/core 0.6.10 → 0.6.11
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/custom-elements.json +803 -16
- package/dist/types/pds.d.ts +1 -0
- package/dist/types/public/assets/js/pds-manager.d.ts +98 -1
- package/dist/types/public/assets/js/pds-manager.d.ts.map +1 -1
- package/dist/types/public/assets/js/pds.d.ts.map +1 -1
- package/dist/types/public/assets/pds/components/pds-live-converter.d.ts +8 -0
- package/dist/types/public/assets/pds/components/pds-live-converter.d.ts.map +1 -0
- package/dist/types/public/assets/pds/components/pds-live-importer.d.ts +2 -0
- package/dist/types/public/assets/pds/components/pds-live-importer.d.ts.map +1 -0
- package/dist/types/public/assets/pds/components/pds-live-template-canvas.d.ts +2 -0
- package/dist/types/public/assets/pds/components/pds-live-template-canvas.d.ts.map +1 -0
- package/dist/types/public/assets/pds/components/pds-omnibox.d.ts.map +1 -1
- package/dist/types/public/assets/pds/components/pds-scrollrow.d.ts +20 -0
- package/dist/types/public/assets/pds/components/pds-scrollrow.d.ts.map +1 -1
- package/dist/types/public/assets/pds/components/pds-toaster.d.ts +1 -1
- package/dist/types/public/assets/pds/components/pds-toaster.d.ts.map +1 -1
- package/dist/types/public/assets/pds/components/pds-treeview.d.ts +37 -0
- package/dist/types/public/assets/pds/components/pds-treeview.d.ts.map +1 -0
- package/dist/types/src/js/common/toast.d.ts +8 -0
- package/dist/types/src/js/common/toast.d.ts.map +1 -1
- package/dist/types/src/js/pds-core/pds-enhancers.d.ts.map +1 -1
- package/dist/types/src/js/pds-core/pds-generator.d.ts.map +1 -1
- package/dist/types/src/js/pds-core/pds-live.d.ts +2 -1
- package/dist/types/src/js/pds-core/pds-live.d.ts.map +1 -1
- package/dist/types/src/js/pds-live-manager/conversion-service.d.ts +66 -0
- package/dist/types/src/js/pds-live-manager/conversion-service.d.ts.map +1 -0
- package/dist/types/src/js/pds-live-manager/import-contract.d.ts +15 -0
- package/dist/types/src/js/pds-live-manager/import-contract.d.ts.map +1 -0
- package/dist/types/src/js/pds-live-manager/import-history-service.d.ts +32 -0
- package/dist/types/src/js/pds-live-manager/import-history-service.d.ts.map +1 -0
- package/dist/types/src/js/pds-live-manager/import-service.d.ts +21 -0
- package/dist/types/src/js/pds-live-manager/import-service.d.ts.map +1 -0
- package/dist/types/src/js/pds-live-manager/template-service.d.ts +17 -0
- package/dist/types/src/js/pds-live-manager/template-service.d.ts.map +1 -0
- package/dist/types/src/js/pds-manager.d.ts +4 -0
- package/dist/types/src/js/pds.d.ts.map +1 -1
- package/package.json +6 -2
- package/packages/pds-cli/README.md +51 -0
- package/packages/pds-cli/bin/pds-import.js +176 -0
- package/packages/pds-cli/bin/pds-static.js +15 -0
- package/packages/pds-cli/bin/postinstall.mjs +17 -8
- package/public/assets/js/app.js +15 -139
- package/public/assets/js/pds-manager.js +358 -255
- package/public/assets/js/pds.js +7 -7
- package/public/assets/pds/components/pds-live-converter.js +47 -0
- package/public/assets/pds/components/pds-live-edit.js +760 -43
- package/public/assets/pds/components/pds-live-importer.js +772 -0
- package/public/assets/pds/components/pds-live-template-canvas.js +171 -0
- package/public/assets/pds/components/pds-omnibox.js +136 -2
- package/public/assets/pds/components/pds-scrollrow.js +56 -1
- package/public/assets/pds/components/pds-toaster.js +50 -5
- package/public/assets/pds/components/pds-treeview.js +972 -0
- package/public/assets/pds/custom-elements.json +803 -16
- package/public/assets/pds/pds-css-complete.json +7 -2
- package/public/assets/pds/templates/commerce-scroll-explorer.html +115 -0
- package/public/assets/pds/templates/content-brand-showcase.html +110 -0
- package/public/assets/pds/templates/feedback-ops-dashboard.html +91 -0
- package/public/assets/pds/templates/release-readiness-radar.html +69 -0
- package/public/assets/pds/templates/support-command-center.html +92 -0
- package/public/assets/pds/templates/templates.json +53 -0
- package/public/assets/pds/templates/workspace-settings-lab.html +131 -0
- package/public/assets/pds/vscode-custom-data.json +54 -4
- package/readme.md +34 -0
- package/src/js/pds-core/pds-config.js +9 -9
- package/src/js/pds-core/pds-enhancers.js +146 -0
- package/src/js/pds-core/pds-generator.js +170 -29
- package/src/js/pds-core/pds-live.js +453 -13
- package/src/js/pds-live-manager/conversion-service.js +3136 -0
- package/src/js/pds-live-manager/import-contract.js +57 -0
- package/src/js/pds-live-manager/import-history-service.js +145 -0
- package/src/js/pds-live-manager/import-service.js +255 -0
- package/src/js/pds-live-manager/tailwind-conversion-rules.json +383 -0
- package/src/js/pds-live-manager/template-service.js +170 -0
- package/src/js/pds.d.ts +1 -0
- package/src/js/pds.js +35 -0
|
@@ -0,0 +1,772 @@
|
|
|
1
|
+
const COMPONENT_TAG = "pds-live-importer";
|
|
2
|
+
const PDS = globalThis.PDS;
|
|
3
|
+
|
|
4
|
+
const IMPORT_MODES = [
|
|
5
|
+
{ id: "convert-only", label: "Convert to PDS HTML only" },
|
|
6
|
+
{ id: "adopt-design-and-convert", label: "Adopt design language + convert" },
|
|
7
|
+
];
|
|
8
|
+
|
|
9
|
+
let managerPromise = null;
|
|
10
|
+
|
|
11
|
+
async function getManagerModule() {
|
|
12
|
+
if (managerPromise) return managerPromise;
|
|
13
|
+
managerPromise = (async () => {
|
|
14
|
+
const candidates = [
|
|
15
|
+
PDS?.currentConfig?.managerURL,
|
|
16
|
+
"../core/pds-manager.js",
|
|
17
|
+
"/assets/pds/core/pds-manager.js",
|
|
18
|
+
].filter(Boolean);
|
|
19
|
+
|
|
20
|
+
const attempted = new Set();
|
|
21
|
+
for (const candidate of candidates) {
|
|
22
|
+
try {
|
|
23
|
+
const resolved = new URL(candidate, import.meta.url).href;
|
|
24
|
+
if (attempted.has(resolved)) continue;
|
|
25
|
+
attempted.add(resolved);
|
|
26
|
+
const mod = await import(resolved);
|
|
27
|
+
if (mod && typeof mod === "object") return mod;
|
|
28
|
+
} catch (e) {}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
return null;
|
|
32
|
+
})();
|
|
33
|
+
return managerPromise;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function formatBytes(size) {
|
|
37
|
+
const value = Number(size);
|
|
38
|
+
if (!Number.isFinite(value) || value <= 0) return "0 B";
|
|
39
|
+
const units = ["B", "KB", "MB", "GB"];
|
|
40
|
+
const index = Math.min(Math.floor(Math.log(value) / Math.log(1024)), units.length - 1);
|
|
41
|
+
const scaled = value / 1024 ** index;
|
|
42
|
+
const precision = scaled >= 10 || index === 0 ? 0 : 1;
|
|
43
|
+
return `${scaled.toFixed(precision)} ${units[index]}`;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function formatDateTime(value) {
|
|
47
|
+
const date = value ? new Date(value) : null;
|
|
48
|
+
if (!date || Number.isNaN(date.getTime())) return "Unknown date";
|
|
49
|
+
return date.toLocaleString();
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function escapeHtml(value) {
|
|
53
|
+
return String(value ?? "")
|
|
54
|
+
.replace(/&/g, "&")
|
|
55
|
+
.replace(/</g, "<")
|
|
56
|
+
.replace(/>/g, ">")
|
|
57
|
+
.replace(/\"/g, """)
|
|
58
|
+
.replace(/'/g, "'");
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function inferSourceType(file, sources = []) {
|
|
62
|
+
const availableIds = new Set((sources || []).map((source) => source?.id).filter(Boolean));
|
|
63
|
+
const fallback =
|
|
64
|
+
(availableIds.has("brand-guidelines") && "brand-guidelines") ||
|
|
65
|
+
(availableIds.has("tailwind-html") && "tailwind-html") ||
|
|
66
|
+
(sources?.[0]?.id || "brand-guidelines");
|
|
67
|
+
|
|
68
|
+
if (!file) return fallback;
|
|
69
|
+
|
|
70
|
+
const name = String(file.name || "").toLowerCase();
|
|
71
|
+
const ext = name.includes(".") ? name.split(".").pop() : "";
|
|
72
|
+
const mime = String(file.type || "").toLowerCase();
|
|
73
|
+
|
|
74
|
+
const isHtml = ext === "html" || ext === "htm" || mime.includes("html");
|
|
75
|
+
if (isHtml && availableIds.has("tailwind-html")) return "tailwind-html";
|
|
76
|
+
|
|
77
|
+
if (availableIds.has("brand-guidelines")) return "brand-guidelines";
|
|
78
|
+
if (availableIds.has("tailwind-html")) return "tailwind-html";
|
|
79
|
+
|
|
80
|
+
return fallback;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function normalizeImportMode(value) {
|
|
84
|
+
const next = String(value || "").trim().toLowerCase();
|
|
85
|
+
return IMPORT_MODES.some((mode) => mode.id === next) ? next : "convert-only";
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function getImportModeLabel(value) {
|
|
89
|
+
const mode = IMPORT_MODES.find((item) => item.id === normalizeImportMode(value));
|
|
90
|
+
return mode?.label || IMPORT_MODES[0].label;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
class PdsLiveImporter extends HTMLElement {
|
|
94
|
+
constructor() {
|
|
95
|
+
super();
|
|
96
|
+
this._sources = [];
|
|
97
|
+
this._selectedFile = null;
|
|
98
|
+
this._selectedText = "";
|
|
99
|
+
this._selectedSourceType = "";
|
|
100
|
+
this._selectedImportMode = "convert-only";
|
|
101
|
+
this._isImporting = false;
|
|
102
|
+
this._history = [];
|
|
103
|
+
this._isHistoryLoading = false;
|
|
104
|
+
this._historyDialog = null;
|
|
105
|
+
this._activeHistoryDialogEntry = null;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
connectedCallback() {
|
|
109
|
+
this._render();
|
|
110
|
+
this._loadSources();
|
|
111
|
+
this._loadHistory();
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
_render() {
|
|
115
|
+
this.className = "card surface-subtle stack-sm";
|
|
116
|
+
this.innerHTML = `
|
|
117
|
+
<label class="stack-xs">
|
|
118
|
+
<span>File</span>
|
|
119
|
+
<pds-upload class="pds-live-import-upload" accept=".html,.htm,.txt,.md,.json,.css,.js,.ts,.tsx,.jsx" max-files="1"></pds-upload>
|
|
120
|
+
</label>
|
|
121
|
+
<label class="stack-xs">
|
|
122
|
+
<span>Import mode</span>
|
|
123
|
+
<select class="pds-live-import-mode">
|
|
124
|
+
${IMPORT_MODES.map((mode) => `<option value="${mode.id}">${escapeHtml(mode.label)}</option>`).join("")}
|
|
125
|
+
</select>
|
|
126
|
+
</label>
|
|
127
|
+
<div class="flex gap-sm justify-end">
|
|
128
|
+
<button type="button" class="btn-secondary btn-sm pds-live-import-run" disabled>Re-import</button>
|
|
129
|
+
</div>
|
|
130
|
+
<section class="card surface-base stack-xs pds-live-import-history">
|
|
131
|
+
<div class="flex items-center justify-between gap-sm">
|
|
132
|
+
<strong>Import History</strong>
|
|
133
|
+
<div class="flex gap-xs">
|
|
134
|
+
<button type="button" class="btn-outline btn-sm pds-live-history-refresh">Refresh</button>
|
|
135
|
+
<button type="button" class="btn-outline btn-sm pds-live-history-clear">Clear</button>
|
|
136
|
+
</div>
|
|
137
|
+
</div>
|
|
138
|
+
<div class="stack-xs pds-live-history-list"></div>
|
|
139
|
+
</section>
|
|
140
|
+
`;
|
|
141
|
+
|
|
142
|
+
this.querySelector(".pds-live-import-upload")?.addEventListener("files-changed", async (event) => {
|
|
143
|
+
const file = event?.detail?.files?.[0] || null;
|
|
144
|
+
await this._setSelectedFile(file);
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
this.querySelector(".pds-live-import-run")?.addEventListener("click", () => {
|
|
148
|
+
this._runImport();
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
this.querySelector(".pds-live-import-mode")?.addEventListener("change", (event) => {
|
|
152
|
+
this._selectedImportMode = normalizeImportMode(event?.currentTarget?.value);
|
|
153
|
+
this._updateSelectionUI();
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
this.querySelector(".pds-live-history-refresh")?.addEventListener("click", () => {
|
|
157
|
+
this._loadHistory();
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
this.querySelector(".pds-live-history-clear")?.addEventListener("click", async () => {
|
|
161
|
+
await this._clearHistory();
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
this._updateSelectionUI();
|
|
165
|
+
this._renderHistory();
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
async _toast(message, type = "information", options = {}) {
|
|
169
|
+
if (!message) return;
|
|
170
|
+
if (typeof PDS?.toast === "function") {
|
|
171
|
+
await PDS.toast(String(message), { type, persistent: true, ...(options || {}) });
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
console.info(message);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
_openLatestHistoryMetadata(options = {}) {
|
|
178
|
+
const requestedFileName = String(options?.fileName || "");
|
|
179
|
+
const requestedSourceType = String(options?.sourceType || "");
|
|
180
|
+
const requestedImportMode = normalizeImportMode(options?.importMode);
|
|
181
|
+
|
|
182
|
+
document.dispatchEvent(
|
|
183
|
+
new CustomEvent("pds:live-edit:enable", {
|
|
184
|
+
bubbles: true,
|
|
185
|
+
composed: true,
|
|
186
|
+
})
|
|
187
|
+
);
|
|
188
|
+
|
|
189
|
+
let attempts = 0;
|
|
190
|
+
const maxAttempts = 12;
|
|
191
|
+
const tryOpen = () => {
|
|
192
|
+
attempts += 1;
|
|
193
|
+
const liveEditHost = document.querySelector("pds-live-edit");
|
|
194
|
+
if (liveEditHost && typeof liveEditHost.openImportDetailsFromToast === "function") {
|
|
195
|
+
liveEditHost.openImportDetailsFromToast({
|
|
196
|
+
fileName: requestedFileName,
|
|
197
|
+
sourceType: requestedSourceType,
|
|
198
|
+
importMode: requestedImportMode,
|
|
199
|
+
});
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
if (attempts < maxAttempts) {
|
|
203
|
+
setTimeout(tryOpen, 100);
|
|
204
|
+
}
|
|
205
|
+
};
|
|
206
|
+
|
|
207
|
+
setTimeout(tryOpen, 0);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
_ensureHistoryDialog() {
|
|
211
|
+
if (this._historyDialog?.isConnected) return this._historyDialog;
|
|
212
|
+
|
|
213
|
+
const dialog = document.createElement("dialog");
|
|
214
|
+
dialog.className = "card surface-elevated stack-sm";
|
|
215
|
+
dialog.setAttribute("aria-label", "Import details");
|
|
216
|
+
|
|
217
|
+
const title = document.createElement("h4");
|
|
218
|
+
title.textContent = "Import Details";
|
|
219
|
+
|
|
220
|
+
const content = document.createElement("div");
|
|
221
|
+
content.className = "stack-sm";
|
|
222
|
+
content.dataset.role = "history-details-content";
|
|
223
|
+
|
|
224
|
+
const footer = document.createElement("div");
|
|
225
|
+
footer.className = "flex gap-sm justify-end";
|
|
226
|
+
|
|
227
|
+
const copyBtn = document.createElement("button");
|
|
228
|
+
copyBtn.type = "button";
|
|
229
|
+
copyBtn.className = "btn-outline btn-sm icon-only";
|
|
230
|
+
copyBtn.setAttribute("aria-label", "Copy to clipboard");
|
|
231
|
+
const copyIcon = document.createElement("pds-icon");
|
|
232
|
+
copyIcon.setAttribute("icon", "copy");
|
|
233
|
+
copyIcon.setAttribute("size", "sm");
|
|
234
|
+
copyBtn.appendChild(copyIcon);
|
|
235
|
+
copyBtn.addEventListener("click", async () => {
|
|
236
|
+
await this._copyActiveHistoryToClipboard();
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
const closeBtn = document.createElement("button");
|
|
240
|
+
closeBtn.type = "button";
|
|
241
|
+
closeBtn.className = "btn-outline btn-sm";
|
|
242
|
+
closeBtn.textContent = "Close";
|
|
243
|
+
closeBtn.addEventListener("click", () => dialog.close());
|
|
244
|
+
|
|
245
|
+
footer.appendChild(copyBtn);
|
|
246
|
+
footer.appendChild(closeBtn);
|
|
247
|
+
dialog.append(title, content, footer);
|
|
248
|
+
this.appendChild(dialog);
|
|
249
|
+
this._historyDialog = dialog;
|
|
250
|
+
return dialog;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
_buildHistoryDetailsHtml(entry) {
|
|
254
|
+
const confidence = Number.isFinite(Number(entry?.confidence))
|
|
255
|
+
? `${Math.round(Number(entry.confidence) * 100)}%`
|
|
256
|
+
: "-";
|
|
257
|
+
const issueCount = Array.isArray(entry?.issues) ? entry.issues.length : 0;
|
|
258
|
+
const notes = Array.isArray(entry?.notes) ? entry.notes : [];
|
|
259
|
+
const coverage = entry?.coverage || {};
|
|
260
|
+
const unknownTokens = Array.isArray(entry?.unknownTailwindTokens)
|
|
261
|
+
? entry.unknownTailwindTokens
|
|
262
|
+
: [];
|
|
263
|
+
const notesHtml = notes.length
|
|
264
|
+
? `<ul class="stack-xs">${notes
|
|
265
|
+
.map((note) => `<li>${escapeHtml(note)}</li>`)
|
|
266
|
+
.join("")}</ul>`
|
|
267
|
+
: "none";
|
|
268
|
+
const issuesHtml = issueCount
|
|
269
|
+
? `<ul class="stack-xs">${entry.issues
|
|
270
|
+
.map(
|
|
271
|
+
(issue) =>
|
|
272
|
+
`<li><strong>${escapeHtml(issue?.severity || "info")}</strong>: ${escapeHtml(issue?.message || "")}</li>`
|
|
273
|
+
)
|
|
274
|
+
.join("")}</ul>`
|
|
275
|
+
: "none";
|
|
276
|
+
const unknownHtml = unknownTokens.length
|
|
277
|
+
? `<code>${escapeHtml(unknownTokens.join(", "))}</code>`
|
|
278
|
+
: "none";
|
|
279
|
+
|
|
280
|
+
return `
|
|
281
|
+
<table class="table-bordered table-compact">
|
|
282
|
+
<tbody>
|
|
283
|
+
<tr><th scope="row">File</th><td>${escapeHtml(entry?.fileName || "(untitled import)")}</td></tr>
|
|
284
|
+
<tr><th scope="row">Source</th><td>${escapeHtml(entry?.sourceType || "unknown")}</td></tr>
|
|
285
|
+
<tr><th scope="row">Mode</th><td>${escapeHtml(getImportModeLabel(entry?.importMode || entry?.meta?.importMode))}</td></tr>
|
|
286
|
+
<tr><th scope="row">Date</th><td>${escapeHtml(formatDateTime(entry?.createdAt || entry?.createdAtIso))}</td></tr>
|
|
287
|
+
<tr><th scope="row">Confidence</th><td>${confidence}</td></tr>
|
|
288
|
+
<tr><th scope="row">Tailwind</th><td>${Number(coverage.tailwind ?? 0)}</td></tr>
|
|
289
|
+
<tr><th scope="row">Mapped</th><td>${Number(coverage.mapped ?? 0)}</td></tr>
|
|
290
|
+
<tr><th scope="row">Ignored</th><td>${Number(coverage.ignored ?? 0)}</td></tr>
|
|
291
|
+
<tr><th scope="row">Policy Skipped</th><td>${Number(coverage.policySkipped ?? 0)}</td></tr>
|
|
292
|
+
<tr><th scope="row">Unknown</th><td>${Number(coverage.unknown ?? 0)}</td></tr>
|
|
293
|
+
<tr><th scope="row">Imported Styles</th><td>${Number(coverage.importedStyles ?? 0)}</td></tr>
|
|
294
|
+
<tr><th scope="row">Unknown Tokens</th><td>${unknownHtml}</td></tr>
|
|
295
|
+
<tr><th scope="row">Notes</th><td>${notesHtml}</td></tr>
|
|
296
|
+
<tr><th scope="row">Issues</th><td>${issuesHtml}</td></tr>
|
|
297
|
+
</tbody>
|
|
298
|
+
</table>
|
|
299
|
+
<div class="flex gap-sm justify-end">
|
|
300
|
+
${String(entry?.convertedHtml || "").trim() ? '<button type="button" class="btn-secondary btn-sm pds-live-history-apply" data-history-id="' + Number(entry?.id || 0) + '">Apply stored result</button>' : ""}
|
|
301
|
+
<button type="button" class="btn-outline btn-sm pds-live-history-reimport" data-history-id="${Number(entry?.id || 0)}">Re-import input</button>
|
|
302
|
+
</div>
|
|
303
|
+
`;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
_openHistoryDetailsDialog(historyId) {
|
|
307
|
+
const entry = this._getHistoryEntry(historyId);
|
|
308
|
+
if (!entry) return;
|
|
309
|
+
this._activeHistoryDialogEntry = entry;
|
|
310
|
+
|
|
311
|
+
const dialog = this._ensureHistoryDialog();
|
|
312
|
+
const content = dialog.querySelector('[data-role="history-details-content"]');
|
|
313
|
+
if (!content) return;
|
|
314
|
+
|
|
315
|
+
content.innerHTML = this._buildHistoryDetailsHtml(entry);
|
|
316
|
+
|
|
317
|
+
content.querySelector(".pds-live-history-apply")?.addEventListener("click", (event) => {
|
|
318
|
+
const id = Number(event.currentTarget?.getAttribute("data-history-id"));
|
|
319
|
+
this._applyHistoryResult(id);
|
|
320
|
+
dialog.close();
|
|
321
|
+
});
|
|
322
|
+
|
|
323
|
+
content.querySelector(".pds-live-history-reimport")?.addEventListener("click", async (event) => {
|
|
324
|
+
const id = Number(event.currentTarget?.getAttribute("data-history-id"));
|
|
325
|
+
await this._reimportHistoryItem(id);
|
|
326
|
+
dialog.close();
|
|
327
|
+
});
|
|
328
|
+
|
|
329
|
+
if (!dialog.open) dialog.showModal();
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
async _copyActiveHistoryToClipboard() {
|
|
333
|
+
const entry = this._activeHistoryDialogEntry;
|
|
334
|
+
if (!entry) return;
|
|
335
|
+
|
|
336
|
+
const text = String(
|
|
337
|
+
entry?.convertedHtml || entry?.resultSnapshot?.template?.html || ""
|
|
338
|
+
).trim();
|
|
339
|
+
if (!text) {
|
|
340
|
+
await this._toast("No converted PDS HTML available to copy", "warning");
|
|
341
|
+
return;
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
try {
|
|
345
|
+
if (navigator?.clipboard?.writeText) {
|
|
346
|
+
await navigator.clipboard.writeText(text);
|
|
347
|
+
} else {
|
|
348
|
+
const area = document.createElement("textarea");
|
|
349
|
+
area.value = text;
|
|
350
|
+
area.setAttribute("readonly", "");
|
|
351
|
+
area.style.position = "fixed";
|
|
352
|
+
area.style.opacity = "0";
|
|
353
|
+
document.body.appendChild(area);
|
|
354
|
+
area.select();
|
|
355
|
+
document.execCommand("copy");
|
|
356
|
+
area.remove();
|
|
357
|
+
}
|
|
358
|
+
await this._toast("Copied converted PDS HTML to clipboard", "success");
|
|
359
|
+
} catch (error) {
|
|
360
|
+
await this._toast("Failed to copy converted PDS HTML", "error");
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
openHistoryDetailsByMeta(options = {}) {
|
|
365
|
+
const requestedFileName = String(options?.fileName || "");
|
|
366
|
+
const requestedSourceType = String(options?.sourceType || "");
|
|
367
|
+
const requestedImportMode = normalizeImportMode(options?.importMode);
|
|
368
|
+
|
|
369
|
+
let entry = null;
|
|
370
|
+
if (requestedFileName) {
|
|
371
|
+
entry = this._history.find((item) => {
|
|
372
|
+
const sameFile = String(item?.fileName || "") === requestedFileName;
|
|
373
|
+
const sameSource = !requestedSourceType || String(item?.sourceType || "") === requestedSourceType;
|
|
374
|
+
const sameMode =
|
|
375
|
+
!requestedImportMode ||
|
|
376
|
+
normalizeImportMode(item?.importMode || item?.meta?.importMode) === requestedImportMode;
|
|
377
|
+
return sameFile && sameSource && sameMode;
|
|
378
|
+
}) || null;
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
if (!entry) {
|
|
382
|
+
entry = this._history[0] || null;
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
if (entry?.id != null) {
|
|
386
|
+
this._openHistoryDetailsDialog(Number(entry.id));
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
_renderHistory() {
|
|
391
|
+
const list = this.querySelector(".pds-live-history-list");
|
|
392
|
+
if (!list) return;
|
|
393
|
+
|
|
394
|
+
if (this._isHistoryLoading) {
|
|
395
|
+
list.innerHTML = `<p class="text-muted">Loading import history...</p>`;
|
|
396
|
+
return;
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
if (!Array.isArray(this._history) || this._history.length === 0) {
|
|
400
|
+
list.innerHTML = `<p class="text-muted">No imports yet.</p>`;
|
|
401
|
+
return;
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
const rows = this._history
|
|
405
|
+
.map((entry) => {
|
|
406
|
+
const confidence = Number.isFinite(Number(entry?.confidence))
|
|
407
|
+
? `${Math.round(Number(entry.confidence) * 100)}%`
|
|
408
|
+
: "-";
|
|
409
|
+
const issueCount = Array.isArray(entry?.issues) ? entry.issues.length : 0;
|
|
410
|
+
const coverage = entry?.coverage || {};
|
|
411
|
+
const failedCount = Number(coverage.unknown ?? 0);
|
|
412
|
+
const mappedCount = Number(coverage.mapped ?? 0);
|
|
413
|
+
const totalTailwind = Number(coverage.tailwind ?? 0);
|
|
414
|
+
const statusIssueText = `${failedCount} failed / ${issueCount} issues`;
|
|
415
|
+
const fileLabel = `${entry?.fileName || "(untitled import)"} (${entry?.sourceType || "unknown"})`;
|
|
416
|
+
const importMode = getImportModeLabel(entry?.importMode || entry?.meta?.importMode);
|
|
417
|
+
return `
|
|
418
|
+
<tr data-history-id="${Number(entry?.id || 0)}" data-history-file-name="${escapeHtml(entry?.fileName || "")}" data-history-source-type="${escapeHtml(entry?.sourceType || "")}">
|
|
419
|
+
<td>${escapeHtml(formatDateTime(entry?.createdAt || entry?.createdAtIso))}</td>
|
|
420
|
+
<td>${escapeHtml(fileLabel)}</td>
|
|
421
|
+
<td class="flex flex-wrap gap-xs items-center">
|
|
422
|
+
<span class="badge badge-outline badge-info badge-sm">${escapeHtml(importMode)}</span>
|
|
423
|
+
<span class="badge badge-outline badge-success badge-sm">${escapeHtml(confidence)} success</span>
|
|
424
|
+
<span class="badge badge-outline badge-warning badge-sm">${escapeHtml(statusIssueText)}</span>
|
|
425
|
+
<span class="badge badge-outline badge-info badge-sm">${mappedCount} of ${totalTailwind} mapped</span>
|
|
426
|
+
</td>
|
|
427
|
+
<td>
|
|
428
|
+
<button type="button" class="btn-outline btn-sm icon-only pds-live-history-details" data-history-id="${Number(entry?.id || 0)}" aria-label="Details" title="Details">
|
|
429
|
+
<pds-icon icon="info" size="sm"></pds-icon>
|
|
430
|
+
</button>
|
|
431
|
+
</td>
|
|
432
|
+
</tr>
|
|
433
|
+
`;
|
|
434
|
+
})
|
|
435
|
+
.join("");
|
|
436
|
+
|
|
437
|
+
list.innerHTML = `
|
|
438
|
+
<table class="table-bordered table-compact">
|
|
439
|
+
<thead>
|
|
440
|
+
<tr>
|
|
441
|
+
<th>Date</th>
|
|
442
|
+
<th>File</th>
|
|
443
|
+
<th>Status</th>
|
|
444
|
+
<th>Info</th>
|
|
445
|
+
</tr>
|
|
446
|
+
</thead>
|
|
447
|
+
<tbody>
|
|
448
|
+
${rows}
|
|
449
|
+
</tbody>
|
|
450
|
+
</table>
|
|
451
|
+
`;
|
|
452
|
+
|
|
453
|
+
list.querySelectorAll(".pds-live-history-details").forEach((button) => {
|
|
454
|
+
button.addEventListener("click", (event) => {
|
|
455
|
+
const historyId = Number(event.currentTarget?.getAttribute("data-history-id"));
|
|
456
|
+
this._openHistoryDetailsDialog(historyId);
|
|
457
|
+
});
|
|
458
|
+
});
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
async _loadHistory() {
|
|
462
|
+
this._isHistoryLoading = true;
|
|
463
|
+
this._renderHistory();
|
|
464
|
+
|
|
465
|
+
try {
|
|
466
|
+
const manager = await getManagerModule();
|
|
467
|
+
if (typeof manager?.listLiveImportHistory === "function") {
|
|
468
|
+
this._history = await manager.listLiveImportHistory({ limit: 30 });
|
|
469
|
+
} else {
|
|
470
|
+
this._history = [];
|
|
471
|
+
}
|
|
472
|
+
} catch (error) {
|
|
473
|
+
console.warn("Failed to load import history", error);
|
|
474
|
+
this._history = [];
|
|
475
|
+
} finally {
|
|
476
|
+
this._isHistoryLoading = false;
|
|
477
|
+
this._renderHistory();
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
async _clearHistory() {
|
|
482
|
+
const manager = await getManagerModule();
|
|
483
|
+
if (typeof manager?.clearLiveImportHistory !== "function") return;
|
|
484
|
+
|
|
485
|
+
let proceed = true;
|
|
486
|
+
if (typeof PDS?.ask === "function") {
|
|
487
|
+
const answer = await PDS.ask("Clear import history?", { type: "confirm" });
|
|
488
|
+
proceed = Boolean(answer);
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
if (!proceed) return;
|
|
492
|
+
|
|
493
|
+
try {
|
|
494
|
+
await manager.clearLiveImportHistory();
|
|
495
|
+
this._history = [];
|
|
496
|
+
this._renderHistory();
|
|
497
|
+
} catch (error) {
|
|
498
|
+
console.warn("Failed to clear import history", error);
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
_getHistoryEntry(historyId) {
|
|
503
|
+
return this._history.find((entry) => Number(entry?.id) === Number(historyId)) || null;
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
_applyHistoryResult(historyId) {
|
|
507
|
+
const entry = this._getHistoryEntry(historyId);
|
|
508
|
+
if (!entry?.resultSnapshot) return;
|
|
509
|
+
|
|
510
|
+
this.dispatchEvent(
|
|
511
|
+
new CustomEvent("pds:live-import:result", {
|
|
512
|
+
bubbles: true,
|
|
513
|
+
composed: true,
|
|
514
|
+
detail: {
|
|
515
|
+
sourceType: entry.sourceType || "unknown",
|
|
516
|
+
importMode: normalizeImportMode(entry.importMode || entry?.meta?.importMode),
|
|
517
|
+
result: entry.resultSnapshot,
|
|
518
|
+
file: {
|
|
519
|
+
name: entry.fileName || "history-import",
|
|
520
|
+
size: Number(entry.fileSize) || 0,
|
|
521
|
+
type: entry.mimeType || "",
|
|
522
|
+
},
|
|
523
|
+
},
|
|
524
|
+
})
|
|
525
|
+
);
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
async _reimportHistoryItem(historyId) {
|
|
529
|
+
const entry = this._getHistoryEntry(historyId);
|
|
530
|
+
if (!entry) return;
|
|
531
|
+
|
|
532
|
+
this._selectedFile = {
|
|
533
|
+
name: entry.fileName || "history-import",
|
|
534
|
+
size: Number(entry.fileSize) || 0,
|
|
535
|
+
type: entry.mimeType || "",
|
|
536
|
+
};
|
|
537
|
+
this._selectedText = String(entry.fileContents || "");
|
|
538
|
+
this._selectedSourceType = entry.sourceType || "brand-guidelines";
|
|
539
|
+
this._selectedImportMode = normalizeImportMode(entry.importMode || entry?.meta?.importMode);
|
|
540
|
+
this._updateSelectionUI();
|
|
541
|
+
await this._runImport({ autoTriggered: false });
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
async _persistImportHistory({ sourceType, importMode, result }) {
|
|
545
|
+
const manager = await getManagerModule();
|
|
546
|
+
if (typeof manager?.saveLiveImportHistory !== "function") return;
|
|
547
|
+
|
|
548
|
+
const meta = result?.meta || {};
|
|
549
|
+
await manager.saveLiveImportHistory({
|
|
550
|
+
createdAt: Date.now(),
|
|
551
|
+
sourceType: sourceType || "unknown",
|
|
552
|
+
importMode: normalizeImportMode(importMode || meta?.importMode),
|
|
553
|
+
source: result?.source || sourceType || "unknown",
|
|
554
|
+
type: result?.type || sourceType || "unknown",
|
|
555
|
+
fileName: this._selectedFile?.name || "",
|
|
556
|
+
fileSize: Number(this._selectedFile?.size) || 0,
|
|
557
|
+
mimeType: this._selectedFile?.type || "",
|
|
558
|
+
fileContents: this._selectedText,
|
|
559
|
+
convertedHtml: result?.template?.html || "",
|
|
560
|
+
confidence: Number(result?.confidence) || 0,
|
|
561
|
+
notes: Array.isArray(meta?.notes) ? meta.notes : [],
|
|
562
|
+
issues: Array.isArray(result?.issues) ? result.issues : [],
|
|
563
|
+
coverage: meta?.coverage || {},
|
|
564
|
+
unknownTailwindTokens: Array.isArray(meta?.unknownTailwindTokens)
|
|
565
|
+
? meta.unknownTailwindTokens
|
|
566
|
+
: [],
|
|
567
|
+
appliedRules: Array.isArray(meta?.appliedRules) ? meta.appliedRules : [],
|
|
568
|
+
importStyleSheetInjected: Boolean(meta?.importStyleSheetInjected),
|
|
569
|
+
templateName: result?.template?.name || "",
|
|
570
|
+
designPatch: result?.designPatch || {},
|
|
571
|
+
meta,
|
|
572
|
+
resultSnapshot: {
|
|
573
|
+
source: result?.source || sourceType || "unknown",
|
|
574
|
+
type: result?.type || sourceType || "unknown",
|
|
575
|
+
importMode: normalizeImportMode(importMode || meta?.importMode),
|
|
576
|
+
confidence: Number(result?.confidence) || 0,
|
|
577
|
+
issues: Array.isArray(result?.issues) ? result.issues : [],
|
|
578
|
+
template: result?.template || null,
|
|
579
|
+
designPatch: result?.designPatch || null,
|
|
580
|
+
meta,
|
|
581
|
+
},
|
|
582
|
+
});
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
_buildDiagnosticsMessage(result, sourceType, fileName) {
|
|
586
|
+
const confidence = typeof result?.confidence === "number"
|
|
587
|
+
? `${Math.round(result.confidence * 100)}%`
|
|
588
|
+
: "-";
|
|
589
|
+
const issues = Array.isArray(result?.issues) ? result.issues : [];
|
|
590
|
+
const coverage = result?.meta?.coverage || {};
|
|
591
|
+
|
|
592
|
+
return [
|
|
593
|
+
`Import complete: ${fileName || "(no file)"}`,
|
|
594
|
+
`source=${sourceType || "unknown"}`,
|
|
595
|
+
`mode=${normalizeImportMode(result?.meta?.importMode || this._selectedImportMode)}`,
|
|
596
|
+
`confidence=${confidence}`,
|
|
597
|
+
`issues=${issues.length}`,
|
|
598
|
+
`mapped=${coverage.mapped ?? 0}/${coverage.tailwind ?? 0}`,
|
|
599
|
+
`report=Open Import History > Metadata table`,
|
|
600
|
+
].join("\n");
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
_buildDiagnosticsToastHtml(result, sourceType, fileName, importMode) {
|
|
604
|
+
const confidencePct = typeof result?.confidence === "number"
|
|
605
|
+
? Math.round(result.confidence * 100)
|
|
606
|
+
: 0;
|
|
607
|
+
const issues = Array.isArray(result?.issues) ? result.issues : [];
|
|
608
|
+
const coverage = result?.meta?.coverage || {};
|
|
609
|
+
const failedCount = Number(coverage.unknown ?? 0);
|
|
610
|
+
const totalTailwind = Number(coverage.tailwind ?? 0);
|
|
611
|
+
const mappedCount = Number(coverage.mapped ?? 0);
|
|
612
|
+
const fileLabel = `${fileName || "(no file)"} (${sourceType || result?.type || "unknown"})`;
|
|
613
|
+
const issueText = `${failedCount} failed / ${issues.length} issues`;
|
|
614
|
+
const modeLabel = getImportModeLabel(importMode || result?.meta?.importMode);
|
|
615
|
+
|
|
616
|
+
return `
|
|
617
|
+
<table class="table-bordered table-compact">
|
|
618
|
+
<tbody>
|
|
619
|
+
<tr><th scope="row">File</th><td>${escapeHtml(fileLabel)}</td></tr>
|
|
620
|
+
<tr><th scope="row">Mode</th><td>${escapeHtml(modeLabel)}</td></tr>
|
|
621
|
+
<tr>
|
|
622
|
+
<th scope="row">Status</th>
|
|
623
|
+
<td class="flex gap-xs items-center">
|
|
624
|
+
<span class="badge badge-outline badge-success badge-sm">${confidencePct}% success</span>
|
|
625
|
+
<span class="badge badge-outline badge-warning badge-sm">${escapeHtml(issueText)}</span>
|
|
626
|
+
<span class="badge badge-outline badge-info badge-sm">${mappedCount} of ${totalTailwind} mapped</span>
|
|
627
|
+
</td>
|
|
628
|
+
</tr>
|
|
629
|
+
</tbody>
|
|
630
|
+
</table>
|
|
631
|
+
`;
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
async _loadSources() {
|
|
635
|
+
const manager = await getManagerModule();
|
|
636
|
+
|
|
637
|
+
this._sources =
|
|
638
|
+
typeof manager?.getLiveImportSources === "function"
|
|
639
|
+
? manager.getLiveImportSources()
|
|
640
|
+
: [
|
|
641
|
+
{ id: "tailwind-html", name: "Tailwind HTML" },
|
|
642
|
+
{ id: "brand-guidelines", name: "Brand Guidelines" },
|
|
643
|
+
];
|
|
644
|
+
|
|
645
|
+
this._sources = (this._sources || []).filter((source) => source.id !== "template");
|
|
646
|
+
|
|
647
|
+
if (this._selectedFile) {
|
|
648
|
+
this._selectedSourceType = inferSourceType(this._selectedFile, this._sources);
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
this._updateSelectionUI();
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
async _setSelectedFile(file) {
|
|
655
|
+
if (!file) {
|
|
656
|
+
this._selectedFile = null;
|
|
657
|
+
this._selectedText = "";
|
|
658
|
+
this._selectedSourceType = "";
|
|
659
|
+
this._updateSelectionUI();
|
|
660
|
+
return;
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
try {
|
|
664
|
+
const text = await file.text();
|
|
665
|
+
this._selectedFile = file;
|
|
666
|
+
this._selectedText = text;
|
|
667
|
+
this._selectedSourceType = inferSourceType(file, this._sources);
|
|
668
|
+
this._updateSelectionUI();
|
|
669
|
+
await this._runImport({ autoTriggered: true });
|
|
670
|
+
} catch (error) {
|
|
671
|
+
await this._toast(`Import failed\nreason=Could not read selected file\nerror=${error?.message || "Unknown error"}`, "error");
|
|
672
|
+
this._selectedFile = null;
|
|
673
|
+
this._selectedText = "";
|
|
674
|
+
this._selectedSourceType = "";
|
|
675
|
+
this._updateSelectionUI();
|
|
676
|
+
}
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
_updateSelectionUI() {
|
|
680
|
+
const runButton = this.querySelector(".pds-live-import-run");
|
|
681
|
+
const importMode = this.querySelector(".pds-live-import-mode");
|
|
682
|
+
|
|
683
|
+
if (importMode) {
|
|
684
|
+
importMode.value = normalizeImportMode(this._selectedImportMode);
|
|
685
|
+
importMode.disabled = this._isImporting;
|
|
686
|
+
}
|
|
687
|
+
|
|
688
|
+
if (!this._selectedFile) {
|
|
689
|
+
if (runButton) runButton.disabled = true;
|
|
690
|
+
return;
|
|
691
|
+
}
|
|
692
|
+
if (runButton) runButton.disabled = !this._selectedText.trim() || this._isImporting;
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
async _runImport(_options = {}) {
|
|
696
|
+
if (this._isImporting) return;
|
|
697
|
+
|
|
698
|
+
const manager = await getManagerModule();
|
|
699
|
+
if (typeof manager?.runLiveImport !== "function") {
|
|
700
|
+
await this._toast("Import failed\nreason=Import service unavailable", "error");
|
|
701
|
+
return;
|
|
702
|
+
}
|
|
703
|
+
|
|
704
|
+
if (!this._selectedText.trim()) return;
|
|
705
|
+
|
|
706
|
+
const runButton = this.querySelector(".pds-live-import-run");
|
|
707
|
+
|
|
708
|
+
this._isImporting = true;
|
|
709
|
+
let result = null;
|
|
710
|
+
let sourceType = this._selectedSourceType || inferSourceType(this._selectedFile, this._sources);
|
|
711
|
+
let importMode = normalizeImportMode(this._selectedImportMode);
|
|
712
|
+
|
|
713
|
+
runButton?.classList.add("btn-working");
|
|
714
|
+
if (runButton) runButton.disabled = true;
|
|
715
|
+
|
|
716
|
+
try {
|
|
717
|
+
const input = this._selectedText;
|
|
718
|
+
const config = PDS?.currentConfig?.design || PDS?.currentConfig || null;
|
|
719
|
+
result = await manager.runLiveImport({ sourceType, importMode, input, config });
|
|
720
|
+
|
|
721
|
+
await this._persistImportHistory({ sourceType, importMode, result });
|
|
722
|
+
await this._loadHistory();
|
|
723
|
+
|
|
724
|
+
this.dispatchEvent(
|
|
725
|
+
new CustomEvent("pds:live-import:result", {
|
|
726
|
+
bubbles: true,
|
|
727
|
+
composed: true,
|
|
728
|
+
detail: { sourceType, importMode, result, file: this._selectedFile },
|
|
729
|
+
})
|
|
730
|
+
);
|
|
731
|
+
} catch (error) {
|
|
732
|
+
await this._toast(
|
|
733
|
+
[
|
|
734
|
+
`Import failed: ${this._selectedFile?.name || "selected file"}`,
|
|
735
|
+
`source=${sourceType || "unknown"}`,
|
|
736
|
+
`mode=${importMode}`,
|
|
737
|
+
`error=${error?.message || "Unknown error"}`,
|
|
738
|
+
].join("\n"),
|
|
739
|
+
"error"
|
|
740
|
+
);
|
|
741
|
+
} finally {
|
|
742
|
+
if (result) {
|
|
743
|
+
const hasIssues = Array.isArray(result?.issues) && result.issues.length > 0;
|
|
744
|
+
const validationBlocked = Boolean(result?.meta?.validationBlocked || result?.meta?.validation?.ok === false);
|
|
745
|
+
const type = validationBlocked ? "error" : hasIssues ? "warning" : "success";
|
|
746
|
+
await this._toast(
|
|
747
|
+
this._buildDiagnosticsToastHtml(result, sourceType, this._selectedFile?.name, importMode),
|
|
748
|
+
type,
|
|
749
|
+
{
|
|
750
|
+
html: true,
|
|
751
|
+
action: {
|
|
752
|
+
label: "Open details",
|
|
753
|
+
icon: "caret-right",
|
|
754
|
+
onClick: () =>
|
|
755
|
+
this._openLatestHistoryMetadata({
|
|
756
|
+
fileName: this._selectedFile?.name || "",
|
|
757
|
+
sourceType,
|
|
758
|
+
importMode,
|
|
759
|
+
}),
|
|
760
|
+
dismissOnClick: false,
|
|
761
|
+
},
|
|
762
|
+
}
|
|
763
|
+
);
|
|
764
|
+
}
|
|
765
|
+
runButton?.classList.remove("btn-working");
|
|
766
|
+
this._isImporting = false;
|
|
767
|
+
this._updateSelectionUI();
|
|
768
|
+
}
|
|
769
|
+
}
|
|
770
|
+
}
|
|
771
|
+
|
|
772
|
+
customElements.define(COMPONENT_TAG, PdsLiveImporter);
|