@sweberdev/witness 0.0.0-stage → 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.
- package/LICENSE +21 -0
- package/README.md +21 -2
- package/dist/ai-sdk.cjs +921 -0
- package/dist/ai-sdk.cjs.map +1 -0
- package/dist/ai-sdk.d.cts +95 -0
- package/dist/ai-sdk.d.ts +95 -0
- package/dist/ai-sdk.js +150 -0
- package/dist/ai-sdk.js.map +1 -0
- package/dist/bin.cjs +944 -0
- package/dist/bin.cjs.map +1 -0
- package/dist/bin.d.cts +1 -0
- package/dist/bin.d.ts +1 -0
- package/dist/bin.js +12 -0
- package/dist/bin.js.map +1 -0
- package/dist/chunk-APXU3MTX.js +958 -0
- package/dist/chunk-APXU3MTX.js.map +1 -0
- package/dist/chunk-DHX7SNWE.js +310 -0
- package/dist/chunk-DHX7SNWE.js.map +1 -0
- package/dist/chunk-L65R2SM5.js +228 -0
- package/dist/chunk-L65R2SM5.js.map +1 -0
- package/dist/chunk-UBRK4CTM.js +156 -0
- package/dist/chunk-UBRK4CTM.js.map +1 -0
- package/dist/chunk-XJOQ5IUT.js +110 -0
- package/dist/chunk-XJOQ5IUT.js.map +1 -0
- package/dist/cli.cjs +964 -0
- package/dist/cli.cjs.map +1 -0
- package/dist/cli.d.cts +7 -0
- package/dist/cli.d.ts +7 -0
- package/dist/cli.js +9 -0
- package/dist/cli.js.map +1 -0
- package/dist/disclosure-5a3UIVQZ.d.cts +70 -0
- package/dist/disclosure-C7Y_uY73.d.ts +70 -0
- package/dist/elements-auto.cjs +642 -0
- package/dist/elements-auto.cjs.map +1 -0
- package/dist/elements-auto.d.cts +3 -0
- package/dist/elements-auto.d.ts +3 -0
- package/dist/elements-auto.js +16 -0
- package/dist/elements-auto.js.map +1 -0
- package/dist/elements.cjs +639 -0
- package/dist/elements.cjs.map +1 -0
- package/dist/elements.d.cts +47 -0
- package/dist/elements.d.ts +47 -0
- package/dist/elements.js +13 -0
- package/dist/elements.js.map +1 -0
- package/dist/image-B7YvdITx.d.ts +49 -0
- package/dist/image-BNrEO-hj.d.cts +49 -0
- package/dist/index.cjs +1344 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +124 -0
- package/dist/index.d.ts +124 -0
- package/dist/index.js +77 -0
- package/dist/index.js.map +1 -0
- package/dist/types-WWHzrNlc.d.cts +90 -0
- package/dist/types-WWHzrNlc.d.ts +90 -0
- package/package.json +123 -3
- package/src/ai-sdk.ts +252 -0
- package/src/bin.ts +6 -0
- package/src/cli.ts +160 -0
- package/src/disclosure.ts +172 -0
- package/src/elements-auto.ts +5 -0
- package/src/elements.ts +356 -0
- package/src/i18n.ts +259 -0
- package/src/image.ts +552 -0
- package/src/index.ts +66 -0
- package/src/inflate.ts +189 -0
- package/src/marking.ts +237 -0
- package/src/types.ts +115 -0
- package/src/watermark.ts +165 -0
- package/styles.css +103 -0
|
@@ -0,0 +1,642 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/elements-auto.ts
|
|
21
|
+
var elements_auto_exports = {};
|
|
22
|
+
__export(elements_auto_exports, {
|
|
23
|
+
WitnessLabelElement: () => WitnessLabelElement,
|
|
24
|
+
WitnessNoticeElement: () => WitnessNoticeElement,
|
|
25
|
+
defineWitnessElements: () => defineWitnessElements
|
|
26
|
+
});
|
|
27
|
+
module.exports = __toCommonJS(elements_auto_exports);
|
|
28
|
+
|
|
29
|
+
// src/disclosure.ts
|
|
30
|
+
var PREFIX = "witness:ack:";
|
|
31
|
+
function createDisclosure(options = {}) {
|
|
32
|
+
const kind = options.kind ?? "chatbot";
|
|
33
|
+
const id = options.id ?? kind;
|
|
34
|
+
const version = options.version ?? "1";
|
|
35
|
+
const locale2 = options.locale ?? "en";
|
|
36
|
+
const now = options.now ?? (() => /* @__PURE__ */ new Date());
|
|
37
|
+
const storage = resolveStorage(options.storage);
|
|
38
|
+
const key = `${PREFIX}${id}`;
|
|
39
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
40
|
+
let shown = false;
|
|
41
|
+
const read = () => {
|
|
42
|
+
try {
|
|
43
|
+
const raw = storage.getItem(key);
|
|
44
|
+
if (!raw) return null;
|
|
45
|
+
const parsed = JSON.parse(raw);
|
|
46
|
+
if (typeof parsed.version !== "string" || typeof parsed.at !== "string") return null;
|
|
47
|
+
return { version: parsed.version, at: parsed.at };
|
|
48
|
+
} catch {
|
|
49
|
+
return null;
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
const emit = (type, at) => {
|
|
53
|
+
options.onEvent?.({ type, id, kind, version, locale: locale2, at });
|
|
54
|
+
};
|
|
55
|
+
const notify = () => {
|
|
56
|
+
for (const listener of listeners) listener();
|
|
57
|
+
};
|
|
58
|
+
return {
|
|
59
|
+
id,
|
|
60
|
+
kind,
|
|
61
|
+
version,
|
|
62
|
+
needsAcknowledgement: () => read()?.version !== version,
|
|
63
|
+
acknowledgedAt: () => {
|
|
64
|
+
const entry = read();
|
|
65
|
+
return entry?.version === version ? entry.at : null;
|
|
66
|
+
},
|
|
67
|
+
markShown() {
|
|
68
|
+
if (shown) return;
|
|
69
|
+
shown = true;
|
|
70
|
+
emit("shown", now().toISOString());
|
|
71
|
+
},
|
|
72
|
+
acknowledge() {
|
|
73
|
+
const at = now().toISOString();
|
|
74
|
+
try {
|
|
75
|
+
storage.setItem(key, JSON.stringify({ version, at }));
|
|
76
|
+
} catch {
|
|
77
|
+
}
|
|
78
|
+
emit("acknowledged", at);
|
|
79
|
+
notify();
|
|
80
|
+
},
|
|
81
|
+
reset() {
|
|
82
|
+
try {
|
|
83
|
+
storage.removeItem(key);
|
|
84
|
+
} catch {
|
|
85
|
+
}
|
|
86
|
+
notify();
|
|
87
|
+
},
|
|
88
|
+
subscribe(listener) {
|
|
89
|
+
listeners.add(listener);
|
|
90
|
+
return () => listeners.delete(listener);
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
function resolveStorage(option) {
|
|
95
|
+
if (option && typeof option === "object") return option;
|
|
96
|
+
if (option !== "memory") {
|
|
97
|
+
try {
|
|
98
|
+
const candidate = option === "session" ? globalThis.sessionStorage : globalThis.localStorage;
|
|
99
|
+
if (candidate) {
|
|
100
|
+
const probe = `${PREFIX}probe`;
|
|
101
|
+
candidate.setItem(probe, "1");
|
|
102
|
+
candidate.removeItem(probe);
|
|
103
|
+
return candidate;
|
|
104
|
+
}
|
|
105
|
+
} catch {
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
return memoryStorage();
|
|
109
|
+
}
|
|
110
|
+
function memoryStorage() {
|
|
111
|
+
const map = /* @__PURE__ */ new Map();
|
|
112
|
+
return {
|
|
113
|
+
getItem: (key) => map.get(key) ?? null,
|
|
114
|
+
setItem: (key, value) => {
|
|
115
|
+
map.set(key, value);
|
|
116
|
+
},
|
|
117
|
+
removeItem: (key) => {
|
|
118
|
+
map.delete(key);
|
|
119
|
+
}
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// src/i18n.ts
|
|
124
|
+
var en = {
|
|
125
|
+
kinds: {
|
|
126
|
+
chatbot: {
|
|
127
|
+
label: "AI assistant",
|
|
128
|
+
title: "You are chatting with an AI",
|
|
129
|
+
body: "This assistant is an AI system, not a person. Its answers are generated automatically and can be wrong."
|
|
130
|
+
},
|
|
131
|
+
generated: {
|
|
132
|
+
label: "AI-generated",
|
|
133
|
+
title: "AI-generated content",
|
|
134
|
+
body: "This content was generated by an AI system."
|
|
135
|
+
},
|
|
136
|
+
edited: {
|
|
137
|
+
label: "AI-edited",
|
|
138
|
+
title: "Edited with AI",
|
|
139
|
+
body: "This content was edited or altered with an AI system."
|
|
140
|
+
},
|
|
141
|
+
deepfake: {
|
|
142
|
+
label: "Artificially generated",
|
|
143
|
+
title: "Artificially generated or manipulated",
|
|
144
|
+
body: "This content was generated or manipulated with AI. It may show people, places or events differently from how they really were."
|
|
145
|
+
},
|
|
146
|
+
"emotion-recognition": {
|
|
147
|
+
label: "Emotion recognition",
|
|
148
|
+
title: "Emotion recognition is active",
|
|
149
|
+
body: "This service uses an AI system that recognises emotions or intentions from your data."
|
|
150
|
+
},
|
|
151
|
+
"biometric-categorisation": {
|
|
152
|
+
label: "Biometric categorisation",
|
|
153
|
+
title: "Biometric categorisation is active",
|
|
154
|
+
body: "This service uses an AI system that assigns people to categories based on biometric data."
|
|
155
|
+
}
|
|
156
|
+
},
|
|
157
|
+
ui: {
|
|
158
|
+
acknowledge: "Got it",
|
|
159
|
+
details: "About this label",
|
|
160
|
+
generatedWith: "Generated with {generator}",
|
|
161
|
+
createdOn: "Created on {date}",
|
|
162
|
+
humanReviewed: "Reviewed by a person",
|
|
163
|
+
moreInfo: "How we use AI",
|
|
164
|
+
close: "Close"
|
|
165
|
+
}
|
|
166
|
+
};
|
|
167
|
+
var de = {
|
|
168
|
+
kinds: {
|
|
169
|
+
chatbot: {
|
|
170
|
+
label: "KI-Assistent",
|
|
171
|
+
title: "Sie chatten mit einer KI",
|
|
172
|
+
body: "Dieser Assistent ist ein KI-System und kein Mensch. Seine Antworten werden automatisch erzeugt und k\xF6nnen falsch sein."
|
|
173
|
+
},
|
|
174
|
+
generated: {
|
|
175
|
+
label: "KI-generiert",
|
|
176
|
+
title: "KI-generierter Inhalt",
|
|
177
|
+
body: "Dieser Inhalt wurde von einem KI-System erzeugt."
|
|
178
|
+
},
|
|
179
|
+
edited: {
|
|
180
|
+
label: "Mit KI bearbeitet",
|
|
181
|
+
title: "Mit KI bearbeitet",
|
|
182
|
+
body: "Dieser Inhalt wurde mit einem KI-System bearbeitet oder ver\xE4ndert."
|
|
183
|
+
},
|
|
184
|
+
deepfake: {
|
|
185
|
+
label: "K\xFCnstlich erzeugt",
|
|
186
|
+
title: "K\xFCnstlich erzeugt oder ver\xE4ndert",
|
|
187
|
+
body: "Dieser Inhalt wurde mit KI erzeugt oder ver\xE4ndert. Er kann Personen, Orte oder Ereignisse anders zeigen, als sie wirklich waren."
|
|
188
|
+
},
|
|
189
|
+
"emotion-recognition": {
|
|
190
|
+
label: "Emotionserkennung",
|
|
191
|
+
title: "Emotionserkennung ist aktiv",
|
|
192
|
+
body: "Dieser Dienst setzt ein KI-System ein, das aus Ihren Daten Emotionen oder Absichten erkennt."
|
|
193
|
+
},
|
|
194
|
+
"biometric-categorisation": {
|
|
195
|
+
label: "Biometrische Kategorisierung",
|
|
196
|
+
title: "Biometrische Kategorisierung ist aktiv",
|
|
197
|
+
body: "Dieser Dienst setzt ein KI-System ein, das Personen anhand biometrischer Daten Kategorien zuordnet."
|
|
198
|
+
}
|
|
199
|
+
},
|
|
200
|
+
ui: {
|
|
201
|
+
acknowledge: "Verstanden",
|
|
202
|
+
details: "\xDCber diese Kennzeichnung",
|
|
203
|
+
generatedWith: "Erzeugt mit {generator}",
|
|
204
|
+
createdOn: "Erstellt am {date}",
|
|
205
|
+
humanReviewed: "Von einem Menschen gepr\xFCft",
|
|
206
|
+
moreInfo: "Wie wir KI einsetzen",
|
|
207
|
+
close: "Schliessen"
|
|
208
|
+
}
|
|
209
|
+
};
|
|
210
|
+
var fr = {
|
|
211
|
+
kinds: {
|
|
212
|
+
chatbot: {
|
|
213
|
+
label: "Assistant IA",
|
|
214
|
+
title: "Vous discutez avec une IA",
|
|
215
|
+
body: "Cet assistant est un syst\xE8me d\u2019IA, pas une personne. Ses r\xE9ponses sont g\xE9n\xE9r\xE9es automatiquement et peuvent \xEAtre erron\xE9es."
|
|
216
|
+
},
|
|
217
|
+
generated: {
|
|
218
|
+
label: "G\xE9n\xE9r\xE9 par IA",
|
|
219
|
+
title: "Contenu g\xE9n\xE9r\xE9 par IA",
|
|
220
|
+
body: "Ce contenu a \xE9t\xE9 g\xE9n\xE9r\xE9 par un syst\xE8me d\u2019IA."
|
|
221
|
+
},
|
|
222
|
+
edited: {
|
|
223
|
+
label: "Modifi\xE9 par IA",
|
|
224
|
+
title: "Modifi\xE9 avec l\u2019IA",
|
|
225
|
+
body: "Ce contenu a \xE9t\xE9 modifi\xE9 ou alt\xE9r\xE9 \xE0 l\u2019aide d\u2019un syst\xE8me d\u2019IA."
|
|
226
|
+
},
|
|
227
|
+
deepfake: {
|
|
228
|
+
label: "G\xE9n\xE9r\xE9 artificiellement",
|
|
229
|
+
title: "G\xE9n\xE9r\xE9 ou manipul\xE9 artificiellement",
|
|
230
|
+
body: "Ce contenu a \xE9t\xE9 g\xE9n\xE9r\xE9 ou manipul\xE9 avec l\u2019IA. Il peut montrer des personnes, des lieux ou des \xE9v\xE9nements autrement qu\u2019ils n\u2019ont r\xE9ellement \xE9t\xE9."
|
|
231
|
+
},
|
|
232
|
+
"emotion-recognition": {
|
|
233
|
+
label: "Reconnaissance des \xE9motions",
|
|
234
|
+
title: "La reconnaissance des \xE9motions est active",
|
|
235
|
+
body: "Ce service utilise un syst\xE8me d\u2019IA qui reconna\xEEt des \xE9motions ou des intentions \xE0 partir de vos donn\xE9es."
|
|
236
|
+
},
|
|
237
|
+
"biometric-categorisation": {
|
|
238
|
+
label: "Cat\xE9gorisation biom\xE9trique",
|
|
239
|
+
title: "La cat\xE9gorisation biom\xE9trique est active",
|
|
240
|
+
body: "Ce service utilise un syst\xE8me d\u2019IA qui classe les personnes dans des cat\xE9gories \xE0 partir de donn\xE9es biom\xE9triques."
|
|
241
|
+
}
|
|
242
|
+
},
|
|
243
|
+
ui: {
|
|
244
|
+
acknowledge: "Compris",
|
|
245
|
+
details: "\xC0 propos de ce label",
|
|
246
|
+
generatedWith: "G\xE9n\xE9r\xE9 avec {generator}",
|
|
247
|
+
createdOn: "Cr\xE9\xE9 le {date}",
|
|
248
|
+
humanReviewed: "V\xE9rifi\xE9 par une personne",
|
|
249
|
+
moreInfo: "Comment nous utilisons l\u2019IA",
|
|
250
|
+
close: "Fermer"
|
|
251
|
+
}
|
|
252
|
+
};
|
|
253
|
+
var it = {
|
|
254
|
+
kinds: {
|
|
255
|
+
chatbot: {
|
|
256
|
+
label: "Assistente IA",
|
|
257
|
+
title: "Stai parlando con un\u2019IA",
|
|
258
|
+
body: "Questo assistente \xE8 un sistema di IA, non una persona. Le sue risposte sono generate automaticamente e possono essere sbagliate."
|
|
259
|
+
},
|
|
260
|
+
generated: {
|
|
261
|
+
label: "Generato con IA",
|
|
262
|
+
title: "Contenuto generato con IA",
|
|
263
|
+
body: "Questo contenuto \xE8 stato generato da un sistema di IA."
|
|
264
|
+
},
|
|
265
|
+
edited: {
|
|
266
|
+
label: "Modificato con IA",
|
|
267
|
+
title: "Modificato con l\u2019IA",
|
|
268
|
+
body: "Questo contenuto \xE8 stato modificato o alterato con un sistema di IA."
|
|
269
|
+
},
|
|
270
|
+
deepfake: {
|
|
271
|
+
label: "Generato artificialmente",
|
|
272
|
+
title: "Generato o manipolato artificialmente",
|
|
273
|
+
body: "Questo contenuto \xE8 stato generato o manipolato con l\u2019IA. Pu\xF2 mostrare persone, luoghi o eventi in modo diverso da come sono stati realmente."
|
|
274
|
+
},
|
|
275
|
+
"emotion-recognition": {
|
|
276
|
+
label: "Riconoscimento delle emozioni",
|
|
277
|
+
title: "Il riconoscimento delle emozioni \xE8 attivo",
|
|
278
|
+
body: "Questo servizio utilizza un sistema di IA che riconosce emozioni o intenzioni a partire dai tuoi dati."
|
|
279
|
+
},
|
|
280
|
+
"biometric-categorisation": {
|
|
281
|
+
label: "Categorizzazione biometrica",
|
|
282
|
+
title: "La categorizzazione biometrica \xE8 attiva",
|
|
283
|
+
body: "Questo servizio utilizza un sistema di IA che assegna le persone a categorie in base a dati biometrici."
|
|
284
|
+
}
|
|
285
|
+
},
|
|
286
|
+
ui: {
|
|
287
|
+
acknowledge: "Ho capito",
|
|
288
|
+
details: "Informazioni su questa etichetta",
|
|
289
|
+
generatedWith: "Generato con {generator}",
|
|
290
|
+
createdOn: "Creato il {date}",
|
|
291
|
+
humanReviewed: "Verificato da una persona",
|
|
292
|
+
moreInfo: "Come usiamo l\u2019IA",
|
|
293
|
+
close: "Chiudi"
|
|
294
|
+
}
|
|
295
|
+
};
|
|
296
|
+
var registry = /* @__PURE__ */ new Map([
|
|
297
|
+
["en", en],
|
|
298
|
+
["de", de],
|
|
299
|
+
["fr", fr],
|
|
300
|
+
["it", it]
|
|
301
|
+
]);
|
|
302
|
+
function resolveLocale(input) {
|
|
303
|
+
const tags = input == null ? [] : typeof input === "string" ? [input] : input;
|
|
304
|
+
for (const tag of tags) {
|
|
305
|
+
const lower = tag.toLowerCase();
|
|
306
|
+
if (registry.has(lower)) return lower;
|
|
307
|
+
const language = lower.split("-")[0] ?? "";
|
|
308
|
+
if (registry.has(language)) return language;
|
|
309
|
+
}
|
|
310
|
+
return "en";
|
|
311
|
+
}
|
|
312
|
+
function getMessages(locale2, override) {
|
|
313
|
+
const messages = registry.get(resolveLocale(locale2)) ?? en;
|
|
314
|
+
return override ? mergeMessages(messages, override) : messages;
|
|
315
|
+
}
|
|
316
|
+
function format(template, values) {
|
|
317
|
+
return template.replace(/\{(\w+)\}/g, (match, name) => values[name] ?? match);
|
|
318
|
+
}
|
|
319
|
+
function mergeMessages(base, override) {
|
|
320
|
+
const kinds = { ...base.kinds };
|
|
321
|
+
for (const [kind, text] of Object.entries(override.kinds ?? {})) {
|
|
322
|
+
const key = kind;
|
|
323
|
+
kinds[key] = { ...base.kinds[key], ...text };
|
|
324
|
+
}
|
|
325
|
+
const ui = { ...base.ui, ...override.ui ?? {} };
|
|
326
|
+
return { kinds, ui };
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
// src/types.ts
|
|
330
|
+
var DISCLOSURE_KINDS = [
|
|
331
|
+
"chatbot",
|
|
332
|
+
"generated",
|
|
333
|
+
"edited",
|
|
334
|
+
"deepfake",
|
|
335
|
+
"emotion-recognition",
|
|
336
|
+
"biometric-categorisation"
|
|
337
|
+
];
|
|
338
|
+
|
|
339
|
+
// src/elements.ts
|
|
340
|
+
var BaseElement = typeof HTMLElement === "undefined" ? class {
|
|
341
|
+
} : HTMLElement;
|
|
342
|
+
var SHARED_CSS = `
|
|
343
|
+
:host { --witness-accent: #003399; --witness-accent-text: #ffffff; --witness-bg: #ffffff;
|
|
344
|
+
--witness-fg: #1a1a1a; --witness-muted: #555b66; --witness-border: #d7dbe3; --witness-radius: 8px;
|
|
345
|
+
font: inherit; color: var(--witness-fg); }
|
|
346
|
+
@media (prefers-color-scheme: dark) {
|
|
347
|
+
:host { --witness-accent: #8fb0ff; --witness-accent-text: #0b1530; --witness-bg: #15181f;
|
|
348
|
+
--witness-fg: #eef1f6; --witness-muted: #a9b0bd; --witness-border: #2c323d; }
|
|
349
|
+
}
|
|
350
|
+
.icon { display: inline-flex; align-items: center; justify-content: center; min-width: 1.75em;
|
|
351
|
+
height: 1.5em; padding: 0 .3em; border-radius: 4px; background: var(--witness-accent);
|
|
352
|
+
color: var(--witness-accent-text); font-weight: 700; font-size: .75em; letter-spacing: .02em;
|
|
353
|
+
line-height: 1; flex: none; }
|
|
354
|
+
button { font: inherit; cursor: pointer; }
|
|
355
|
+
button:focus-visible, a:focus-visible { outline: 2px solid var(--witness-accent); outline-offset: 2px; }
|
|
356
|
+
a { color: inherit; }
|
|
357
|
+
.muted { color: var(--witness-muted); }
|
|
358
|
+
`;
|
|
359
|
+
var NOTICE_CSS = `${SHARED_CSS}
|
|
360
|
+
:host { display: block; }
|
|
361
|
+
.notice { display: flex; gap: .75em; align-items: flex-start; padding: .875em 1em;
|
|
362
|
+
border: 1px solid var(--witness-border); border-left: 4px solid var(--witness-accent);
|
|
363
|
+
border-radius: var(--witness-radius); background: var(--witness-bg); }
|
|
364
|
+
.notice h2 { font-size: 1em; margin: 0 0 .25em; }
|
|
365
|
+
.notice p { margin: 0 0 .75em; line-height: 1.45; }
|
|
366
|
+
.actions { display: flex; gap: .75em; align-items: center; flex-wrap: wrap; }
|
|
367
|
+
.ack { padding: .4em .9em; border-radius: 6px; border: 0; background: var(--witness-accent);
|
|
368
|
+
color: var(--witness-accent-text); font-weight: 600; }
|
|
369
|
+
.compact { display: inline-flex; gap: .5em; align-items: center; padding: .25em .5em;
|
|
370
|
+
border: 1px solid var(--witness-border); border-radius: 999px; background: var(--witness-bg);
|
|
371
|
+
color: var(--witness-fg); font-size: .875em; }
|
|
372
|
+
`;
|
|
373
|
+
var LABEL_CSS = `${SHARED_CSS}
|
|
374
|
+
:host { display: inline-block; position: relative; font-size: .875em; }
|
|
375
|
+
:host([variant="overlay"]) { position: absolute; inset-block-start: .5em; inset-inline-end: .5em; z-index: 1; }
|
|
376
|
+
.badge { display: inline-flex; gap: .4em; align-items: center; padding: .2em .55em .2em .25em;
|
|
377
|
+
border: 1px solid var(--witness-border); border-radius: 999px; background: var(--witness-bg);
|
|
378
|
+
color: var(--witness-fg); }
|
|
379
|
+
.panel { position: absolute; inset-block-start: calc(100% + .4em); inset-inline-end: 0; z-index: 10;
|
|
380
|
+
width: max-content; max-width: min(22em, 80vw); padding: .75em .875em; text-align: start;
|
|
381
|
+
border: 1px solid var(--witness-border); border-radius: var(--witness-radius);
|
|
382
|
+
background: var(--witness-bg); box-shadow: 0 6px 24px rgb(0 0 0 / .15); line-height: 1.45; }
|
|
383
|
+
:host([variant="inline"]) .panel, :host(:not([variant])) .panel { inset-inline-end: auto; inset-inline-start: 0; }
|
|
384
|
+
.panel strong { display: block; margin-bottom: .25em; }
|
|
385
|
+
.panel p { margin: 0 0 .4em; }
|
|
386
|
+
.panel ul { margin: .4em 0; padding-inline-start: 1.1em; }
|
|
387
|
+
.close { position: absolute; inset-block-start: .35em; inset-inline-end: .35em; border: 0;
|
|
388
|
+
background: none; color: var(--witness-muted); font-size: 1.1em; line-height: 1; padding: .2em .35em; }
|
|
389
|
+
[hidden] { display: none !important; }
|
|
390
|
+
`;
|
|
391
|
+
function locale(el) {
|
|
392
|
+
const own = el.getAttribute("locale") ?? el.closest("[lang]")?.getAttribute("lang");
|
|
393
|
+
if (own) return [own];
|
|
394
|
+
return typeof navigator !== "undefined" ? [...navigator.languages] : [];
|
|
395
|
+
}
|
|
396
|
+
function kindOf(el, fallback) {
|
|
397
|
+
const value = el.getAttribute("kind");
|
|
398
|
+
return value && DISCLOSURE_KINDS.includes(value) ? value : fallback;
|
|
399
|
+
}
|
|
400
|
+
function h(doc, tag, attrs = {}, ...children) {
|
|
401
|
+
const el = doc.createElement(tag);
|
|
402
|
+
for (const [name, value] of Object.entries(attrs)) el.setAttribute(name, value);
|
|
403
|
+
for (const child of children) {
|
|
404
|
+
if (child !== null) el.append(child);
|
|
405
|
+
}
|
|
406
|
+
return el;
|
|
407
|
+
}
|
|
408
|
+
function icon(doc) {
|
|
409
|
+
return h(doc, "span", { class: "icon", "aria-hidden": "true", part: "icon" }, "AI");
|
|
410
|
+
}
|
|
411
|
+
var WitnessNoticeElement = class extends BaseElement {
|
|
412
|
+
static {
|
|
413
|
+
this.observedAttributes = ["kind", "locale", "disclosure-id", "version", "href", "storage"];
|
|
414
|
+
}
|
|
415
|
+
#disclosure = null;
|
|
416
|
+
#unsubscribe = null;
|
|
417
|
+
#expanded = false;
|
|
418
|
+
connectedCallback() {
|
|
419
|
+
if (!this.shadowRoot) this.attachShadow({ mode: "open" });
|
|
420
|
+
this.#setup();
|
|
421
|
+
}
|
|
422
|
+
disconnectedCallback() {
|
|
423
|
+
this.#unsubscribe?.();
|
|
424
|
+
this.#unsubscribe = null;
|
|
425
|
+
}
|
|
426
|
+
attributeChangedCallback() {
|
|
427
|
+
if (this.isConnected && this.shadowRoot) this.#setup();
|
|
428
|
+
}
|
|
429
|
+
/** Forgets the acknowledgement and shows the full notice again. */
|
|
430
|
+
reset() {
|
|
431
|
+
this.#disclosure?.reset();
|
|
432
|
+
}
|
|
433
|
+
get disclosure() {
|
|
434
|
+
return this.#disclosure;
|
|
435
|
+
}
|
|
436
|
+
#setup() {
|
|
437
|
+
this.#unsubscribe?.();
|
|
438
|
+
const storage = this.getAttribute("storage");
|
|
439
|
+
const kind = kindOf(this, "chatbot");
|
|
440
|
+
const tags = locale(this);
|
|
441
|
+
this.#disclosure = createDisclosure({
|
|
442
|
+
kind,
|
|
443
|
+
id: this.getAttribute("disclosure-id") ?? kind,
|
|
444
|
+
version: this.getAttribute("version") ?? "1",
|
|
445
|
+
locale: getLocaleCode(tags),
|
|
446
|
+
...storage === "session" || storage === "memory" || storage === "local" ? { storage } : {},
|
|
447
|
+
onEvent: (event) => this.#dispatch(event)
|
|
448
|
+
});
|
|
449
|
+
this.#expanded = false;
|
|
450
|
+
this.#unsubscribe = this.#disclosure.subscribe(() => {
|
|
451
|
+
this.#expanded = false;
|
|
452
|
+
this.#render();
|
|
453
|
+
});
|
|
454
|
+
this.#render();
|
|
455
|
+
}
|
|
456
|
+
#dispatch(event) {
|
|
457
|
+
this.dispatchEvent(
|
|
458
|
+
new CustomEvent(`witness-${event.type}`, { detail: event, bubbles: true, composed: true })
|
|
459
|
+
);
|
|
460
|
+
}
|
|
461
|
+
#render() {
|
|
462
|
+
const root = this.shadowRoot;
|
|
463
|
+
const disclosure = this.#disclosure;
|
|
464
|
+
if (!root || !disclosure) return;
|
|
465
|
+
const doc = this.ownerDocument;
|
|
466
|
+
const messages = getMessages(locale(this));
|
|
467
|
+
const text = messages.kinds[disclosure.kind];
|
|
468
|
+
const href = this.getAttribute("href");
|
|
469
|
+
const full = this.#expanded || disclosure.needsAcknowledgement();
|
|
470
|
+
const style = h(doc, "style", {}, NOTICE_CSS);
|
|
471
|
+
if (full) {
|
|
472
|
+
const ack = h(
|
|
473
|
+
doc,
|
|
474
|
+
"button",
|
|
475
|
+
{ type: "button", class: "ack", part: "button" },
|
|
476
|
+
messages.ui.acknowledge
|
|
477
|
+
);
|
|
478
|
+
ack.addEventListener("click", () => disclosure.acknowledge());
|
|
479
|
+
const link = href ? h(doc, "a", { href, part: "link" }, messages.ui.moreInfo) : null;
|
|
480
|
+
const box = h(
|
|
481
|
+
doc,
|
|
482
|
+
"section",
|
|
483
|
+
{ class: "notice", role: "note", "aria-labelledby": "title", part: "notice" },
|
|
484
|
+
icon(doc),
|
|
485
|
+
h(
|
|
486
|
+
doc,
|
|
487
|
+
"div",
|
|
488
|
+
{},
|
|
489
|
+
h(doc, "h2", { id: "title", part: "title" }, text.title),
|
|
490
|
+
h(doc, "p", { part: "body" }, h(doc, "slot", {}, text.body)),
|
|
491
|
+
h(doc, "div", { class: "actions" }, ack, link)
|
|
492
|
+
)
|
|
493
|
+
);
|
|
494
|
+
root.replaceChildren(style, box);
|
|
495
|
+
disclosure.markShown();
|
|
496
|
+
} else {
|
|
497
|
+
const reopen = h(
|
|
498
|
+
doc,
|
|
499
|
+
"button",
|
|
500
|
+
{
|
|
501
|
+
type: "button",
|
|
502
|
+
class: "compact",
|
|
503
|
+
"aria-label": `${text.label}: ${messages.ui.details}`,
|
|
504
|
+
part: "compact"
|
|
505
|
+
},
|
|
506
|
+
icon(doc),
|
|
507
|
+
text.label
|
|
508
|
+
);
|
|
509
|
+
reopen.addEventListener("click", () => {
|
|
510
|
+
this.#expanded = true;
|
|
511
|
+
this.#render();
|
|
512
|
+
});
|
|
513
|
+
root.replaceChildren(style, reopen);
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
};
|
|
517
|
+
var WitnessLabelElement = class extends BaseElement {
|
|
518
|
+
static {
|
|
519
|
+
this.observedAttributes = [
|
|
520
|
+
"kind",
|
|
521
|
+
"locale",
|
|
522
|
+
"generator",
|
|
523
|
+
"generator-version",
|
|
524
|
+
"created",
|
|
525
|
+
"reviewed",
|
|
526
|
+
"href",
|
|
527
|
+
"variant"
|
|
528
|
+
];
|
|
529
|
+
}
|
|
530
|
+
#open = false;
|
|
531
|
+
#onKey = (event) => {
|
|
532
|
+
if (event.key === "Escape" && this.#open) {
|
|
533
|
+
this.#toggle(false);
|
|
534
|
+
this.shadowRoot?.querySelector(".badge")?.focus();
|
|
535
|
+
}
|
|
536
|
+
};
|
|
537
|
+
#onOutside = (event) => {
|
|
538
|
+
if (this.#open && !event.composedPath().includes(this)) this.#toggle(false);
|
|
539
|
+
};
|
|
540
|
+
connectedCallback() {
|
|
541
|
+
if (!this.shadowRoot) this.attachShadow({ mode: "open" });
|
|
542
|
+
this.ownerDocument.addEventListener("keydown", this.#onKey);
|
|
543
|
+
this.ownerDocument.addEventListener("click", this.#onOutside);
|
|
544
|
+
this.#render();
|
|
545
|
+
}
|
|
546
|
+
disconnectedCallback() {
|
|
547
|
+
this.ownerDocument.removeEventListener("keydown", this.#onKey);
|
|
548
|
+
this.ownerDocument.removeEventListener("click", this.#onOutside);
|
|
549
|
+
}
|
|
550
|
+
attributeChangedCallback() {
|
|
551
|
+
if (this.isConnected && this.shadowRoot) this.#render();
|
|
552
|
+
}
|
|
553
|
+
#toggle(open) {
|
|
554
|
+
this.#open = open;
|
|
555
|
+
this.#render();
|
|
556
|
+
}
|
|
557
|
+
#render() {
|
|
558
|
+
const root = this.shadowRoot;
|
|
559
|
+
if (!root) return;
|
|
560
|
+
const doc = this.ownerDocument;
|
|
561
|
+
const tags = locale(this);
|
|
562
|
+
const messages = getMessages(tags);
|
|
563
|
+
const kind = kindOf(this, "generated");
|
|
564
|
+
const text = messages.kinds[kind];
|
|
565
|
+
const generator = [this.getAttribute("generator"), this.getAttribute("generator-version")].filter(Boolean).join(" ");
|
|
566
|
+
const created = this.getAttribute("created");
|
|
567
|
+
const href = this.getAttribute("href");
|
|
568
|
+
const badge = h(
|
|
569
|
+
doc,
|
|
570
|
+
"button",
|
|
571
|
+
{
|
|
572
|
+
type: "button",
|
|
573
|
+
class: "badge",
|
|
574
|
+
part: "badge",
|
|
575
|
+
"aria-expanded": String(this.#open),
|
|
576
|
+
"aria-controls": "panel",
|
|
577
|
+
title: messages.ui.details
|
|
578
|
+
},
|
|
579
|
+
icon(doc),
|
|
580
|
+
h(doc, "span", { part: "label" }, text.label)
|
|
581
|
+
);
|
|
582
|
+
badge.addEventListener("click", () => this.#toggle(!this.#open));
|
|
583
|
+
const facts = h(doc, "ul", {});
|
|
584
|
+
if (generator) facts.append(h(doc, "li", {}, format(messages.ui.generatedWith, { generator })));
|
|
585
|
+
if (created) {
|
|
586
|
+
facts.append(
|
|
587
|
+
h(doc, "li", {}, format(messages.ui.createdOn, { date: formatDate(created, tags) }))
|
|
588
|
+
);
|
|
589
|
+
}
|
|
590
|
+
if (this.hasAttribute("reviewed")) facts.append(h(doc, "li", {}, messages.ui.humanReviewed));
|
|
591
|
+
const close = h(
|
|
592
|
+
doc,
|
|
593
|
+
"button",
|
|
594
|
+
{ type: "button", class: "close", "aria-label": messages.ui.close },
|
|
595
|
+
"\xD7"
|
|
596
|
+
);
|
|
597
|
+
close.addEventListener("click", () => this.#toggle(false));
|
|
598
|
+
const panel = h(
|
|
599
|
+
doc,
|
|
600
|
+
"div",
|
|
601
|
+
{ id: "panel", class: "panel", role: "dialog", "aria-label": text.title, part: "panel" },
|
|
602
|
+
close,
|
|
603
|
+
h(doc, "strong", {}, text.title),
|
|
604
|
+
h(doc, "p", {}, text.body),
|
|
605
|
+
facts.childElementCount > 0 ? facts : null,
|
|
606
|
+
href ? h(doc, "a", { href, part: "link" }, messages.ui.moreInfo) : null
|
|
607
|
+
);
|
|
608
|
+
if (!this.#open) panel.hidden = true;
|
|
609
|
+
root.replaceChildren(h(doc, "style", {}, LABEL_CSS), badge, panel);
|
|
610
|
+
}
|
|
611
|
+
};
|
|
612
|
+
function formatDate(value, tags) {
|
|
613
|
+
const date = new Date(value);
|
|
614
|
+
if (Number.isNaN(date.getTime())) return value;
|
|
615
|
+
try {
|
|
616
|
+
return new Intl.DateTimeFormat(tags.length > 0 ? tags : void 0, {
|
|
617
|
+
dateStyle: "medium"
|
|
618
|
+
}).format(date);
|
|
619
|
+
} catch {
|
|
620
|
+
return value;
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
function getLocaleCode(tags) {
|
|
624
|
+
return tags[0] ?? "en";
|
|
625
|
+
}
|
|
626
|
+
function defineWitnessElements() {
|
|
627
|
+
if (typeof customElements === "undefined") return;
|
|
628
|
+
if (!customElements.get("witness-notice"))
|
|
629
|
+
customElements.define("witness-notice", WitnessNoticeElement);
|
|
630
|
+
if (!customElements.get("witness-label"))
|
|
631
|
+
customElements.define("witness-label", WitnessLabelElement);
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
// src/elements-auto.ts
|
|
635
|
+
defineWitnessElements();
|
|
636
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
637
|
+
0 && (module.exports = {
|
|
638
|
+
WitnessLabelElement,
|
|
639
|
+
WitnessNoticeElement,
|
|
640
|
+
defineWitnessElements
|
|
641
|
+
});
|
|
642
|
+
//# sourceMappingURL=elements-auto.cjs.map
|