arcane-os 0.1.0-dev.5

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.
Files changed (248) hide show
  1. package/CHANGELOG.md +154 -0
  2. package/COMMERCIAL-LICENSE.md +13 -0
  3. package/LICENSE +661 -0
  4. package/NOTICE +70 -0
  5. package/README.md +448 -0
  6. package/bin/arcane-test.mjs +741 -0
  7. package/bin/arcane.mjs +5 -0
  8. package/docs/architecture.md +234 -0
  9. package/docs/compatibility.md +36 -0
  10. package/docs/event-manager.md +166 -0
  11. package/docs/platform-targets.md +108 -0
  12. package/docs/publishing.md +203 -0
  13. package/docs/reference/README.md +117 -0
  14. package/docs/reference/arcane-ollama.md +288 -0
  15. package/docs/reference/availability-and-normalization.md +123 -0
  16. package/docs/reference/behavioral-testing.md +86 -0
  17. package/docs/reference/cli.md +569 -0
  18. package/docs/reference/core/README.md +62 -0
  19. package/docs/reference/core/arcane-ai-contracts.md +873 -0
  20. package/docs/reference/core/arcane-api.md +601 -0
  21. package/docs/reference/core/arcane-entities.md +65 -0
  22. package/docs/reference/core/arcane-events.md +134 -0
  23. package/docs/reference/core/ollama-module.md +181 -0
  24. package/docs/reference/core/reference/arcane-api/ai-and-ollama.md +1909 -0
  25. package/docs/reference/core/reference/arcane-api/applications-terminal-capabilities.md +1057 -0
  26. package/docs/reference/core/reference/arcane-api/core-and-events.md +320 -0
  27. package/docs/reference/core/reference/arcane-api/filesystem-storage-preferences-appearance.md +610 -0
  28. package/docs/reference/core/reference/arcane-api/namespaces.md +1157 -0
  29. package/docs/reference/core/reference/arcane-api/platform-installation-users-system.md +1423 -0
  30. package/docs/reference/core/reference/arcane-api/session-provisioning-diagnostics-development.md +315 -0
  31. package/docs/reference/event-manager.md +957 -0
  32. package/docs/reference/inventory/package-api.json +2632 -0
  33. package/docs/reference/inventory/runtime-components.json +934 -0
  34. package/docs/reference/inventory/runtime-entities.json +26 -0
  35. package/docs/reference/inventory/runtime-modules.json +1249 -0
  36. package/docs/reference/protocols.md +242 -0
  37. package/docs/reference/runtime-components.md +1098 -0
  38. package/docs/reference/runtime-entities.md +303 -0
  39. package/docs/reference/runtime-modules.md +2010 -0
  40. package/docs/reference/sdk-api.md +4901 -0
  41. package/docs/roadmap.md +79 -0
  42. package/docs/work-amplification.md +124 -0
  43. package/node_modules/event-pubsub/CHANGELOG.md +55 -0
  44. package/node_modules/event-pubsub/MIGRATION.md +70 -0
  45. package/node_modules/event-pubsub/README.md +363 -0
  46. package/node_modules/event-pubsub/SECURITY.md +37 -0
  47. package/node_modules/event-pubsub/index.js +141 -0
  48. package/node_modules/event-pubsub/licence +21 -0
  49. package/node_modules/event-pubsub/package.json +59 -0
  50. package/node_modules/strong-type/README.md +408 -0
  51. package/node_modules/strong-type/assets/strong-type-header.png +0 -0
  52. package/node_modules/strong-type/index.js +1151 -0
  53. package/node_modules/strong-type/licence +21 -0
  54. package/node_modules/strong-type/node.js +125 -0
  55. package/node_modules/strong-type/package.json +61 -0
  56. package/package.json +95 -0
  57. package/runtime/ARCANE_RUNTIME_RELEASE.json +791 -0
  58. package/runtime/arcane/components/app-bar.html +468 -0
  59. package/runtime/arcane/components/assistant-panel.html +715 -0
  60. package/runtime/arcane/components/calculator.html +8 -0
  61. package/runtime/arcane/components/chart.html +655 -0
  62. package/runtime/arcane/components/chat.html +1225 -0
  63. package/runtime/arcane/components/conversation-view.html +13 -0
  64. package/runtime/arcane/components/dashboard-config.html +341 -0
  65. package/runtime/arcane/components/data-maintenance.html +112 -0
  66. package/runtime/arcane/components/data-view.html +92 -0
  67. package/runtime/arcane/components/directory-picker.html +197 -0
  68. package/runtime/arcane/components/document-inspector.html +252 -0
  69. package/runtime/arcane/components/file-drop.html +264 -0
  70. package/runtime/arcane/components/file-inspector.html +293 -0
  71. package/runtime/arcane/components/file-manager.html +1715 -0
  72. package/runtime/arcane/components/header.html +142 -0
  73. package/runtime/arcane/components/integration-settings.html +14 -0
  74. package/runtime/arcane/components/local-ai-status.html +360 -0
  75. package/runtime/arcane/components/markdown-document.html +1048 -0
  76. package/runtime/arcane/components/markdown-editor.html +360 -0
  77. package/runtime/arcane/components/media-embed.html +8 -0
  78. package/runtime/arcane/components/modal.html +402 -0
  79. package/runtime/arcane/components/output-panel.html +259 -0
  80. package/runtime/arcane/components/preferences-form.html +135 -0
  81. package/runtime/arcane/components/record-timeline.html +105 -0
  82. package/runtime/arcane/components/relationship-board.html +116 -0
  83. package/runtime/arcane/components/screen-capture.html +8 -0
  84. package/runtime/arcane/components/source-code-viewer.html +441 -0
  85. package/runtime/arcane/components/source-explanation.html +124 -0
  86. package/runtime/arcane/components/speech.html +365 -0
  87. package/runtime/arcane/components/summary-strip.html +177 -0
  88. package/runtime/arcane/components/table.html +77 -0
  89. package/runtime/arcane/components/task-progress.html +282 -0
  90. package/runtime/arcane/components/terminal-workspace.html +65 -0
  91. package/runtime/arcane/components/theme-editor.html +41 -0
  92. package/runtime/arcane/components/theme-switcher.html +46 -0
  93. package/runtime/arcane/components/unified-inbox.html +20 -0
  94. package/runtime/arcane/components/voice-transcription.html +476 -0
  95. package/runtime/arcane/components/weather-widget.html +8 -0
  96. package/runtime/arcane/components/web-navigator.html +239 -0
  97. package/runtime/arcane/css/communications.css +1 -0
  98. package/runtime/arcane/css/dashboard-config.css +45 -0
  99. package/runtime/arcane/css/document-site.css +981 -0
  100. package/runtime/arcane/css/layout.css +438 -0
  101. package/runtime/arcane/css/primitives.css +321 -0
  102. package/runtime/arcane/css/theme.css +112 -0
  103. package/runtime/arcane/css/utility-workspace.css +1 -0
  104. package/runtime/arcane/entities/ApiModelRecord.js +20 -0
  105. package/runtime/arcane/entities/Calculation.js +13 -0
  106. package/runtime/arcane/entities/Chat.js +581 -0
  107. package/runtime/arcane/entities/CommunicationMessage.js +29 -0
  108. package/runtime/arcane/entities/CommunicationThread.js +21 -0
  109. package/runtime/arcane/entities/Document.js +10 -0
  110. package/runtime/arcane/entities/File.js +143 -0
  111. package/runtime/arcane/entities/Image.js +135 -0
  112. package/runtime/arcane/entities/IntentEnvelope.js +834 -0
  113. package/runtime/arcane/entities/Preference.js +83 -0
  114. package/runtime/arcane/entities/TWiNPolicyDecision.js +1092 -0
  115. package/runtime/arcane/entities/TerminalSession.js +46 -0
  116. package/runtime/arcane/entities/Theme.js +107 -0
  117. package/runtime/arcane/entities/User.js +1046 -0
  118. package/runtime/arcane/entities/Weather.js +23 -0
  119. package/runtime/arcane/img/arcane-os-everywhere.png +0 -0
  120. package/runtime/arcane/img/arrow-left.png +0 -0
  121. package/runtime/arcane/img/arrow-right.png +0 -0
  122. package/runtime/arcane/img/doc.svg +5 -0
  123. package/runtime/arcane/img/folder.svg +4 -0
  124. package/runtime/arcane/img/image.svg +5 -0
  125. package/runtime/arcane/img/refresh.png +0 -0
  126. package/runtime/arcane/img/send.svg +9 -0
  127. package/runtime/arcane/img/trash.svg +5 -0
  128. package/runtime/arcane/img/upload.svg +5 -0
  129. package/runtime/arcane/modules/AI.js +2048 -0
  130. package/runtime/arcane/modules/AIPreferenceRuntime.js +32 -0
  131. package/runtime/arcane/modules/AIPreferenceTuple.js +92 -0
  132. package/runtime/arcane/modules/AIResponseLength.js +42 -0
  133. package/runtime/arcane/modules/AIResponseURLPolicy.js +626 -0
  134. package/runtime/arcane/modules/AnsiText.js +53 -0
  135. package/runtime/arcane/modules/ApiModelDatabase.js +25 -0
  136. package/runtime/arcane/modules/AppDataScope.js +245 -0
  137. package/runtime/arcane/modules/AppearancePreferences.js +28 -0
  138. package/runtime/arcane/modules/ArcaneCommunicationBridge.js +22 -0
  139. package/runtime/arcane/modules/ArcaneNavigationPolicy.js +135 -0
  140. package/runtime/arcane/modules/ArcaneNetworkPolicy.js +255 -0
  141. package/runtime/arcane/modules/AsyncBoundary.js +161 -0
  142. package/runtime/arcane/modules/BrowserTestSuite.js +326 -0
  143. package/runtime/arcane/modules/CalculatorEngine.js +20 -0
  144. package/runtime/arcane/modules/CaseEvidenceIndexer.js +134 -0
  145. package/runtime/arcane/modules/ChartLibrary.js +35 -0
  146. package/runtime/arcane/modules/ChatRecords.js +13 -0
  147. package/runtime/arcane/modules/CommunicationAppController.js +43 -0
  148. package/runtime/arcane/modules/CommunicationHub.js +16 -0
  149. package/runtime/arcane/modules/CommunicationPreferences.js +13 -0
  150. package/runtime/arcane/modules/CommunicationProviderRegistry.js +16 -0
  151. package/runtime/arcane/modules/ComponentContracts.js +586 -0
  152. package/runtime/arcane/modules/ConfiguredAIChatSession.js +288 -0
  153. package/runtime/arcane/modules/ConversationActionItems.js +488 -0
  154. package/runtime/arcane/modules/ConversationClosingReport.js +274 -0
  155. package/runtime/arcane/modules/ConversationTimebox.js +527 -0
  156. package/runtime/arcane/modules/CoreLocalModelCatalog.js +255 -0
  157. package/runtime/arcane/modules/DBLS.js +171 -0
  158. package/runtime/arcane/modules/DBOPFS.js +1154 -0
  159. package/runtime/arcane/modules/DBOPFSWorker.js +116 -0
  160. package/runtime/arcane/modules/DataMaintenance.js +91 -0
  161. package/runtime/arcane/modules/DevelopmentWorkspace.js +74 -0
  162. package/runtime/arcane/modules/DirectoryPicker.js +109 -0
  163. package/runtime/arcane/modules/DocumentNavigation.js +223 -0
  164. package/runtime/arcane/modules/Errors.js +1025 -0
  165. package/runtime/arcane/modules/GifEncoder.js +29 -0
  166. package/runtime/arcane/modules/HTMLImport.js +114 -0
  167. package/runtime/arcane/modules/InMemoryCommunicationProvider.js +14 -0
  168. package/runtime/arcane/modules/IsolatedModelQuestionRunner.js +275 -0
  169. package/runtime/arcane/modules/LocalAIReadiness.js +870 -0
  170. package/runtime/arcane/modules/LocalAIReadinessController.js +156 -0
  171. package/runtime/arcane/modules/MD.js +111 -0
  172. package/runtime/arcane/modules/Mail.js +352 -0
  173. package/runtime/arcane/modules/MailTransport.mjs +180 -0
  174. package/runtime/arcane/modules/Marked.min.js +71 -0
  175. package/runtime/arcane/modules/MemoryRecords.js +44 -0
  176. package/runtime/arcane/modules/MessageAdvisory.js +38 -0
  177. package/runtime/arcane/modules/ModelDefinition.js +189 -0
  178. package/runtime/arcane/modules/Ollama.js +74 -0
  179. package/runtime/arcane/modules/OllamaModelIdentifier.js +21 -0
  180. package/runtime/arcane/modules/OllamaSettings.js +24 -0
  181. package/runtime/arcane/modules/OpenMeteoWeatherProvider.js +14 -0
  182. package/runtime/arcane/modules/PreferenceStore.js +109 -0
  183. package/runtime/arcane/modules/QRCode.min.js +1 -0
  184. package/runtime/arcane/modules/Questionnaire.js +61 -0
  185. package/runtime/arcane/modules/RecordLinkIndex.js +24 -0
  186. package/runtime/arcane/modules/RecordPassageIndex.js +222 -0
  187. package/runtime/arcane/modules/RecordReviewStore.js +94 -0
  188. package/runtime/arcane/modules/RevocableProjectionLedger.js +1623 -0
  189. package/runtime/arcane/modules/RiskSignalAnalyzer.js +37 -0
  190. package/runtime/arcane/modules/ScamRiskPolicy.js +62 -0
  191. package/runtime/arcane/modules/ScopedOPFSCache.js +183 -0
  192. package/runtime/arcane/modules/ScreenCapture.js +20 -0
  193. package/runtime/arcane/modules/SpeechPlayback.js +581 -0
  194. package/runtime/arcane/modules/StaticDocumentCatalog.js +1248 -0
  195. package/runtime/arcane/modules/SystemAppearance.js +20 -0
  196. package/runtime/arcane/modules/SystemPlatformPresentation.js +51 -0
  197. package/runtime/arcane/modules/SystemToolRegistry.js +28 -0
  198. package/runtime/arcane/modules/TerminalClient.js +52 -0
  199. package/runtime/arcane/modules/TerminalCommandRegistry.js +50 -0
  200. package/runtime/arcane/modules/ThemeBootstrap.js +26 -0
  201. package/runtime/arcane/modules/ThemeManager.js +131 -0
  202. package/runtime/arcane/modules/TimeGuard.js +149 -0
  203. package/runtime/arcane/modules/ToolCallRouter.js +83 -0
  204. package/runtime/arcane/modules/WaitForComponent.js +102 -0
  205. package/runtime/arcane/modules/YouTubeMedia.js +16 -0
  206. package/runtime/arcane/modules/uPlot.LICENSE.txt +21 -0
  207. package/runtime/arcane/modules/uPlot.iife.min.js +2 -0
  208. package/runtime/arcane/modules/uPlot.min.css +1 -0
  209. package/runtime/arcane/security/arcane-network-policy.json +6 -0
  210. package/runtime/strong-type/index.js +352 -0
  211. package/runtime/strong-type/licence +21 -0
  212. package/runtime/strong-type/package.json +45 -0
  213. package/schemas/arcane-app-bundle.schema.json +125 -0
  214. package/schemas/arcane-app.schema.json +329 -0
  215. package/schemas/arcane-lock.schema.json +86 -0
  216. package/schemas/arcane-package.schema.json +224 -0
  217. package/schemas/cli-event.schema.json +122 -0
  218. package/schemas/event-stack.schema.json +152 -0
  219. package/schemas/native-build-plan.schema.json +176 -0
  220. package/schemas/target-adapter.schema.json +117 -0
  221. package/src/app-descriptor.mjs +500 -0
  222. package/src/cli/main.mjs +561 -0
  223. package/src/constants.mjs +31 -0
  224. package/src/dev-server.mjs +718 -0
  225. package/src/doctor.mjs +315 -0
  226. package/src/dom-event-instrumentation.mjs +594 -0
  227. package/src/errors.mjs +75 -0
  228. package/src/event-manager.mjs +1342 -0
  229. package/src/event-queue.mjs +138 -0
  230. package/src/events.mjs +219 -0
  231. package/src/index.mjs +177 -0
  232. package/src/integrated-provider-loader.mjs +432 -0
  233. package/src/native-plan.mjs +698 -0
  234. package/src/native-provider-loader.mjs +1126 -0
  235. package/src/packager/core.mjs +2691 -0
  236. package/src/process.mjs +353 -0
  237. package/src/release-bundle.mjs +2523 -0
  238. package/src/repository.mjs +90 -0
  239. package/src/runtime.mjs +452 -0
  240. package/src/scaffold.mjs +380 -0
  241. package/src/targets/index.mjs +436 -0
  242. package/src/templates/assets/app-icon.png +0 -0
  243. package/src/templates/workspace-template.mjs +388 -0
  244. package/src/testing-loader.mjs +9 -0
  245. package/src/testing.mjs +427 -0
  246. package/src/toolchain.mjs +1335 -0
  247. package/src/update-check.mjs +307 -0
  248. package/src/workspace.mjs +449 -0
