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,264 @@
1
+ <link rel="stylesheet" href="./arcane/css/primitives.css?v=1">
2
+ <style>
3
+ :host{display:block}
4
+ .file-drop{overflow:hidden}
5
+ .drop-zone{
6
+ align-items:center;
7
+ border:2px dashed var(--arcane-border);
8
+ border-radius:var(--arcane-radius-medium);
9
+ display:grid;
10
+ gap:var(--arcane-space-3);
11
+ justify-items:center;
12
+ min-height:9rem;
13
+ padding:var(--arcane-space-5);
14
+ text-align:center;
15
+ transition:background-color 160ms ease,border-color 160ms ease;
16
+ }
17
+ .drop-zone[data-drag-active="true"]{
18
+ background:color-mix(in srgb,var(--arcane-action) 9%,var(--arcane-surface));
19
+ border-color:var(--arcane-action);
20
+ }
21
+ .drop-zone[aria-busy="true"]{cursor:wait;opacity:.72}
22
+ .drop-title{font-weight:700;margin:0}
23
+ .drop-hint{color:var(--arcane-muted);margin:0;max-width:36rem}
24
+ input[type="file"]{display:none}
25
+ .progress-wrap{display:grid;gap:var(--arcane-space-2);padding-top:var(--arcane-space-3)}
26
+ progress{accent-color:var(--arcane-action);width:100%}
27
+ .status{min-height:1.4em}
28
+ </style>
29
+
30
+ <section class="file-drop arcane-card" aria-labelledby="fileDropTitle">
31
+ <div id="dropZone" class="drop-zone">
32
+ <p id="fileDropTitle" class="drop-title">Add files</p>
33
+ <p id="fileDropHint" class="drop-hint">Drop files here or choose them from this device.</p>
34
+ <button id="choose" class="arcane-button" type="button">Choose files</button>
35
+ <input id="picker" type="file" aria-describedby="fileDropHint">
36
+ </div>
37
+ <div id="feedback" class="arcane-card__body" hidden>
38
+ <div id="progressWrap" class="progress-wrap" hidden>
39
+ <progress id="progress" max="100"></progress>
40
+ <span id="progressLabel"></span>
41
+ </div>
42
+ <p id="status" class="status" role="status" aria-live="polite"></p>
43
+ </div>
44
+ </section>
45
+
46
+ <script type="module">
47
+ const host=this;
48
+ const root=host.shadowRoot;
49
+ const dropZone=root.querySelector('#dropZone');
50
+ const title=root.querySelector('#fileDropTitle');
51
+ const hint=root.querySelector('#fileDropHint');
52
+ const choose=root.querySelector('#choose');
53
+ const picker=root.querySelector('#picker');
54
+ const feedback=root.querySelector('#feedback');
55
+ const progressWrap=root.querySelector('#progressWrap');
56
+ const progressElement=root.querySelector('#progress');
57
+ const progressLabel=root.querySelector('#progressLabel');
58
+ const statusElement=root.querySelector('#status');
59
+
60
+ let dragDepth=0;
61
+ let busy=false;
62
+ let currentFiles=[];
63
+ let progress=null;
64
+ let options={};
65
+
66
+ host.clear=clear;
67
+ host.configure=configure;
68
+ host.openPicker=openPicker;
69
+ host.setBusy=setBusy;
70
+ host.setError=setError;
71
+ host.setProgress=setProgress;
72
+
73
+ Object.defineProperties(host,{
74
+ busy:{get:()=>busy,set:setBusy},
75
+ files:{get:()=>currentFiles.slice()},
76
+ options:{get:getOptions,set:configure},
77
+ progress:{get:()=>progress,set:setProgress}
78
+ });
79
+
80
+ choose.addEventListener('click',openPicker);
81
+ picker.addEventListener('change',()=>acceptFiles(picker.files,'picker'));
82
+ dropZone.addEventListener('dragenter',dragEnter);
83
+ dropZone.addEventListener('dragover',dragOver);
84
+ dropZone.addEventListener('dragleave',dragLeave);
85
+ dropZone.addEventListener('drop',dropFiles);
86
+
87
+ function datasetOptions(){
88
+ return {
89
+ accept:host.dataset.accept||'',
90
+ chooseLabel:host.dataset.chooseLabel||'Choose files',
91
+ hint:host.dataset.hint||'Drop files here or choose them from this device.',
92
+ maxFiles:numberOr(host.dataset.maxFiles,0),
93
+ multiple:host.dataset.multiple!=='false',
94
+ title:host.dataset.title||'Add files'
95
+ };
96
+ }
97
+
98
+ function configure(input={}){
99
+ const previous={...datasetOptions(),...options};
100
+ options={
101
+ ...previous,
102
+ ...input,
103
+ accept:`${input.accept??previous.accept??''}`,
104
+ maxFiles:numberOr(input.maxFiles??previous.maxFiles,0),
105
+ multiple:input.multiple===undefined?Boolean(previous.multiple):Boolean(input.multiple)
106
+ };
107
+ title.innerText=`${options.title||'Add files'}`;
108
+ hint.innerText=`${options.hint||''}`;
109
+ choose.innerText=`${options.chooseLabel||'Choose files'}`;
110
+ picker.multiple=options.multiple;
111
+ if(options.accept){
112
+ picker.accept=options.accept;
113
+ }else{
114
+ picker.removeAttribute('accept');
115
+ }
116
+ return getOptions();
117
+ }
118
+
119
+ function getOptions(){
120
+ return {...options};
121
+ }
122
+
123
+ function openPicker(){
124
+ if(busy){
125
+ return false;
126
+ }
127
+ picker.click();
128
+ return true;
129
+ }
130
+
131
+ function dragEnter(event){
132
+ event.preventDefault();
133
+ if(busy){
134
+ return;
135
+ }
136
+ dragDepth+=1;
137
+ dropZone.dataset.dragActive='true';
138
+ }
139
+
140
+ function dragOver(event){
141
+ event.preventDefault();
142
+ if(event.dataTransfer){
143
+ event.dataTransfer.dropEffect=busy?'none':'copy';
144
+ }
145
+ }
146
+
147
+ function dragLeave(event){
148
+ event.preventDefault();
149
+ dragDepth=Math.max(0,dragDepth-1);
150
+ if(!dragDepth){
151
+ dropZone.dataset.dragActive='false';
152
+ }
153
+ }
154
+
155
+ function dropFiles(event){
156
+ event.preventDefault();
157
+ dragDepth=0;
158
+ dropZone.dataset.dragActive='false';
159
+ if(busy){
160
+ return;
161
+ }
162
+ acceptFiles(event.dataTransfer?.files||[],'drop');
163
+ }
164
+
165
+ function acceptFiles(fileList=[],source='api'){
166
+ const files=Array.from(fileList||[]).filter(Boolean);
167
+ if(!files.length){
168
+ return false;
169
+ }
170
+ if(options.maxFiles>0&&files.length>options.maxFiles){
171
+ setError(`Select no more than ${options.maxFiles} file${options.maxFiles===1?'':'s'}.`);
172
+ return false;
173
+ }
174
+ currentFiles=options.multiple?files:files.slice(0,1);
175
+ setError('');
176
+ feedback.hidden=false;
177
+ statusElement.className='status';
178
+ statusElement.innerText=`${currentFiles.length} file${currentFiles.length===1?'':'s'} selected.`;
179
+ host.dispatchEvent(new CustomEvent('file-drop-selected',{
180
+ bubbles:true,
181
+ cancelable:false,
182
+ composed:true,
183
+ detail:{files:currentFiles.slice(),source}
184
+ }));
185
+ return currentFiles.slice();
186
+ }
187
+
188
+ function setBusy(value=true,message=''){
189
+ busy=Boolean(value);
190
+ choose.disabled=busy;
191
+ picker.disabled=busy;
192
+ dropZone.setAttribute('aria-busy',`${busy}`);
193
+ host.toggleAttribute('data-busy',busy);
194
+ if(message){
195
+ feedback.hidden=false;
196
+ statusElement.className='status';
197
+ statusElement.innerText=`${message}`;
198
+ }
199
+ host.dispatchEvent(new CustomEvent('file-drop-state',{
200
+ bubbles:true,
201
+ composed:true,
202
+ detail:{busy,progress}
203
+ }));
204
+ return busy;
205
+ }
206
+
207
+ function setProgress(value=null,label=''){
208
+ const numeric=Number(value);
209
+ progress=value===null||value===undefined||!Number.isFinite(numeric)
210
+ ?null
211
+ :Math.min(100,Math.max(0,numeric));
212
+ feedback.hidden=progress===null&&!statusElement.innerText;
213
+ progressWrap.hidden=progress===null;
214
+ if(progress!==null){
215
+ progressElement.value=progress;
216
+ progressLabel.innerText=label||`${Math.round(progress)}%`;
217
+ }else{
218
+ progressElement.removeAttribute('value');
219
+ progressLabel.innerText='';
220
+ }
221
+ host.dispatchEvent(new CustomEvent('file-drop-progress',{
222
+ bubbles:true,
223
+ composed:true,
224
+ detail:{progress,label:progressLabel.innerText}
225
+ }));
226
+ return progress;
227
+ }
228
+
229
+ function setError(message=''){
230
+ const text=`${message||''}`;
231
+ feedback.hidden=!text&&progress===null;
232
+ statusElement.innerText=text;
233
+ statusElement.className=text?'status arcane-error':'status';
234
+ if(text){
235
+ host.dispatchEvent(new CustomEvent('file-drop-error',{
236
+ bubbles:true,
237
+ composed:true,
238
+ detail:{message:text}
239
+ }));
240
+ }
241
+ return text;
242
+ }
243
+
244
+ function clear(){
245
+ currentFiles=[];
246
+ picker.value='';
247
+ setBusy(false);
248
+ setProgress(null);
249
+ setError('');
250
+ feedback.hidden=true;
251
+ return true;
252
+ }
253
+
254
+ function numberOr(value,fallback){
255
+ const numeric=Number(value);
256
+ return Number.isFinite(numeric)&&numeric>=0?numeric:fallback;
257
+ }
258
+
259
+ configure(datasetOptions());
260
+ dropZone.dataset.dragActive='false';
261
+ setBusy(false);
262
+ host.ready=true;
263
+ host.dispatchEvent(new CustomEvent('file-drop-ready',{bubbles:true,composed:true}));
264
+ </script>
@@ -0,0 +1,293 @@
1
+ <link rel="stylesheet" href="./arcane/css/primitives.css?v=1">
2
+ <style>
3
+ :host{display:block;min-width:0}
4
+ .inspector{overflow:hidden}
5
+ .title-wrap{display:grid;gap:var(--arcane-space-1);min-width:0}
6
+ .title,.path{overflow-wrap:anywhere}
7
+ .path{color:var(--arcane-muted);font-size:.86rem;margin:0}
8
+ .status{flex:0 0 auto}
9
+ .metadata{
10
+ display:grid;
11
+ gap:var(--arcane-space-3);
12
+ grid-template-columns:repeat(auto-fit,minmax(min(100%,9rem),1fr));
13
+ margin:0;
14
+ }
15
+ .metadata>div{display:grid;gap:var(--arcane-space-1);min-width:0}
16
+ .metadata dt{color:var(--arcane-muted);font-size:.8rem;font-weight:650;text-transform:uppercase}
17
+ .metadata dd{margin:0;overflow-wrap:anywhere}
18
+ .preview-shell{
19
+ background:var(--arcane-surface);
20
+ border:1px solid var(--arcane-border);
21
+ border-radius:var(--arcane-radius-medium);
22
+ margin-top:var(--arcane-space-4);
23
+ max-height:32rem;
24
+ min-height:8rem;
25
+ overflow:auto;
26
+ padding:var(--arcane-space-4);
27
+ }
28
+ .preview-shell pre{font:inherit;margin:0;overflow-wrap:anywhere;white-space:pre-wrap}
29
+ .preview-empty{color:var(--arcane-muted);margin:0}
30
+ .actions{display:flex;flex-wrap:wrap;gap:var(--arcane-space-2)}
31
+ .state{margin:var(--arcane-space-4)}
32
+ </style>
33
+
34
+ <section id="region" class="inspector arcane-card" aria-label="File inspector">
35
+ <p id="empty" class="state arcane-state arcane-state--empty">Select an item to inspect.</p>
36
+ <div id="content" hidden>
37
+ <header class="arcane-card__header">
38
+ <div class="title-wrap">
39
+ <slot name="title"><h2 id="inspectorTitle" class="title arcane-section-heading"></h2></slot>
40
+ <p id="path" class="path"></p>
41
+ </div>
42
+ <span id="status" class="status arcane-badge" hidden></span>
43
+ </header>
44
+ <div class="arcane-card__body">
45
+ <slot name="metadata"><dl id="metadata" class="metadata"></dl></slot>
46
+ <div id="previewShell" class="preview-shell" aria-label="Preview">
47
+ <slot name="preview"><div id="preview"></div></slot>
48
+ </div>
49
+ </div>
50
+ <footer id="footer" class="arcane-card__footer" hidden>
51
+ <slot name="actions"><div id="actions" class="actions"></div></slot>
52
+ </footer>
53
+ </div>
54
+ </section>
55
+
56
+ <script type="module">
57
+ const host=this;
58
+ const root=host.shadowRoot;
59
+ const region=root.querySelector('#region');
60
+ const empty=root.querySelector('#empty');
61
+ const content=root.querySelector('#content');
62
+ const title=root.querySelector('#inspectorTitle');
63
+ const path=root.querySelector('#path');
64
+ const status=root.querySelector('#status');
65
+ const metadata=root.querySelector('#metadata');
66
+ const previewShell=root.querySelector('#previewShell');
67
+ const preview=root.querySelector('#preview');
68
+ const footer=root.querySelector('#footer');
69
+ const actions=root.querySelector('#actions');
70
+
71
+ let actionItems=[];
72
+ let current=null;
73
+ let options={};
74
+
75
+ host.clear=clear;
76
+ host.configure=configure;
77
+ host.setActions=setActions;
78
+ host.setBusy=setBusy;
79
+ host.setError=setError;
80
+ host.setPreview=setPreview;
81
+ host.show=show;
82
+
83
+ Object.defineProperties(host,{
84
+ file:{get:()=>current?{...current}:null,set:show},
85
+ options:{get:()=>({...options}),set:configure}
86
+ });
87
+
88
+ actions.addEventListener('click',handleAction);
89
+
90
+ function datasetOptions(){
91
+ return {
92
+ ariaLabel:host.dataset.ariaLabel||'File inspector',
93
+ emptyLabel:host.dataset.emptyLabel||'Select an item to inspect.',
94
+ previewLabel:host.dataset.previewLabel||'Preview'
95
+ };
96
+ }
97
+
98
+ function configure(input={}){
99
+ options={...datasetOptions(),...options,...input};
100
+ region.setAttribute('aria-label',`${options.ariaLabel||'File inspector'}`);
101
+ empty.innerText=`${options.emptyLabel||'Select an item to inspect.'}`;
102
+ previewShell.setAttribute('aria-label',`${options.previewLabel||'Preview'}`);
103
+ return {...options};
104
+ }
105
+
106
+ function show(input={}){
107
+ if(!input){
108
+ clear();
109
+ return null;
110
+ }
111
+ current={...input};
112
+ empty.hidden=true;
113
+ content.hidden=false;
114
+ title.innerText=`${input.title??input.name??input.path??'Item'}`;
115
+ path.innerText=`${input.path??''}`;
116
+ path.hidden=!path.innerText;
117
+ setStatus(input.status||'');
118
+ renderMetadata(input.metadata??defaultMetadata(input));
119
+ setActions(input.actions||[]);
120
+ setPreview(input.preview??input.content??'');
121
+ host.dispatchEvent(new CustomEvent('file-inspector-change',{
122
+ bubbles:true,
123
+ composed:true,
124
+ detail:{file:{...current}}
125
+ }));
126
+ return {...current};
127
+ }
128
+
129
+ function defaultMetadata(input={}){
130
+ return [
131
+ ['Type',input.mimeType||input.type||''],
132
+ ['Size',formatSize(input.size)],
133
+ ['Modified',formatDate(input.lastModified)]
134
+ ].filter(([,value])=>value);
135
+ }
136
+
137
+ function renderMetadata(input=[]){
138
+ const entries=Array.isArray(input)
139
+ ?input.map(entry=>Array.isArray(entry)?entry:[entry.label,entry.value])
140
+ :Object.entries(input||{});
141
+ const fragment=document.createDocumentFragment();
142
+ for(const [label,value] of entries){
143
+ if(value===undefined||value===null||value===''){
144
+ continue;
145
+ }
146
+ const group=document.createElement('div');
147
+ const term=document.createElement('dt');
148
+ const description=document.createElement('dd');
149
+ term.innerText=`${label}`;
150
+ description.innerText=`${value}`;
151
+ group.append(term,description);
152
+ fragment.append(group);
153
+ }
154
+ metadata.replaceChildren(fragment);
155
+ metadata.hidden=!metadata.children.length;
156
+ }
157
+
158
+ function setPreview(value=''){
159
+ preview.replaceChildren();
160
+ if(typeof Node!=='undefined'&&value instanceof Node){
161
+ preview.append(value);
162
+ }else if(`${value??''}`){
163
+ const text=document.createElement('pre');
164
+ text.innerText=`${value}`;
165
+ preview.append(text);
166
+ }else{
167
+ const message=document.createElement('p');
168
+ message.className='preview-empty';
169
+ message.innerText='No preview available.';
170
+ preview.append(message);
171
+ }
172
+ return value;
173
+ }
174
+
175
+ function setActions(values=[]){
176
+ actionItems=Array.from(values||[]).map((value,index)=>({
177
+ disabled:Boolean(value.disabled),
178
+ id:`${value.id??value.action??`action-${index+1}`}`,
179
+ label:`${value.label??value.title??'Action'}`,
180
+ variant:`${value.variant??(index?'secondary':'action')}`
181
+ }));
182
+ const fragment=document.createDocumentFragment();
183
+ for(const action of actionItems){
184
+ const button=document.createElement('button');
185
+ button.type='button';
186
+ button.className=`arcane-button ${action.variant==='secondary'?'arcane-button--secondary':action.variant==='tertiary'?'arcane-button--tertiary':''}`.trim();
187
+ button.dataset.inspectorAction=action.id;
188
+ button.disabled=action.disabled;
189
+ button.innerText=action.label;
190
+ fragment.append(button);
191
+ }
192
+ actions.replaceChildren(fragment);
193
+ footer.hidden=!actionItems.length;
194
+ return actionItems.map(action=>({...action}));
195
+ }
196
+
197
+ function handleAction(event){
198
+ const button=event.target.closest('[data-inspector-action]');
199
+ const action=actionItems.find(candidate=>candidate.id===button?.dataset.inspectorAction);
200
+ if(!button||!action||action.disabled){
201
+ return;
202
+ }
203
+ host.dispatchEvent(new CustomEvent('file-inspector-action',{
204
+ bubbles:true,
205
+ cancelable:true,
206
+ composed:true,
207
+ detail:{action:{...action},file:current?{...current}:null,id:action.id}
208
+ }));
209
+ }
210
+
211
+ function setStatus(value=''){
212
+ const next=typeof value==='object'?value:{label:value,status:value};
213
+ status.innerText=`${next.label||''}`;
214
+ status.dataset.status=`${next.status||''}`;
215
+ status.hidden=!status.innerText;
216
+ }
217
+
218
+ function setBusy(value=true,message='Loading preview…'){
219
+ const busy=Boolean(value);
220
+ previewShell.setAttribute('aria-busy',`${busy}`);
221
+ if(busy){
222
+ preview.replaceChildren();
223
+ const state=document.createElement('p');
224
+ state.className='arcane-state arcane-state--loading';
225
+ state.innerText=`${message}`;
226
+ preview.append(state);
227
+ }
228
+ return busy;
229
+ }
230
+
231
+ function setError(message=''){
232
+ const text=`${message||''}`;
233
+ preview.replaceChildren();
234
+ if(text){
235
+ const state=document.createElement('p');
236
+ state.className='arcane-state arcane-state--error';
237
+ state.innerText=text;
238
+ preview.append(state);
239
+ host.dispatchEvent(new CustomEvent('file-inspector-error',{
240
+ bubbles:true,
241
+ composed:true,
242
+ detail:{file:current?{...current}:null,message:text}
243
+ }));
244
+ }
245
+ return text;
246
+ }
247
+
248
+ function formatSize(value){
249
+ const bytes=Number(value);
250
+ if(!Number.isFinite(bytes)||bytes<0){
251
+ return '';
252
+ }
253
+ if(bytes<1024){
254
+ return `${bytes} B`;
255
+ }
256
+ const units=['KB','MB','GB','TB'];
257
+ let amount=bytes/1024;
258
+ let unit=0;
259
+ while(amount>=1024&&unit<units.length-1){
260
+ amount/=1024;
261
+ unit+=1;
262
+ }
263
+ return `${amount.toFixed(amount>=10?1:2)} ${units[unit]}`;
264
+ }
265
+
266
+ function formatDate(value){
267
+ if(value===undefined||value===null||value===''){
268
+ return '';
269
+ }
270
+ const date=new Date(value);
271
+ return Number.isNaN(date.getTime())?'':date.toLocaleString();
272
+ }
273
+
274
+ function clear(){
275
+ current=null;
276
+ actionItems=[];
277
+ content.hidden=true;
278
+ empty.hidden=false;
279
+ title.innerText='';
280
+ path.innerText='';
281
+ metadata.replaceChildren();
282
+ preview.replaceChildren();
283
+ actions.replaceChildren();
284
+ footer.hidden=true;
285
+ host.dispatchEvent(new CustomEvent('file-inspector-cleared',{bubbles:true,composed:true}));
286
+ return true;
287
+ }
288
+
289
+ configure(datasetOptions());
290
+ clear();
291
+ host.ready=true;
292
+ host.dispatchEvent(new CustomEvent('file-inspector-ready',{bubbles:true,composed:true}));
293
+ </script>