arcane-os 0.2.2 → 0.3.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/CHANGELOG.md +29 -0
- package/README.md +8 -8
- package/browser-runtime/ARCANE_SDK_BROWSER_RELEASE.json +29 -22
- package/browser-runtime/ai/ARCANE_AI_BROWSER_SPEECH_COMPONENTS.json +203 -0
- package/browser-runtime/ai/browser-kokoro-worker.mjs +11 -2
- package/browser-runtime/ai/browser-speech-artifacts.mjs +3230 -397
- package/browser-runtime/ai/browser-speech-providers.mjs +1141 -157
- package/browser-runtime/ai/browser-speech.mjs +2 -0
- package/browser-runtime/ai/browser-whisper-worker.mjs +11 -2
- package/browser-runtime/ai/model-controller.mjs +285 -95
- package/browser-runtime/ai/speech-worker-client.mjs +247 -32
- package/browser-runtime/ai/speech-worker-runtime.mjs +2310 -167
- package/browser-runtime/event-manager.mjs +1097 -1
- package/docs/architecture.md +2 -2
- package/docs/event-manager.md +155 -27
- package/docs/reference/README.md +27 -27
- package/docs/reference/ai/browser-speech-package-authority.json +835 -0
- package/docs/reference/ai/browser-speech.md +1162 -246
- package/docs/reference/ai/browser-wasm.md +18 -7
- package/docs/reference/availability-and-normalization.md +6 -3
- package/docs/reference/behavioral-testing.md +29 -6
- package/docs/reference/cli.md +117 -9
- package/docs/reference/core/arcane-ai-contracts.md +1 -1
- package/docs/reference/event-manager.md +577 -32
- package/docs/reference/inventory/package-api.json +478 -2
- package/docs/reference/inventory/runtime-components.json +108 -44
- package/docs/reference/inventory/runtime-modules.json +131 -53
- package/docs/reference/mail.md +316 -0
- package/docs/reference/protocols.md +157 -43
- package/docs/reference/runtime-components.md +258 -83
- package/docs/reference/runtime-modules.md +613 -77
- package/docs/reference/sdk-api.md +1014 -25
- package/package.json +5 -4
- package/runtime/ARCANE_RUNTIME_RELEASE.json +145 -140
- package/runtime/arcane/components/app-bar.html +34 -13
- package/runtime/arcane/components/assistant-panel.html +110 -57
- package/runtime/arcane/components/calculator.html +7 -4
- package/runtime/arcane/components/chart.html +58 -17
- package/runtime/arcane/components/chat.html +606 -136
- package/runtime/arcane/components/conversation-view.html +13 -6
- package/runtime/arcane/components/dashboard-config.html +96 -59
- package/runtime/arcane/components/data-maintenance.html +69 -14
- package/runtime/arcane/components/data-view.html +53 -7
- package/runtime/arcane/components/directory-picker.html +118 -32
- package/runtime/arcane/components/document-inspector.html +47 -10
- package/runtime/arcane/components/file-drop.html +81 -35
- package/runtime/arcane/components/file-inspector.html +72 -22
- package/runtime/arcane/components/file-manager.html +374 -79
- package/runtime/arcane/components/integration-settings.html +12 -5
- package/runtime/arcane/components/local-ai-status.html +48 -19
- package/runtime/arcane/components/markdown-document.html +161 -68
- package/runtime/arcane/components/markdown-editor.html +110 -33
- package/runtime/arcane/components/media-embed.html +8 -5
- package/runtime/arcane/components/modal.html +15 -5
- package/runtime/arcane/components/output-panel.html +28 -23
- package/runtime/arcane/components/preferences-form.html +22 -4
- package/runtime/arcane/components/record-timeline.html +18 -2
- package/runtime/arcane/components/relationship-board.html +23 -3
- package/runtime/arcane/components/screen-capture.html +10 -4
- package/runtime/arcane/components/source-code-viewer.html +76 -9
- package/runtime/arcane/components/source-explanation.html +23 -3
- package/runtime/arcane/components/speech.html +462 -384
- package/runtime/arcane/components/summary-strip.html +22 -11
- package/runtime/arcane/components/table.html +39 -21
- package/runtime/arcane/components/task-progress.html +79 -21
- package/runtime/arcane/components/terminal-workspace.html +7 -4
- package/runtime/arcane/components/theme-editor.html +7 -3
- package/runtime/arcane/components/unified-inbox.html +9 -4
- package/runtime/arcane/components/voice-transcription.html +639 -98
- package/runtime/arcane/components/weather-widget.html +5 -3
- package/runtime/arcane/components/web-navigator.html +48 -8
- package/runtime/arcane/entities/Chat.js +1 -1
- package/runtime/arcane/entities/User.js +110 -23
- package/runtime/arcane/modules/AI.js +2109 -130
- package/runtime/arcane/modules/AIProviderRuntime.js +720 -13
- package/runtime/arcane/modules/AIRuntimeState.js +109 -52
- package/runtime/arcane/modules/ApiModelDatabase.js +390 -17
- package/runtime/arcane/modules/BrowserTestSuite.js +205 -28
- package/runtime/arcane/modules/CalculatorEngine.js +63 -3
- package/runtime/arcane/modules/CommunicationAppController.js +588 -28
- package/runtime/arcane/modules/CommunicationHub.js +590 -10
- package/runtime/arcane/modules/ComponentContracts.js +470 -0
- package/runtime/arcane/modules/ConversationTimebox.js +152 -33
- package/runtime/arcane/modules/DBLS.js +40 -7
- package/runtime/arcane/modules/DBOPFS.js +35 -11
- package/runtime/arcane/modules/DataMaintenance.js +12 -2
- package/runtime/arcane/modules/Errors.js +65 -7
- package/runtime/arcane/modules/HTMLImport.js +198 -14
- package/runtime/arcane/modules/LocalAIReadinessController.js +208 -29
- package/runtime/arcane/modules/Mail.js +738 -115
- package/runtime/arcane/modules/MailOutbox.mjs +1395 -0
- package/runtime/arcane/modules/MailTransport.mjs +197 -39
- package/runtime/arcane/modules/Ollama.js +36 -1
- package/runtime/arcane/modules/OpenMeteoWeatherProvider.js +583 -7
- package/runtime/arcane/modules/PreferenceStore.js +367 -33
- package/runtime/arcane/modules/RecordReviewStore.js +322 -23
- package/runtime/arcane/modules/ScreenCapture.js +1397 -15
- package/runtime/arcane/modules/SpeechPlayback.js +438 -41
- package/runtime/arcane/modules/TerminalClient.js +277 -12
- package/runtime/arcane/modules/ThemeBootstrap.js +80 -6
- package/runtime/arcane/modules/ThemeManager.js +39 -7
- package/runtime/arcane/modules/TimeGuard.js +131 -20
- package/runtime/arcane/modules/WaitForComponent.js +386 -33
- package/schemas/arcane-lock.schema.json +2 -2
- package/src/cli/main.mjs +435 -9
- package/src/event-manager.mjs +1097 -1
- package/src/import-map.mjs +21 -3
- package/src/index.mjs +13 -0
- package/src/installed-sdk-runtime.mjs +112 -0
- package/src/mail-api.mjs +22 -0
- package/src/mail-credentials.mjs +667 -0
- package/src/mail-server.mjs +1769 -0
- package/src/mail.mjs +261 -0
- package/src/sdk-browser-runtime.mjs +85 -41
- package/src/testing-loader.mjs +7 -0
- package/src/toolchain.mjs +3 -0
- package/src/workspace.mjs +1 -1
|
@@ -89,6 +89,9 @@
|
|
|
89
89
|
applyMarkdownFormat,
|
|
90
90
|
normalizeMarkdownOptions
|
|
91
91
|
}=await import(moduleURL('ComponentContracts.js'));
|
|
92
|
+
const {createArcaneEventSource,projectArcaneDOMEvent}=await import('arcane-os/event-manager');
|
|
93
|
+
const events=createArcaneEventSource(host,{source:'arcane.component.markdown-editor',eventTypes:['markdown-editor-change','markdown-editor-saved','markdown-editor-ready']});
|
|
94
|
+
const lifecycleController=new AbortController();
|
|
92
95
|
const titleInput=host.shadowRoot.querySelector('#entryTitle');
|
|
93
96
|
const preview=host.shadowRoot.querySelector('#preview');
|
|
94
97
|
const toolbar=host.shadowRoot.querySelector('#toolbar');
|
|
@@ -97,29 +100,43 @@
|
|
|
97
100
|
const status=host.shadowRoot.querySelector('#status');
|
|
98
101
|
|
|
99
102
|
let previewFrame=0;
|
|
103
|
+
let operationSequence=0;
|
|
104
|
+
let saveGeneration=0;
|
|
105
|
+
let saveController=null;
|
|
106
|
+
let destroyed=false;
|
|
100
107
|
let options=normalizeMarkdownOptions(optionsFromDataset());
|
|
101
108
|
|
|
109
|
+
function emit(type,detail={},publicDetail={},operationId=null){
|
|
110
|
+
if(destroyed){
|
|
111
|
+
return false;
|
|
112
|
+
}
|
|
113
|
+
const publication=events.dispatch(type,detail,{publicDetail,operationId});
|
|
114
|
+
return projectArcaneDOMEvent(host,publication.occurrence,{bubbles:true,composed:true});
|
|
115
|
+
}
|
|
116
|
+
|
|
102
117
|
host.clear=clear;
|
|
103
118
|
host.configure=configure;
|
|
104
|
-
host.
|
|
119
|
+
host.destroy=destroy;
|
|
120
|
+
host.focus=()=>{if(destroyed)return false;textarea.focus();return true;};
|
|
105
121
|
host.saveEntry=saveEntry;
|
|
106
122
|
|
|
107
123
|
Object.defineProperties(
|
|
108
124
|
host,
|
|
109
125
|
{
|
|
110
126
|
entryTitle:{
|
|
127
|
+
configurable:true,
|
|
111
128
|
get:()=>titleInput.value,
|
|
112
129
|
set:value=>setTitle(value)
|
|
113
130
|
},
|
|
114
|
-
options:{get:getOptions,set:configure},
|
|
115
|
-
value:{get:()=>textarea.value,set:setValue}
|
|
131
|
+
options:{configurable:true,get:getOptions,set:configure},
|
|
132
|
+
value:{configurable:true,get:()=>textarea.value,set:setValue}
|
|
116
133
|
}
|
|
117
134
|
);
|
|
118
135
|
|
|
119
|
-
textarea.addEventListener('input',contentChanged);
|
|
120
|
-
titleInput.addEventListener('input',contentChanged);
|
|
121
|
-
toolbar.addEventListener('click',formatMarkdown);
|
|
122
|
-
saveButton.addEventListener('click',saveEntry);
|
|
136
|
+
textarea.addEventListener('input',contentChanged,{signal:lifecycleController.signal});
|
|
137
|
+
titleInput.addEventListener('input',contentChanged,{signal:lifecycleController.signal});
|
|
138
|
+
toolbar.addEventListener('click',formatMarkdown,{signal:lifecycleController.signal});
|
|
139
|
+
saveButton.addEventListener('click',saveEntry,{signal:lifecycleController.signal});
|
|
123
140
|
|
|
124
141
|
function optionsFromDataset(){
|
|
125
142
|
const dataset=host.dataset||{};
|
|
@@ -152,6 +169,9 @@
|
|
|
152
169
|
}
|
|
153
170
|
|
|
154
171
|
function configure(input={}){
|
|
172
|
+
if(destroyed){
|
|
173
|
+
return false;
|
|
174
|
+
}
|
|
155
175
|
const setInitialValue=Object.prototype.hasOwnProperty.call(
|
|
156
176
|
input||{},
|
|
157
177
|
'initialValue'
|
|
@@ -163,9 +183,11 @@
|
|
|
163
183
|
options=normalizeMarkdownOptions(input,options);
|
|
164
184
|
renderOptions();
|
|
165
185
|
if(setInitialTitle){
|
|
186
|
+
supersedeSave('markdown-title-replaced');
|
|
166
187
|
titleInput.value=options.initialTitle;
|
|
167
188
|
}
|
|
168
189
|
if(setInitialValue){
|
|
190
|
+
supersedeSave('markdown-content-replaced');
|
|
169
191
|
textarea.value=options.initialValue;
|
|
170
192
|
}
|
|
171
193
|
updatePreview();
|
|
@@ -204,17 +226,16 @@
|
|
|
204
226
|
}
|
|
205
227
|
|
|
206
228
|
function contentChanged(){
|
|
229
|
+
if(destroyed){
|
|
230
|
+
return;
|
|
231
|
+
}
|
|
232
|
+
supersedeSave('markdown-content-edited');
|
|
207
233
|
schedulePreview();
|
|
208
234
|
const detail={
|
|
209
235
|
markdown:textarea.value,
|
|
210
236
|
title:titleInput.value
|
|
211
237
|
};
|
|
212
|
-
|
|
213
|
-
new CustomEvent(
|
|
214
|
-
'markdown-editor-change',
|
|
215
|
-
{bubbles:true,composed:true,detail}
|
|
216
|
-
)
|
|
217
|
-
);
|
|
238
|
+
emit('markdown-editor-change',detail,{markdownLength:detail.markdown.length,titleLength:detail.title.length});
|
|
218
239
|
if(options.onChange){
|
|
219
240
|
Promise.resolve(options.onChange(detail)).catch(
|
|
220
241
|
error=>console.error('Markdown change callback failed:',error)
|
|
@@ -223,6 +244,9 @@
|
|
|
223
244
|
}
|
|
224
245
|
|
|
225
246
|
function schedulePreview(){
|
|
247
|
+
if(destroyed){
|
|
248
|
+
return;
|
|
249
|
+
}
|
|
226
250
|
if(previewFrame){
|
|
227
251
|
cancelAnimationFrame(previewFrame);
|
|
228
252
|
}
|
|
@@ -230,6 +254,9 @@
|
|
|
230
254
|
}
|
|
231
255
|
|
|
232
256
|
function updatePreview(){
|
|
257
|
+
if(destroyed){
|
|
258
|
+
return;
|
|
259
|
+
}
|
|
233
260
|
if(previewFrame){
|
|
234
261
|
cancelAnimationFrame(previewFrame);
|
|
235
262
|
}
|
|
@@ -268,7 +295,7 @@
|
|
|
268
295
|
}
|
|
269
296
|
|
|
270
297
|
async function saveEntry(){
|
|
271
|
-
if(options.readOnly||!options.showSave){
|
|
298
|
+
if(destroyed||options.readOnly||!options.showSave){
|
|
272
299
|
return false;
|
|
273
300
|
}
|
|
274
301
|
const markdown=textarea.value;
|
|
@@ -287,35 +314,52 @@
|
|
|
287
314
|
return false;
|
|
288
315
|
}
|
|
289
316
|
|
|
317
|
+
saveController?.abort('markdown-save-replaced');
|
|
318
|
+
const controller=new AbortController();
|
|
319
|
+
saveController=controller;
|
|
320
|
+
const generation=++saveGeneration;
|
|
321
|
+
const operationId=`${events.descriptor.instanceId}:save:${++operationSequence}`;
|
|
290
322
|
saveButton.disabled=true;
|
|
291
323
|
status.innerText=options.labels.saving;
|
|
292
324
|
try{
|
|
293
|
-
await save({title:entryTitle,markdown});
|
|
325
|
+
await save({title:entryTitle,markdown},{signal:controller.signal,operationId});
|
|
326
|
+
if(destroyed||generation!==saveGeneration){
|
|
327
|
+
return false;
|
|
328
|
+
}
|
|
294
329
|
if(options.clearOnSave){
|
|
295
|
-
|
|
330
|
+
resetEditor(false);
|
|
296
331
|
}
|
|
297
332
|
status.innerText=options.labels.saved;
|
|
298
|
-
|
|
299
|
-
new CustomEvent(
|
|
300
|
-
'markdown-editor-saved',
|
|
301
|
-
{
|
|
302
|
-
bubbles:true,
|
|
303
|
-
composed:true,
|
|
304
|
-
detail:{title:entryTitle,markdown}
|
|
305
|
-
}
|
|
306
|
-
)
|
|
307
|
-
);
|
|
333
|
+
emit('markdown-editor-saved',{title:entryTitle,markdown},{markdownLength:markdown.length,titleLength:entryTitle.length},operationId);
|
|
308
334
|
return true;
|
|
309
335
|
}catch(error){
|
|
336
|
+
if(destroyed||generation!==saveGeneration||controller.signal.aborted){
|
|
337
|
+
return false;
|
|
338
|
+
}
|
|
310
339
|
status.innerText=options.labels.saveError;
|
|
311
340
|
console.error('Unable to save Markdown content:',error);
|
|
312
341
|
return false;
|
|
313
342
|
}finally{
|
|
314
|
-
|
|
343
|
+
if(saveController===controller){
|
|
344
|
+
saveController=null;
|
|
345
|
+
}
|
|
346
|
+
if(!destroyed&&generation===saveGeneration){
|
|
347
|
+
syncSaveButton();
|
|
348
|
+
}
|
|
315
349
|
}
|
|
316
350
|
}
|
|
317
351
|
|
|
318
352
|
function clear(){
|
|
353
|
+
return resetEditor(true);
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
function resetEditor(supersede){
|
|
357
|
+
if(destroyed){
|
|
358
|
+
return false;
|
|
359
|
+
}
|
|
360
|
+
if(supersede){
|
|
361
|
+
supersedeSave('markdown-content-cleared');
|
|
362
|
+
}
|
|
319
363
|
titleInput.value='';
|
|
320
364
|
textarea.value='';
|
|
321
365
|
updatePreview();
|
|
@@ -323,12 +367,20 @@
|
|
|
323
367
|
}
|
|
324
368
|
|
|
325
369
|
function setValue(value=''){
|
|
370
|
+
if(destroyed){
|
|
371
|
+
return false;
|
|
372
|
+
}
|
|
373
|
+
supersedeSave('markdown-content-replaced');
|
|
326
374
|
textarea.value=`${value??''}`;
|
|
327
375
|
updatePreview();
|
|
328
376
|
return textarea.value;
|
|
329
377
|
}
|
|
330
378
|
|
|
331
379
|
function setTitle(value=''){
|
|
380
|
+
if(destroyed){
|
|
381
|
+
return false;
|
|
382
|
+
}
|
|
383
|
+
supersedeSave('markdown-title-replaced');
|
|
332
384
|
titleInput.value=`${value??''}`;
|
|
333
385
|
return titleInput.value;
|
|
334
386
|
}
|
|
@@ -345,16 +397,41 @@
|
|
|
345
397
|
};
|
|
346
398
|
}
|
|
347
399
|
|
|
400
|
+
function supersedeSave(reason){
|
|
401
|
+
const active=saveController!==null;
|
|
402
|
+
saveGeneration+=1;
|
|
403
|
+
saveController?.abort(reason);
|
|
404
|
+
saveController=null;
|
|
405
|
+
if(!destroyed){
|
|
406
|
+
if(active){
|
|
407
|
+
status.innerText='';
|
|
408
|
+
}
|
|
409
|
+
syncSaveButton();
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
function destroy(){
|
|
414
|
+
if(destroyed){
|
|
415
|
+
return false;
|
|
416
|
+
}
|
|
417
|
+
destroyed=true;
|
|
418
|
+
supersedeSave('markdown-editor-destroyed');
|
|
419
|
+
lifecycleController.abort('markdown-editor-destroyed');
|
|
420
|
+
if(previewFrame){
|
|
421
|
+
cancelAnimationFrame(previewFrame);
|
|
422
|
+
previewFrame=0;
|
|
423
|
+
}
|
|
424
|
+
preview.replaceChildren();
|
|
425
|
+
events.dispose();
|
|
426
|
+
host.ready=false;
|
|
427
|
+
return true;
|
|
428
|
+
}
|
|
429
|
+
|
|
348
430
|
renderOptions();
|
|
349
431
|
titleInput.value=options.initialTitle;
|
|
350
432
|
textarea.value=options.initialValue;
|
|
351
433
|
updatePreview();
|
|
352
434
|
status.innerText='';
|
|
353
435
|
host.ready=true;
|
|
354
|
-
|
|
355
|
-
new CustomEvent(
|
|
356
|
-
'markdown-editor-ready',
|
|
357
|
-
{bubbles:true,composed:true}
|
|
358
|
-
)
|
|
359
|
-
);
|
|
436
|
+
emit('markdown-editor-ready',{}, {ready:true});
|
|
360
437
|
</script>
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
<link rel="stylesheet" href="./arcane/css/theme.css?v=1"><link rel="stylesheet" href="./arcane/css/primitives.css?v=1">
|
|
2
2
|
<style>:host{display:block}.player-shell{display:grid;gap:var(--arcane-space-4)}.loader{display:flex;gap:var(--arcane-space-2)}.loader input{min-width:0;width:100%}.player{aspect-ratio:16/9;display:grid;place-items:center;overflow:hidden;background:var(--arcane-surface-muted);border:1px solid var(--arcane-border);border-radius:var(--arcane-radius-large)}iframe{width:100%;height:100%;border:0}.empty{text-align:center;color:var(--arcane-muted);padding:var(--arcane-space-5)}.footer{align-items:center;display:flex;gap:var(--arcane-space-3);justify-content:space-between}.status{margin:0;color:var(--arcane-muted)}@media(max-width:36rem){.loader,.footer{align-items:stretch;flex-direction:column}}</style>
|
|
3
3
|
<section class="player-shell"><form id="loader" class="loader"><label class="visually-hidden" for="mediaUrl">Video or playlist address</label><input id="mediaUrl" type="text" inputmode="url" autocomplete="off" spellcheck="false" placeholder="Paste a YouTube video or playlist URL"><button class="arcane-button" type="submit">Play</button></form><div class="player"><div id="empty" class="empty"><strong>Choose something to play</strong><p>Paste a YouTube or YouTube Music video or playlist address.</p></div><iframe id="frame" title="Embedded media player" hidden allow="autoplay; encrypted-media; picture-in-picture; fullscreen" allowfullscreen referrerpolicy="strict-origin-when-cross-origin"></iframe></div><div class="footer"><p id="status" class="status" role="status" aria-live="polite">Nothing loaded.</p><button id="platform" class="arcane-button arcane-button--secondary" type="button">Open platform</button></div></section>
|
|
4
|
-
<script type="module">const host=this,root=host.shadowRoot,form=root.querySelector('#loader'),input=root.querySelector('#mediaUrl'),frame=root.querySelector('#frame'),empty=root.querySelector('#empty'),status=root.querySelector('#status');const componentURL=new URL(host.getAttribute('href')||'./arcane/components/media-embed.html',document.baseURI);const {parseYouTubeMedia,youtubeEmbedUrl}=await import(new URL('../modules/YouTubeMedia.js',componentURL));let platformUrl='https://www.youtube.com/',privacyEnhanced=true;
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
4
|
+
<script type="module">const host=this,root=host.shadowRoot,form=root.querySelector('#loader'),input=root.querySelector('#mediaUrl'),frame=root.querySelector('#frame'),empty=root.querySelector('#empty'),status=root.querySelector('#status');const componentURL=new URL(host.getAttribute('href')||'./arcane/components/media-embed.html',document.baseURI);const {parseYouTubeMedia,youtubeEmbedUrl}=await import(new URL('../modules/YouTubeMedia.js',componentURL));const {createArcaneEventSource,projectArcaneDOMEvent}=await import('arcane-os/event-manager');const events=createArcaneEventSource(host,{source:'arcane.component.media-embed',eventTypes:['media-open-platform','media-load','media-error','media-embed-ready']}),lifecycleController=new AbortController();let platformUrl='https://www.youtube.com/',privacyEnhanced=true,destroyed=false,operationSequence=0;
|
|
5
|
+
function nextOperationId(kind){operationSequence+=1;return `${events.descriptor.instanceId}:${kind}:${operationSequence}`}
|
|
6
|
+
function emit(type,detail={},publicDetail={},operationId=null){if(destroyed)return false;const publication=events.dispatch(type,detail,{publicDetail,operationId});return projectArcaneDOMEvent(host,publication.occurrence,{bubbles:true,composed:true})}
|
|
7
|
+
host.configure=options=>{if(destroyed)return false;platformUrl=String(options?.platformUrl||platformUrl);privacyEnhanced=options?.privacyEnhanced!==false;if(options?.placeholder)input.placeholder=String(options.placeholder);if(options?.openLabel)root.querySelector('#platform').textContent=String(options.openLabel);if(options?.initialValue){input.value=String(options.initialValue);load(input.value)}return host};host.load=load;host.destroy=destroy;
|
|
8
|
+
form.addEventListener('submit',event=>{event.preventDefault();load(input.value)},{signal:lifecycleController.signal});root.querySelector('#platform').addEventListener('click',()=>emit('media-open-platform',{url:platformUrl},{destination:'platform'},nextOperationId('open-platform')),{signal:lifecycleController.signal});
|
|
9
|
+
function load(value){if(destroyed)return null;const operationId=nextOperationId('load');try{const locator=parseYouTubeMedia(value),url=youtubeEmbedUrl(locator,{privacyEnhanced});frame.src=url;frame.hidden=false;empty.hidden=true;status.textContent=locator.type==='playlist'?'Playlist loaded.':'Video loaded.';emit('media-load',{locator,url},{mediaType:String(locator.type||'video')},operationId);return locator}catch(error){const code=String(error?.code||'ARCANE_MEDIA_EMBED_SOURCE_INVALID'),reason='media-source-invalid';status.textContent=error.message;frame.hidden=true;empty.hidden=false;emit('media-error',{error,code,reason},{code,reason},operationId);return null}}
|
|
10
|
+
function destroy(){if(destroyed)return false;destroyed=true;lifecycleController.abort('media-embed-destroyed');frame.src='about:blank';frame.removeAttribute('src');frame.hidden=true;events.dispose();host.ready=false;return true}
|
|
11
|
+
host.ready=true;emit('media-embed-ready',{}, {ready:true});</script>
|
|
@@ -158,6 +158,8 @@
|
|
|
158
158
|
<script type="module">
|
|
159
159
|
const host=this;
|
|
160
160
|
const shadowRoot=host.shadowRoot;
|
|
161
|
+
const {createArcaneEventSource,projectArcaneDOMEvent}=await import('arcane-os/event-manager');
|
|
162
|
+
const events=createArcaneEventSource(host,{source:'arcane.component.modal',eventTypes:['modal-action','modal-opened','modal-closed','modal-ready']});
|
|
161
163
|
const dialog=shadowRoot.querySelector('#modal');
|
|
162
164
|
const modalContent=shadowRoot.querySelector('#modal-content');
|
|
163
165
|
const modalSearch=shadowRoot.querySelector('#modal-search');
|
|
@@ -175,8 +177,14 @@
|
|
|
175
177
|
host.populate=populate;
|
|
176
178
|
host.open=open;
|
|
177
179
|
host.close=close;
|
|
180
|
+
host.destroy=dispose;
|
|
178
181
|
host.runTasks=runTasks;
|
|
179
182
|
|
|
183
|
+
function emit(type,detail={},publicDetail={}){
|
|
184
|
+
const publication=events.dispatch(type,detail,{publicDetail});
|
|
185
|
+
return projectArcaneDOMEvent(host,publication.occurrence);
|
|
186
|
+
}
|
|
187
|
+
|
|
180
188
|
Object.defineProperties(host,{
|
|
181
189
|
running:{get:function getRunningState(){return running;}},
|
|
182
190
|
opened:{get:function getOpenedState(){return dialog.open;}}
|
|
@@ -220,7 +228,7 @@
|
|
|
220
228
|
const detail={...action.dataset};
|
|
221
229
|
detail.action=detail.modalAction;
|
|
222
230
|
delete detail.modalAction;
|
|
223
|
-
|
|
231
|
+
emit('modal-action',detail,{action:String(detail.action||'')});
|
|
224
232
|
});
|
|
225
233
|
|
|
226
234
|
async function open(){
|
|
@@ -244,7 +252,7 @@
|
|
|
244
252
|
const focusTarget=modalContent.querySelector('[autofocus],input:not([disabled]),select:not([disabled]),textarea:not([disabled]),button:not([disabled]),a[href]')||closeButton;
|
|
245
253
|
focusTarget?.focus({preventScroll:true});
|
|
246
254
|
});
|
|
247
|
-
|
|
255
|
+
emit('modal-opened',{}, {opened:true});
|
|
248
256
|
}
|
|
249
257
|
return true;
|
|
250
258
|
}
|
|
@@ -269,7 +277,7 @@
|
|
|
269
277
|
}
|
|
270
278
|
|
|
271
279
|
if(wasOpen){
|
|
272
|
-
|
|
280
|
+
emit('modal-closed',{}, {opened:false});
|
|
273
281
|
const target=returnFocus;
|
|
274
282
|
returnFocus=null;
|
|
275
283
|
queueMicrotask(function restoreModalReturnFocus(){
|
|
@@ -287,7 +295,7 @@
|
|
|
287
295
|
|
|
288
296
|
function dispose(){
|
|
289
297
|
if(disposed){
|
|
290
|
-
return;
|
|
298
|
+
return false;
|
|
291
299
|
}
|
|
292
300
|
disposed=true;
|
|
293
301
|
host.ready=false;
|
|
@@ -298,7 +306,9 @@
|
|
|
298
306
|
if(dialog.open){
|
|
299
307
|
dialog.close();
|
|
300
308
|
}
|
|
309
|
+
events.dispose();
|
|
301
310
|
host.remove();
|
|
311
|
+
return true;
|
|
302
312
|
}
|
|
303
313
|
|
|
304
314
|
async function populate(content='<p>Content goes here</p>',search=false){
|
|
@@ -398,5 +408,5 @@
|
|
|
398
408
|
}
|
|
399
409
|
|
|
400
410
|
host.ready=true;
|
|
401
|
-
|
|
411
|
+
emit('modal-ready',{}, {ready:true});
|
|
402
412
|
</script>
|
|
@@ -43,6 +43,8 @@
|
|
|
43
43
|
<script type="module">
|
|
44
44
|
const host=this;
|
|
45
45
|
const root=host.shadowRoot;
|
|
46
|
+
const {createArcaneEventSource,projectArcaneDOMEvent}=await import('arcane-os/event-manager');
|
|
47
|
+
const events=createArcaneEventSource(host,{source:'arcane.component.output-panel',eventTypes:['output-panel-action','output-panel-state','output-panel-error','output-panel-change','output-panel-cleared','output-panel-ready']});
|
|
46
48
|
const region=root.querySelector('#region');
|
|
47
49
|
const title=root.querySelector('#outputTitle');
|
|
48
50
|
const status=root.querySelector('#status');
|
|
@@ -55,11 +57,13 @@
|
|
|
55
57
|
const footerActions=root.querySelector('#footerActions');
|
|
56
58
|
|
|
57
59
|
let actions=[];
|
|
60
|
+
let destroyed=false;
|
|
58
61
|
let output=null;
|
|
59
62
|
let options={};
|
|
60
63
|
|
|
61
64
|
host.clear=clear;
|
|
62
65
|
host.configure=configure;
|
|
66
|
+
host.destroy=destroy;
|
|
63
67
|
host.setActions=setActions;
|
|
64
68
|
host.setBody=setBody;
|
|
65
69
|
host.setCoverage=setCoverage;
|
|
@@ -77,6 +81,13 @@
|
|
|
77
81
|
footerActions.addEventListener('click',handleAction);
|
|
78
82
|
bodySlot.addEventListener('slotchange',syncBodySlot);
|
|
79
83
|
|
|
84
|
+
function emit(type,detail={},publicDetail={},cancelable=false){
|
|
85
|
+
if(destroyed)return false;
|
|
86
|
+
const publication=events.dispatch(type,detail,{publicDetail,cancelable});
|
|
87
|
+
if(cancelable&&!publication.accepted) return false;
|
|
88
|
+
return projectArcaneDOMEvent(host,publication.occurrence,{bubbles:true,composed:true,cancelable});
|
|
89
|
+
}
|
|
90
|
+
|
|
80
91
|
function datasetOptions(){
|
|
81
92
|
return {
|
|
82
93
|
ariaLabel:host.dataset.ariaLabel||'Output',
|
|
@@ -183,12 +194,7 @@
|
|
|
183
194
|
if(!button||!action||action.disabled){
|
|
184
195
|
return;
|
|
185
196
|
}
|
|
186
|
-
|
|
187
|
-
bubbles:true,
|
|
188
|
-
cancelable:true,
|
|
189
|
-
composed:true,
|
|
190
|
-
detail:{action:{...action},id:action.id,output:output?{...output}:null}
|
|
191
|
-
}));
|
|
197
|
+
emit('output-panel-action',{action:{...action},id:action.id,output:output?{...output}:null},{actionId:action.id,hasOutput:Boolean(output)},true);
|
|
192
198
|
}
|
|
193
199
|
|
|
194
200
|
function setPending(value=true,message='Working…'){
|
|
@@ -197,11 +203,7 @@
|
|
|
197
203
|
if(pending){
|
|
198
204
|
renderState(message,'loading');
|
|
199
205
|
}
|
|
200
|
-
|
|
201
|
-
bubbles:true,
|
|
202
|
-
composed:true,
|
|
203
|
-
detail:{pending,state:pending?'loading':'ready'}
|
|
204
|
-
}));
|
|
206
|
+
emit('output-panel-state',{pending,state:pending?'loading':'ready'},{pending,state:pending?'loading':'ready'});
|
|
205
207
|
return pending;
|
|
206
208
|
}
|
|
207
209
|
|
|
@@ -210,11 +212,7 @@
|
|
|
210
212
|
body.setAttribute('aria-busy','false');
|
|
211
213
|
if(text){
|
|
212
214
|
renderState(text,'error');
|
|
213
|
-
|
|
214
|
-
bubbles:true,
|
|
215
|
-
composed:true,
|
|
216
|
-
detail:{message:text,output:output?{...output}:null}
|
|
217
|
-
}));
|
|
215
|
+
emit('output-panel-error',{message:text,output:output?{...output}:null},{hasOutput:Boolean(output),hasError:true});
|
|
218
216
|
}
|
|
219
217
|
return text;
|
|
220
218
|
}
|
|
@@ -231,11 +229,7 @@
|
|
|
231
229
|
}
|
|
232
230
|
|
|
233
231
|
function emitChange(){
|
|
234
|
-
|
|
235
|
-
bubbles:true,
|
|
236
|
-
composed:true,
|
|
237
|
-
detail:{output:output?{...output}:null}
|
|
238
|
-
}));
|
|
232
|
+
emit('output-panel-change',{output:output?{...output}:null},{hasOutput:Boolean(output)});
|
|
239
233
|
}
|
|
240
234
|
|
|
241
235
|
function clear(){
|
|
@@ -247,7 +241,18 @@
|
|
|
247
241
|
setActions([]);
|
|
248
242
|
renderState(options.emptyLabel||'No output yet.','empty');
|
|
249
243
|
body.setAttribute('aria-busy','false');
|
|
250
|
-
|
|
244
|
+
emit('output-panel-cleared');
|
|
245
|
+
return true;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
function destroy(){
|
|
249
|
+
if(destroyed)return false;
|
|
250
|
+
destroyed=true;
|
|
251
|
+
host.ready=false;
|
|
252
|
+
headerActions.removeEventListener('click',handleAction);
|
|
253
|
+
footerActions.removeEventListener('click',handleAction);
|
|
254
|
+
bodySlot.removeEventListener('slotchange',syncBodySlot);
|
|
255
|
+
events.dispose();
|
|
251
256
|
return true;
|
|
252
257
|
}
|
|
253
258
|
|
|
@@ -255,5 +260,5 @@
|
|
|
255
260
|
clear();
|
|
256
261
|
syncBodySlot();
|
|
257
262
|
host.ready=true;
|
|
258
|
-
|
|
263
|
+
emit('output-panel-ready',{}, {ready:true});
|
|
259
264
|
</script>
|
|
@@ -38,9 +38,19 @@
|
|
|
38
38
|
const status=root.querySelector('#status');
|
|
39
39
|
const reset=root.querySelector('#reset');
|
|
40
40
|
const save=root.querySelector('#save');
|
|
41
|
+
const {createArcaneEventSource,projectArcaneDOMEvent}=await import('arcane-os/event-manager');
|
|
42
|
+
const events=createArcaneEventSource(host,{source:'arcane.component.preferences-form',eventTypes:['preferences-submit','preferences-change','preferences-reset','preferences-form-ready']});
|
|
43
|
+
let destroyed=false;
|
|
41
44
|
let schema=[];
|
|
42
45
|
|
|
46
|
+
function emit(type,detail={},publicDetail={}){
|
|
47
|
+
if(destroyed)return false;
|
|
48
|
+
const publication=events.dispatch(type,detail,{publicDetail});
|
|
49
|
+
return projectArcaneDOMEvent(host,publication.occurrence,{bubbles:true,composed:true});
|
|
50
|
+
}
|
|
51
|
+
|
|
43
52
|
host.configure=configure;
|
|
53
|
+
host.destroy=destroy;
|
|
44
54
|
host.getValues=getValues;
|
|
45
55
|
host.setValues=setValues;
|
|
46
56
|
host.setBusy=setBusy;
|
|
@@ -48,14 +58,14 @@
|
|
|
48
58
|
|
|
49
59
|
form.addEventListener('submit',event=>{
|
|
50
60
|
event.preventDefault();
|
|
51
|
-
|
|
61
|
+
emit('preferences-submit',{values:getValues()},{fieldCount:schema.length});
|
|
52
62
|
});
|
|
53
63
|
form.addEventListener('input',event=>{
|
|
54
64
|
const field=schema.find(item=>item.key===event.target.name);
|
|
55
65
|
if(!field) return;
|
|
56
|
-
|
|
66
|
+
emit('preferences-change',{key:field.key,value:readControl(event.target,field),values:getValues()},{key:String(field.key),fieldType:String(field.type||'text')});
|
|
57
67
|
});
|
|
58
|
-
reset.addEventListener('click',()=>
|
|
68
|
+
reset.addEventListener('click',()=>emit('preferences-reset'));
|
|
59
69
|
|
|
60
70
|
function configure(options={}){
|
|
61
71
|
schema=Array.from(options.schema||[]).map(item=>typeof item.toJSON==='function'?item.toJSON():{...item});
|
|
@@ -130,6 +140,14 @@
|
|
|
130
140
|
}
|
|
131
141
|
function setStatus(message=''){status.innerText=String(message||'');return status.innerText;}
|
|
132
142
|
|
|
143
|
+
function destroy(){
|
|
144
|
+
if(destroyed)return false;
|
|
145
|
+
destroyed=true;
|
|
146
|
+
host.ready=false;
|
|
147
|
+
events.dispose();
|
|
148
|
+
return true;
|
|
149
|
+
}
|
|
150
|
+
|
|
133
151
|
host.ready=true;
|
|
134
|
-
|
|
152
|
+
emit('preferences-form-ready',{}, {ready:true});
|
|
135
153
|
</script>
|
|
@@ -28,18 +28,24 @@
|
|
|
28
28
|
const host=this;
|
|
29
29
|
const list=host.shadowRoot.querySelector('[data-list]');
|
|
30
30
|
const empty=host.shadowRoot.querySelector('[data-empty]');
|
|
31
|
+
const {createArcaneEventSource,projectArcaneDOMEvent}=await import('arcane-os/event-manager');
|
|
32
|
+
const events=createArcaneEventSource(host,{source:'arcane.component.record-timeline',eventTypes:['record-timeline-open','record-timeline-ready']});
|
|
33
|
+
let destroyed=false;
|
|
31
34
|
let items=[];
|
|
32
35
|
let options={emptyLabel:'No dated events match this view.'};
|
|
33
36
|
|
|
34
37
|
host.setItems=setItems;
|
|
35
38
|
host.populate=(value,input={})=>setItems(value,input);
|
|
39
|
+
host.destroy=destroy;
|
|
36
40
|
|
|
37
41
|
list.addEventListener('click',event=>{
|
|
42
|
+
if(destroyed) return;
|
|
38
43
|
const trigger=event.target.closest('[data-event-id]');
|
|
39
44
|
if(!trigger) return;
|
|
40
45
|
const item=items.find(candidate=>candidate.id===trigger.dataset.eventId);
|
|
41
46
|
if(!item) return;
|
|
42
|
-
|
|
47
|
+
const publication=events.dispatch('record-timeline-open',{id:item.id,item:{...item}},{publicDetail:{category:String(item.category||'')}});
|
|
48
|
+
projectArcaneDOMEvent(host,publication.occurrence,{bubbles:true,composed:true});
|
|
43
49
|
});
|
|
44
50
|
|
|
45
51
|
function normalizeItem(item,index){
|
|
@@ -101,5 +107,15 @@
|
|
|
101
107
|
}
|
|
102
108
|
}
|
|
103
109
|
|
|
104
|
-
|
|
110
|
+
function destroy(){
|
|
111
|
+
if(destroyed) return false;
|
|
112
|
+
destroyed=true;
|
|
113
|
+
host.ready=false;
|
|
114
|
+
events.dispose();
|
|
115
|
+
return true;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
host.ready=true;
|
|
119
|
+
const readyPublication=events.dispatch('record-timeline-ready',{}, {publicDetail:{ready:true}});
|
|
120
|
+
projectArcaneDOMEvent(host,readyPublication.occurrence,{bubbles:true,composed:true});
|
|
105
121
|
</script>
|
|
@@ -34,23 +34,33 @@
|
|
|
34
34
|
const selectedTitle=host.shadowRoot.querySelector('[data-selected-title]');
|
|
35
35
|
const selectedSummary=host.shadowRoot.querySelector('[data-selected-summary]');
|
|
36
36
|
const edgeList=host.shadowRoot.querySelector('[data-edges]');
|
|
37
|
+
const {createArcaneEventSource,projectArcaneDOMEvent}=await import('arcane-os/event-manager');
|
|
38
|
+
const events=createArcaneEventSource(host,{source:'arcane.component.relationship-board',eventTypes:['relationship-node-open','relationship-edge-open','relationship-board-ready']});
|
|
39
|
+
let destroyed=false;
|
|
37
40
|
let nodes=[]; let edges=[]; let lanes=[]; let selectedId='';
|
|
38
41
|
|
|
39
42
|
host.setGraph=setGraph;
|
|
40
43
|
host.populate=(graph={},options={})=>setGraph(graph,options);
|
|
44
|
+
host.destroy=destroy;
|
|
41
45
|
|
|
42
46
|
board.addEventListener('click',event=>{
|
|
47
|
+
if(destroyed) return;
|
|
43
48
|
const trigger=event.target.closest('[data-node-id]');
|
|
44
49
|
if(!trigger) return;
|
|
45
50
|
selectedId=trigger.dataset.nodeId; renderSelection();
|
|
46
51
|
const node=nodes.find(item=>item.id===selectedId);
|
|
47
|
-
|
|
52
|
+
const publication=events.dispatch('relationship-node-open',{id:selectedId,node:{...node}},{publicDetail:{lane:String(node?.lane||'')}});
|
|
53
|
+
projectArcaneDOMEvent(host,publication.occurrence,{bubbles:true,composed:true});
|
|
48
54
|
});
|
|
49
55
|
edgeList.addEventListener('click',event=>{
|
|
56
|
+
if(destroyed) return;
|
|
50
57
|
const trigger=event.target.closest('[data-edge-id]');
|
|
51
58
|
if(!trigger) return;
|
|
52
59
|
const edge=edges.find(item=>item.id===trigger.dataset.edgeId);
|
|
53
|
-
if(edge)
|
|
60
|
+
if(edge){
|
|
61
|
+
const publication=events.dispatch('relationship-edge-open',{id:edge.id,edge:{...edge}},{publicDetail:{hasEdge:true}});
|
|
62
|
+
projectArcaneDOMEvent(host,publication.occurrence,{bubbles:true,composed:true});
|
|
63
|
+
}
|
|
54
64
|
});
|
|
55
65
|
|
|
56
66
|
function normalizeNode(value,index){
|
|
@@ -112,5 +122,15 @@
|
|
|
112
122
|
if(!related.length){const row=document.createElement('li'); row.className='empty'; row.textContent='No displayed connections.'; edgeList.append(row);}
|
|
113
123
|
}
|
|
114
124
|
|
|
115
|
-
|
|
125
|
+
function destroy(){
|
|
126
|
+
if(destroyed) return false;
|
|
127
|
+
destroyed=true;
|
|
128
|
+
host.ready=false;
|
|
129
|
+
events.dispose();
|
|
130
|
+
return true;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
host.ready=true;
|
|
134
|
+
const readyPublication=events.dispatch('relationship-board-ready',{}, {publicDetail:{ready:true}});
|
|
135
|
+
projectArcaneDOMEvent(host,readyPublication.occurrence,{bubbles:true,composed:true});
|
|
116
136
|
</script>
|