@@ -0,0 +1,402 @@
1
+ <link rel="stylesheet" href="./arcane/css/layout.css?v=3" />
2
+ <style>
3
+ :host{
4
+ --modal-surface:var(--modal-background,var(--background,#fff));
5
+ --modal-border:var(--border-color,rgba(127,127,127,.35));
6
+ --modal-shadow:0 .5em 2em var(--shadow-color,rgba(0,0,0,.28));
7
+ --modal-backdrop:rgba(0,0,0,.55);
8
+ --modal-width:min(35em,calc(100vw - 2em));
9
+ --modal-max-height:min(80vh,calc(100vh - 2em));
10
+ --modal-radius:.65em;
11
+ --modal-padding:3em;
12
+ display:contents;
13
+ }
14
+
15
+ dialog.modal{
16
+ box-sizing:border-box;
17
+ width:var(--modal-width);
18
+ max-width:var(--modal-width);
19
+ max-height:var(--modal-max-height);
20
+ margin:auto;
21
+ padding:0;
22
+ overflow:hidden;
23
+ border:1px solid var(--modal-border);
24
+ border-radius:var(--modal-radius);
25
+ color:var(--text-color,CanvasText);
26
+ background:var(--modal-surface);
27
+ box-shadow:var(--modal-shadow);
28
+ }
29
+
30
+ dialog.modal::backdrop{
31
+ background:var(--modal-backdrop);
32
+ backdrop-filter:blur(var(--modal-backdrop-blur,0));
33
+ }
34
+
35
+ .modal-shell{
36
+ position:relative;
37
+ display:grid;
38
+ grid-template-rows:auto auto minmax(0,1fr) auto;
39
+ max-height:var(--modal-max-height);
40
+ overflow:hidden;
41
+ }
42
+
43
+ .modal-header:empty,
44
+ .modal-footer:empty{
45
+ display:none;
46
+ }
47
+
48
+ .modal-header,
49
+ .modal-footer{
50
+ padding:var(--modal-region-padding,1em var(--modal-padding));
51
+ }
52
+
53
+ .modal-header{
54
+ border-bottom:1px solid var(--modal-border);
55
+ }
56
+
57
+ .modal-footer{
58
+ border-top:1px solid var(--modal-border);
59
+ }
60
+
61
+ .modal-content{
62
+ box-sizing:border-box;
63
+ min-height:0;
64
+ padding:var(--modal-padding);
65
+ overflow:auto;
66
+ overscroll-behavior:contain;
67
+ }
68
+
69
+ .modal-search{
70
+ box-sizing:border-box;
71
+ width:auto;
72
+ margin:1em var(--modal-padding) 0;
73
+ padding:.65em .75em;
74
+ border:1px solid var(--modal-border);
75
+ border-radius:.4em;
76
+ color:inherit;
77
+ background:var(--input-background,var(--modal-surface));
78
+ }
79
+
80
+ .modal>.modal-shell>.modal-button{
81
+ position:absolute;
82
+ top:.5em;
83
+ right:.5em;
84
+ z-index:2;
85
+ min-width:2.25em;
86
+ min-height:2.25em;
87
+ margin:0;
88
+ padding:.35em;
89
+ border:0;
90
+ border-radius:.4em;
91
+ color:inherit;
92
+ background:transparent;
93
+ box-shadow:none;
94
+ cursor:pointer;
95
+ opacity:.55;
96
+ }
97
+
98
+ .modal-button:hover,
99
+ .modal-button:focus-visible{
100
+ background:var(--secondary-color,rgba(127,127,127,.18));
101
+ opacity:1;
102
+ }
103
+
104
+ .modal-content input,
105
+ .modal-content textarea{
106
+ box-sizing:border-box;
107
+ width:100%;
108
+ max-width:100%;
109
+ }
110
+
111
+ .modal-content h1{
112
+ overflow-wrap:anywhere;
113
+ }
114
+
115
+ .report-progress-list{
116
+ list-style:none;
117
+ margin:2em 0 0;
118
+ padding:0;
119
+ }
120
+
121
+ .report-progress-list li{
122
+ display:flex;
123
+ align-items:center;
124
+ justify-content:space-between;
125
+ gap:2em;
126
+ padding:.75em 0;
127
+ border-bottom:1px solid var(--modal-border);
128
+ }
129
+
130
+ .report-progress-status{white-space:nowrap}
131
+ .report-progress-list li[data-status="complete"] .report-progress-status{color:var(--success-color,green)}
132
+ .report-progress-list li[data-status="failed"] .report-progress-status{color:var(--danger-color,#b00020)}
133
+ .hidden{display:none!important}
134
+
135
+ @media(max-width:36em){
136
+ :host{
137
+ --modal-width:calc(100vw - 1em);
138
+ --modal-max-height:calc(100vh - 1em);
139
+ --modal-padding:1em;
140
+ }
141
+ }
142
+
143
+ @media(prefers-reduced-motion:reduce){
144
+ dialog.modal{scroll-behavior:auto}
145
+ }
146
+ </style>
147
+
148
+ <dialog id="modal" class="modal" part="surface" aria-label="Dialog">
149
+ <div class="modal-shell" part="shell">
150
+ <button id="close" class="modal-button" part="close" type="button" aria-label="Close" title="Close">&#10005;</button>
151
+ <header id="modal-header" class="modal-header" part="header" hidden><slot id="header-slot" name="header"></slot></header>
152
+ <input type="search" id="modal-search" class="modal-search hidden" part="search" placeholder="Search..." aria-label="Search modal content">
153
+ <div id="modal-content" class="modal-content" part="body"><slot name="body"></slot></div>
154
+ <footer id="modal-footer" class="modal-footer" part="footer" hidden><slot id="footer-slot" name="footer"></slot></footer>
155
+ </div>
156
+ </dialog>
157
+
158
+ <script type="module">
159
+ const host=this;
160
+ const shadowRoot=host.shadowRoot;
161
+ const dialog=shadowRoot.querySelector('#modal');
162
+ const modalContent=shadowRoot.querySelector('#modal-content');
163
+ const modalSearch=shadowRoot.querySelector('#modal-search');
164
+ const closeButton=shadowRoot.querySelector('#close');
165
+ const headerSlot=shadowRoot.querySelector('#header-slot');
166
+ const footerSlot=shadowRoot.querySelector('#footer-slot');
167
+ const modalStack=window.modalStack=window.modalStack||[];
168
+
169
+ let running=false;
170
+ let disposed=false;
171
+ let activeRun=Promise.resolve([]);
172
+ let returnFocus=null;
173
+
174
+ host.ready=false;
175
+ host.populate=populate;
176
+ host.open=open;
177
+ host.close=close;
178
+ host.runTasks=runTasks;
179
+
180
+ Object.defineProperties(host,{
181
+ running:{get:function getRunningState(){return running;}},
182
+ opened:{get:function getOpenedState(){return dialog.open;}}
183
+ });
184
+
185
+ dialog.addEventListener('cancel',function preventRunningDialogCancellation(event){
186
+ event.preventDefault();
187
+ close(event);
188
+ });
189
+
190
+ dialog.addEventListener('click',function closeFromDialogBackdrop(event){
191
+ if(event.target!==dialog||running){
192
+ return;
193
+ }
194
+ const bounds=dialog.getBoundingClientRect();
195
+ const inside=event.clientX>=bounds.left
196
+ &&event.clientX<=bounds.right
197
+ &&event.clientY>=bounds.top
198
+ &&event.clientY<=bounds.bottom;
199
+ if(!inside){
200
+ close(event);
201
+ }
202
+ });
203
+
204
+ closeButton.addEventListener('click',function closeFromButton(event){
205
+ close(event);
206
+ });
207
+
208
+ for(const slot of [headerSlot,footerSlot]){
209
+ const region=slot.parentElement;
210
+ function updateSlotVisibility(){region.hidden=slot.assignedNodes({flatten:true}).length===0;}
211
+ slot.addEventListener('slotchange',updateSlotVisibility);
212
+ updateSlotVisibility();
213
+ }
214
+
215
+ modalContent.addEventListener('click',function dispatchModalAction(event){
216
+ const action=event.target.closest('[data-modal-action]');
217
+ if(!action){
218
+ return;
219
+ }
220
+ const detail={...action.dataset};
221
+ detail.action=detail.modalAction;
222
+ delete detail.modalAction;
223
+ host.dispatchEvent(new CustomEvent('modal-action',{detail}));
224
+ });
225
+
226
+ async function open(){
227
+ if(disposed){
228
+ return false;
229
+ }
230
+
231
+ const wasOpen=dialog.open;
232
+ const stackIndex=modalStack.indexOf(host);
233
+ if(stackIndex>-1){
234
+ modalStack.splice(stackIndex,1);
235
+ }
236
+ modalStack.push(host);
237
+
238
+ if(!wasOpen){
239
+ returnFocus=document.activeElement instanceof HTMLElement
240
+ ?document.activeElement
241
+ :null;
242
+ dialog.showModal();
243
+ queueMicrotask(function focusOpenedModal(){
244
+ const focusTarget=modalContent.querySelector('[autofocus],input:not([disabled]),select:not([disabled]),textarea:not([disabled]),button:not([disabled]),a[href]')||closeButton;
245
+ focusTarget?.focus({preventScroll:true});
246
+ });
247
+ host.dispatchEvent(new CustomEvent('modal-opened'));
248
+ }
249
+ return true;
250
+ }
251
+
252
+ async function close(_event,force=false){
253
+ if(disposed){
254
+ return false;
255
+ }
256
+ if(running&&!force){
257
+ return true;
258
+ }
259
+
260
+ const wasOpen=dialog.open;
261
+ if(wasOpen){
262
+ dialog.close();
263
+ }
264
+ closeButton.classList.remove('hidden');
265
+
266
+ const stackIndex=modalStack.indexOf(host);
267
+ if(stackIndex>-1){
268
+ modalStack.splice(stackIndex,1);
269
+ }
270
+
271
+ if(wasOpen){
272
+ host.dispatchEvent(new CustomEvent('modal-closed'));
273
+ const target=returnFocus;
274
+ returnFocus=null;
275
+ queueMicrotask(function restoreModalReturnFocus(){
276
+ if(target?.isConnected){
277
+ target.focus({preventScroll:true});
278
+ }
279
+ });
280
+ }
281
+
282
+ if(host.hasAttribute('data-once')){
283
+ dispose();
284
+ }
285
+ return true;
286
+ }
287
+
288
+ function dispose(){
289
+ if(disposed){
290
+ return;
291
+ }
292
+ disposed=true;
293
+ host.ready=false;
294
+ const stackIndex=modalStack.indexOf(host);
295
+ if(stackIndex>-1){
296
+ modalStack.splice(stackIndex,1);
297
+ }
298
+ if(dialog.open){
299
+ dialog.close();
300
+ }
301
+ host.remove();
302
+ }
303
+
304
+ async function populate(content='<p>Content goes here</p>',search=false){
305
+ closeButton.classList.remove('hidden');
306
+ modalSearch.classList.toggle('hidden',!search);
307
+ if(content instanceof Node){
308
+ modalContent.replaceChildren(content);
309
+ }else{
310
+ modalContent.innerHTML=content;
311
+ }
312
+ const heading=modalContent.querySelector('h1,h2,h3');
313
+ if(heading){
314
+ heading.id=heading.id||`modal-title-${Math.random().toString(36).slice(2)}`;
315
+ dialog.setAttribute('aria-labelledby',heading.id);
316
+ dialog.removeAttribute('aria-label');
317
+ }else{
318
+ dialog.removeAttribute('aria-labelledby');
319
+ dialog.setAttribute('aria-label',host.dataset.label||'Dialog');
320
+ }
321
+ return modalContent;
322
+ }
323
+
324
+ async function runTasks(title='Stand By While Reports Are Generated',jobs=[]){
325
+ if(running){
326
+ return activeRun;
327
+ }
328
+
329
+ const tasks=jobs.filter(function isRunnableTask(job){
330
+ return job&&typeof job.name==='string'&&typeof job.task==='function';
331
+ });
332
+ if(!tasks.length){
333
+ return [];
334
+ }
335
+
336
+ running=true;
337
+ closeButton.classList.add('hidden');
338
+ modalSearch.classList.add('hidden');
339
+ modalContent.replaceChildren();
340
+
341
+ const heading=document.createElement('h2');
342
+ heading.id='modal-title';
343
+ heading.innerText=title;
344
+ dialog.setAttribute('aria-labelledby',heading.id);
345
+ dialog.removeAttribute('aria-label');
346
+ const message=document.createElement('p');
347
+ message.innerText='Please keep this window open until every task is complete.';
348
+ const list=document.createElement('ul');
349
+ list.className='report-progress-list';
350
+ list.setAttribute('aria-live','polite');
351
+
352
+ const rows=tasks.map(function createTaskProgressRow(job){
353
+ const row=document.createElement('li');
354
+ const name=document.createElement('span');
355
+ const status=document.createElement('span');
356
+ row.dataset.status='pending';
357
+ name.innerText=job.name;
358
+ status.className='report-progress-status';
359
+ status.innerText='Working...';
360
+ row.append(name,status);
361
+ list.append(row);
362
+ return {row,status};
363
+ });
364
+
365
+ modalContent.append(heading,message,list);
366
+ await open();
367
+
368
+ activeRun=Promise.allSettled(tasks.map(async function runProgressTask(job,index){
369
+ try{
370
+ const result=await job.task();
371
+ rows[index].row.dataset.status='complete';
372
+ rows[index].status.innerText='Complete';
373
+ return result;
374
+ }catch(error){
375
+ rows[index].row.dataset.status='failed';
376
+ rows[index].status.innerText='Unable to complete';
377
+ console.error(`Unable to complete ${job.name}:`,error);
378
+ throw error;
379
+ }
380
+ }));
381
+
382
+ const results=await activeRun;
383
+ const failed=results.some(function taskWasRejected(result){
384
+ return result.status==='rejected';
385
+ });
386
+ running=false;
387
+ closeButton.classList.remove('hidden');
388
+
389
+ if(failed){
390
+ heading.innerText='Some Tasks Could Not Be Completed';
391
+ message.innerText='You may close this message and try again.';
392
+ return results;
393
+ }
394
+
395
+ heading.innerText='All Tasks Complete';
396
+ message.innerText='Every task completed. You may close this message.';
397
+ return results;
398
+ }
399
+
400
+ host.ready=true;
401
+ host.dispatchEvent(new CustomEvent('modal-ready'));
402
+ </script>
@@ -0,0 +1,259 @@
1
+ <link rel="stylesheet" href="./arcane/css/primitives.css?v=1">
2
+ <style>
3
+ :host{display:block;min-width:0}
4
+ .output-panel{overflow:hidden}
5
+ .title-wrap{display:grid;gap:var(--arcane-space-2);min-width:0}
6
+ .title{overflow-wrap:anywhere}
7
+ .meta{align-items:center;display:flex;flex-wrap:wrap;gap:var(--arcane-space-2)}
8
+ .coverage{color:var(--arcane-muted);font-size:.88rem;overflow-wrap:anywhere}
9
+ .header-actions,.footer-actions{display:flex;flex-wrap:wrap;gap:var(--arcane-space-2)}
10
+ .body{line-height:1.55;min-height:6rem;min-width:0;overflow-wrap:anywhere}
11
+ .body pre{font:inherit;margin:0;overflow-wrap:anywhere;white-space:pre-wrap}
12
+ .state{margin:0}
13
+ @media(max-width:36rem){
14
+ .header-actions{width:100%}
15
+ .header-actions>.arcane-button{flex:1 1 auto}
16
+ }
17
+ </style>
18
+
19
+ <section id="region" class="output-panel arcane-card" aria-label="Output">
20
+ <header class="arcane-card__header">
21
+ <div class="title-wrap">
22
+ <slot name="title"><h2 id="outputTitle" class="title arcane-section-heading">Output</h2></slot>
23
+ <div class="meta">
24
+ <span id="status" class="arcane-badge" hidden></span>
25
+ <slot name="coverage"><span id="coverage" class="coverage"></span></slot>
26
+ </div>
27
+ </div>
28
+ <slot name="header-actions"><div id="headerActions" class="header-actions"></div></slot>
29
+ </header>
30
+ <div class="arcane-card__body">
31
+ <div id="body" class="body" role="region" aria-live="polite">
32
+ <slot name="body" id="bodySlot"></slot>
33
+ <div id="bodyContent">
34
+ <p class="state arcane-state arcane-state--empty">No output yet.</p>
35
+ </div>
36
+ </div>
37
+ </div>
38
+ <footer id="footer" class="arcane-card__footer" hidden>
39
+ <slot name="actions"><div id="footerActions" class="footer-actions"></div></slot>
40
+ </footer>
41
+ </section>
42
+
43
+ <script type="module">
44
+ const host=this;
45
+ const root=host.shadowRoot;
46
+ const region=root.querySelector('#region');
47
+ const title=root.querySelector('#outputTitle');
48
+ const status=root.querySelector('#status');
49
+ const coverage=root.querySelector('#coverage');
50
+ const headerActions=root.querySelector('#headerActions');
51
+ const body=root.querySelector('#body');
52
+ const bodySlot=root.querySelector('#bodySlot');
53
+ const bodyContent=root.querySelector('#bodyContent');
54
+ const footer=root.querySelector('#footer');
55
+ const footerActions=root.querySelector('#footerActions');
56
+
57
+ let actions=[];
58
+ let output=null;
59
+ let options={};
60
+
61
+ host.clear=clear;
62
+ host.configure=configure;
63
+ host.setActions=setActions;
64
+ host.setBody=setBody;
65
+ host.setCoverage=setCoverage;
66
+ host.setError=setError;
67
+ host.setOutput=setOutput;
68
+ host.setPending=setPending;
69
+ host.setStatus=setStatus;
70
+
71
+ Object.defineProperties(host,{
72
+ options:{get:()=>({...options}),set:configure},
73
+ output:{get:()=>output?{...output}:null,set:setOutput}
74
+ });
75
+
76
+ headerActions.addEventListener('click',handleAction);
77
+ footerActions.addEventListener('click',handleAction);
78
+ bodySlot.addEventListener('slotchange',syncBodySlot);
79
+
80
+ function datasetOptions(){
81
+ return {
82
+ ariaLabel:host.dataset.ariaLabel||'Output',
83
+ bodyLabel:host.dataset.bodyLabel||'Output',
84
+ emptyLabel:host.dataset.emptyLabel||'No output yet.',
85
+ title:host.dataset.title||'Output'
86
+ };
87
+ }
88
+
89
+ function configure(input={}){
90
+ options={...datasetOptions(),...options,...input};
91
+ region.setAttribute('aria-label',`${options.ariaLabel||'Output'}`);
92
+ body.setAttribute('aria-label',`${options.bodyLabel||'Output'}`);
93
+ if(!output){
94
+ title.innerText=`${options.title||'Output'}`;
95
+ renderState(options.emptyLabel||'No output yet.','empty');
96
+ }
97
+ return {...options};
98
+ }
99
+
100
+ function setOutput(input={}){
101
+ if(!input){
102
+ clear();
103
+ return null;
104
+ }
105
+ output={...input};
106
+ title.innerText=`${input.title??options.title??'Output'}`;
107
+ setStatus(input.status||'');
108
+ setCoverage(input.coverage||'');
109
+ setActions(input.actions||[]);
110
+ if(input.pending){
111
+ setPending(true,input.pendingMessage||'Working…');
112
+ }else if(input.error){
113
+ setError(input.error);
114
+ }else{
115
+ setBody(input.body??input.content??'');
116
+ }
117
+ emitChange();
118
+ return {...output};
119
+ }
120
+
121
+ function setBody(value=''){
122
+ bodyContent.replaceChildren();
123
+ if(typeof Node!=='undefined'&&value instanceof Node){
124
+ bodyContent.append(value);
125
+ }else if(`${value??''}`){
126
+ const text=document.createElement('pre');
127
+ text.innerText=`${value}`;
128
+ bodyContent.append(text);
129
+ }else{
130
+ renderState(options.emptyLabel||'No output yet.','empty');
131
+ }
132
+ body.setAttribute('aria-busy','false');
133
+ return value;
134
+ }
135
+
136
+ function setCoverage(value=''){
137
+ const next=typeof value==='object'?value:{label:value};
138
+ coverage.innerText=`${next.label??next.text??''}`;
139
+ coverage.hidden=!coverage.innerText;
140
+ return coverage.innerText;
141
+ }
142
+
143
+ function setStatus(value=''){
144
+ const next=typeof value==='object'?value:{label:value,status:value};
145
+ status.innerText=`${next.label||''}`;
146
+ status.dataset.status=`${next.status||''}`;
147
+ status.hidden=!status.innerText;
148
+ return status.innerText;
149
+ }
150
+
151
+ function setActions(values=[]){
152
+ actions=Array.from(values||[]).map((value,index)=>({
153
+ disabled:Boolean(value.disabled),
154
+ id:`${value.id??value.action??`action-${index+1}`}`,
155
+ label:`${value.label??value.title??'Action'}`,
156
+ location:value.location==='header'?'header':'footer',
157
+ variant:`${value.variant??(index?'secondary':'action')}`
158
+ }));
159
+ renderActions(headerActions,actions.filter(action=>action.location==='header'));
160
+ const footerItems=actions.filter(action=>action.location==='footer');
161
+ renderActions(footerActions,footerItems);
162
+ footer.hidden=!footerItems.length;
163
+ return actions.map(action=>({...action}));
164
+ }
165
+
166
+ function renderActions(container,values){
167
+ const fragment=document.createDocumentFragment();
168
+ for(const action of values){
169
+ const button=document.createElement('button');
170
+ button.type='button';
171
+ button.className=`arcane-button ${action.variant==='secondary'?'arcane-button--secondary':action.variant==='tertiary'?'arcane-button--tertiary':''}`.trim();
172
+ button.dataset.outputAction=action.id;
173
+ button.disabled=action.disabled;
174
+ button.innerText=action.label;
175
+ fragment.append(button);
176
+ }
177
+ container.replaceChildren(fragment);
178
+ }
179
+
180
+ function handleAction(event){
181
+ const button=event.target.closest('[data-output-action]');
182
+ const action=actions.find(candidate=>candidate.id===button?.dataset.outputAction);
183
+ if(!button||!action||action.disabled){
184
+ return;
185
+ }
186
+ host.dispatchEvent(new CustomEvent('output-panel-action',{
187
+ bubbles:true,
188
+ cancelable:true,
189
+ composed:true,
190
+ detail:{action:{...action},id:action.id,output:output?{...output}:null}
191
+ }));
192
+ }
193
+
194
+ function setPending(value=true,message='Working…'){
195
+ const pending=Boolean(value);
196
+ body.setAttribute('aria-busy',`${pending}`);
197
+ if(pending){
198
+ renderState(message,'loading');
199
+ }
200
+ host.dispatchEvent(new CustomEvent('output-panel-state',{
201
+ bubbles:true,
202
+ composed:true,
203
+ detail:{pending,state:pending?'loading':'ready'}
204
+ }));
205
+ return pending;
206
+ }
207
+
208
+ function setError(message=''){
209
+ const text=`${message||''}`;
210
+ body.setAttribute('aria-busy','false');
211
+ if(text){
212
+ renderState(text,'error');
213
+ host.dispatchEvent(new CustomEvent('output-panel-error',{
214
+ bubbles:true,
215
+ composed:true,
216
+ detail:{message:text,output:output?{...output}:null}
217
+ }));
218
+ }
219
+ return text;
220
+ }
221
+
222
+ function renderState(message,type){
223
+ const state=document.createElement('p');
224
+ state.className=`state arcane-state arcane-state--${type}`;
225
+ state.innerText=`${message}`;
226
+ bodyContent.replaceChildren(state);
227
+ }
228
+
229
+ function syncBodySlot(){
230
+ bodyContent.hidden=bodySlot.assignedNodes({flatten:true}).length>0;
231
+ }
232
+
233
+ function emitChange(){
234
+ host.dispatchEvent(new CustomEvent('output-panel-change',{
235
+ bubbles:true,
236
+ composed:true,
237
+ detail:{output:output?{...output}:null}
238
+ }));
239
+ }
240
+
241
+ function clear(){
242
+ output=null;
243
+ actions=[];
244
+ title.innerText=`${options.title||'Output'}`;
245
+ setStatus('');
246
+ setCoverage('');
247
+ setActions([]);
248
+ renderState(options.emptyLabel||'No output yet.','empty');
249
+ body.setAttribute('aria-busy','false');
250
+ host.dispatchEvent(new CustomEvent('output-panel-cleared',{bubbles:true,composed:true}));
251
+ return true;
252
+ }
253
+
254
+ configure(datasetOptions());
255
+ clear();
256
+ syncBodySlot();
257
+ host.ready=true;
258
+ host.dispatchEvent(new CustomEvent('output-panel-ready',{bubbles:true,composed:true}));
259
+ </script>