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,360 @@
1
+ <link rel="stylesheet" href="./arcane/css/layout.css?v=3">
2
+ <style>
3
+ :host{
4
+ display:block;
5
+ height:100%;
6
+ min-height:0;
7
+ }
8
+
9
+ .markdown-editor{
10
+ display:grid;
11
+ gap:.75em;
12
+ grid-template-rows:auto minmax(8em,1fr) auto minmax(10em,1fr) auto;
13
+ height:100%;
14
+ min-height:0;
15
+ }
16
+
17
+ .entry-title,
18
+ .entry-markdown{
19
+ box-sizing:border-box;
20
+ margin:0;
21
+ width:100%;
22
+ }
23
+
24
+ .preview{
25
+ background:var(--background);
26
+ border:1px solid var(--border-color);
27
+ border-radius:.5em;
28
+ overflow:auto;
29
+ padding:1em;
30
+ }
31
+
32
+ .preview:empty::before{
33
+ content:attr(data-empty-label);
34
+ opacity:.55;
35
+ }
36
+
37
+ .toolbar,
38
+ .actions{
39
+ display:flex;
40
+ flex-wrap:wrap;
41
+ gap:.35em;
42
+ }
43
+
44
+ .toolbar button,
45
+ .actions button{
46
+ margin:0;
47
+ }
48
+
49
+ .entry-markdown{
50
+ font-family:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", monospace;
51
+ min-height:10em;
52
+ resize:vertical;
53
+ }
54
+
55
+ .actions{
56
+ align-items:center;
57
+ justify-content:flex-end;
58
+ }
59
+
60
+ .status{
61
+ margin-right:auto;
62
+ }
63
+
64
+ .hidden{
65
+ display:none;
66
+ }
67
+ </style>
68
+
69
+ <section class="markdown-editor">
70
+ <input id="entryTitle" class="entry-title" type="text">
71
+ <section id="preview" class="preview"></section>
72
+ <section id="toolbar" class="toolbar"></section>
73
+ <textarea id="entryMarkdown" class="entry-markdown"></textarea>
74
+ <section class="actions">
75
+ <span id="status" class="status" aria-live="polite"></span>
76
+ <button id="save" type="button" disabled></button>
77
+ </section>
78
+ </section>
79
+
80
+ <script type="module">
81
+ const host=this;
82
+ const componentURL=new URL(
83
+ host.getAttribute('href')||'./arcane/components/markdown-editor.html',
84
+ document.baseURI
85
+ );
86
+ const moduleURL=name=>new URL(`../modules/${name}`,componentURL).href;
87
+ const {default:MD}=await import(moduleURL('MD.js?v=2'));
88
+ const {
89
+ applyMarkdownFormat,
90
+ normalizeMarkdownOptions
91
+ }=await import(moduleURL('ComponentContracts.js'));
92
+ const titleInput=host.shadowRoot.querySelector('#entryTitle');
93
+ const preview=host.shadowRoot.querySelector('#preview');
94
+ const toolbar=host.shadowRoot.querySelector('#toolbar');
95
+ const textarea=host.shadowRoot.querySelector('#entryMarkdown');
96
+ const saveButton=host.shadowRoot.querySelector('#save');
97
+ const status=host.shadowRoot.querySelector('#status');
98
+
99
+ let previewFrame=0;
100
+ let options=normalizeMarkdownOptions(optionsFromDataset());
101
+
102
+ host.clear=clear;
103
+ host.configure=configure;
104
+ host.focus=()=>textarea.focus();
105
+ host.saveEntry=saveEntry;
106
+
107
+ Object.defineProperties(
108
+ host,
109
+ {
110
+ entryTitle:{
111
+ get:()=>titleInput.value,
112
+ set:value=>setTitle(value)
113
+ },
114
+ options:{get:getOptions,set:configure},
115
+ value:{get:()=>textarea.value,set:setValue}
116
+ }
117
+ );
118
+
119
+ textarea.addEventListener('input',contentChanged);
120
+ titleInput.addEventListener('input',contentChanged);
121
+ toolbar.addEventListener('click',formatMarkdown);
122
+ saveButton.addEventListener('click',saveEntry);
123
+
124
+ function optionsFromDataset(){
125
+ const dataset=host.dataset||{};
126
+ const mapped={};
127
+ const fields=[
128
+ 'bodyPlaceholder',
129
+ 'previewLabel',
130
+ 'saveLabel',
131
+ 'titlePlaceholder',
132
+ 'toolbarLabel'
133
+ ];
134
+ for(const field of fields){
135
+ if(dataset[field]!==undefined){
136
+ mapped[field]=dataset[field];
137
+ }
138
+ }
139
+ for(const field of [
140
+ 'clearOnSave',
141
+ 'readOnly',
142
+ 'showPreview',
143
+ 'showSave',
144
+ 'showTitle',
145
+ 'showToolbar'
146
+ ]){
147
+ if(dataset[field]!==undefined){
148
+ mapped[field]=dataset[field]==='true';
149
+ }
150
+ }
151
+ return mapped;
152
+ }
153
+
154
+ function configure(input={}){
155
+ const setInitialValue=Object.prototype.hasOwnProperty.call(
156
+ input||{},
157
+ 'initialValue'
158
+ );
159
+ const setInitialTitle=Object.prototype.hasOwnProperty.call(
160
+ input||{},
161
+ 'initialTitle'
162
+ );
163
+ options=normalizeMarkdownOptions(input,options);
164
+ renderOptions();
165
+ if(setInitialTitle){
166
+ titleInput.value=options.initialTitle;
167
+ }
168
+ if(setInitialValue){
169
+ textarea.value=options.initialValue;
170
+ }
171
+ updatePreview();
172
+ return getOptions();
173
+ }
174
+
175
+ function renderOptions(){
176
+ titleInput.placeholder=options.labels.titlePlaceholder;
177
+ textarea.placeholder=options.labels.bodyPlaceholder;
178
+ preview.setAttribute('aria-label',options.labels.preview);
179
+ preview.dataset.emptyLabel=options.labels.preview;
180
+ toolbar.setAttribute('aria-label',options.labels.toolbar);
181
+ saveButton.innerText=options.labels.save;
182
+ titleInput.classList.toggle('hidden',!options.showTitle);
183
+ preview.classList.toggle('hidden',!options.showPreview);
184
+ toolbar.classList.toggle('hidden',!options.showToolbar);
185
+ saveButton.classList.toggle('hidden',!options.showSave);
186
+ titleInput.readOnly=options.readOnly;
187
+ textarea.readOnly=options.readOnly;
188
+ renderToolbar();
189
+ syncSaveButton();
190
+ }
191
+
192
+ function renderToolbar(){
193
+ const fragment=document.createDocumentFragment();
194
+ for(const format of options.formats){
195
+ const button=document.createElement('button');
196
+ button.type='button';
197
+ button.dataset.format=format.id;
198
+ button.title=format.title;
199
+ button.innerText=format.label;
200
+ button.disabled=options.readOnly;
201
+ fragment.append(button);
202
+ }
203
+ toolbar.replaceChildren(fragment);
204
+ }
205
+
206
+ function contentChanged(){
207
+ schedulePreview();
208
+ const detail={
209
+ markdown:textarea.value,
210
+ title:titleInput.value
211
+ };
212
+ host.dispatchEvent(
213
+ new CustomEvent(
214
+ 'markdown-editor-change',
215
+ {bubbles:true,composed:true,detail}
216
+ )
217
+ );
218
+ if(options.onChange){
219
+ Promise.resolve(options.onChange(detail)).catch(
220
+ error=>console.error('Markdown change callback failed:',error)
221
+ );
222
+ }
223
+ }
224
+
225
+ function schedulePreview(){
226
+ if(previewFrame){
227
+ cancelAnimationFrame(previewFrame);
228
+ }
229
+ previewFrame=requestAnimationFrame(updatePreview);
230
+ }
231
+
232
+ function updatePreview(){
233
+ if(previewFrame){
234
+ cancelAnimationFrame(previewFrame);
235
+ }
236
+ previewFrame=0;
237
+ preview.innerHTML=new MD(textarea.value).safeRendered;
238
+ preview.querySelectorAll('a').forEach(
239
+ link=>{
240
+ link.target='_blank';
241
+ link.rel='noopener noreferrer';
242
+ }
243
+ );
244
+ }
245
+
246
+ function formatMarkdown(event){
247
+ if(options.readOnly){
248
+ return;
249
+ }
250
+ const button=event.target.closest('[data-format]');
251
+ const format=options.formats.find(
252
+ candidate=>candidate.id===button?.dataset.format
253
+ );
254
+ if(!button||!format){
255
+ return;
256
+ }
257
+
258
+ const result=applyMarkdownFormat(
259
+ textarea.value,
260
+ textarea.selectionStart,
261
+ textarea.selectionEnd,
262
+ format
263
+ );
264
+ textarea.value=result.value;
265
+ textarea.focus();
266
+ textarea.setSelectionRange(result.selectionStart,result.selectionEnd);
267
+ contentChanged();
268
+ }
269
+
270
+ async function saveEntry(){
271
+ if(options.readOnly||!options.showSave){
272
+ return false;
273
+ }
274
+ const markdown=textarea.value;
275
+ const entryTitle=titleInput.value.trim();
276
+ if(!markdown.trim()){
277
+ status.innerText=options.labels.emptyError;
278
+ textarea.focus();
279
+ return false;
280
+ }
281
+
282
+ const save=options.onSave||(
283
+ typeof host.save==='function'?host.save.bind(host):null
284
+ );
285
+ if(!save){
286
+ status.innerText=options.labels.unavailable;
287
+ return false;
288
+ }
289
+
290
+ saveButton.disabled=true;
291
+ status.innerText=options.labels.saving;
292
+ try{
293
+ await save({title:entryTitle,markdown});
294
+ if(options.clearOnSave){
295
+ clear();
296
+ }
297
+ status.innerText=options.labels.saved;
298
+ host.dispatchEvent(
299
+ new CustomEvent(
300
+ 'markdown-editor-saved',
301
+ {
302
+ bubbles:true,
303
+ composed:true,
304
+ detail:{title:entryTitle,markdown}
305
+ }
306
+ )
307
+ );
308
+ return true;
309
+ }catch(error){
310
+ status.innerText=options.labels.saveError;
311
+ console.error('Unable to save Markdown content:',error);
312
+ return false;
313
+ }finally{
314
+ syncSaveButton();
315
+ }
316
+ }
317
+
318
+ function clear(){
319
+ titleInput.value='';
320
+ textarea.value='';
321
+ updatePreview();
322
+ return true;
323
+ }
324
+
325
+ function setValue(value=''){
326
+ textarea.value=`${value??''}`;
327
+ updatePreview();
328
+ return textarea.value;
329
+ }
330
+
331
+ function setTitle(value=''){
332
+ titleInput.value=`${value??''}`;
333
+ return titleInput.value;
334
+ }
335
+
336
+ function syncSaveButton(){
337
+ saveButton.disabled=options.readOnly||!options.showSave;
338
+ }
339
+
340
+ function getOptions(){
341
+ return {
342
+ ...options,
343
+ labels:{...options.labels},
344
+ formats:options.formats.map(format=>({...format}))
345
+ };
346
+ }
347
+
348
+ renderOptions();
349
+ titleInput.value=options.initialTitle;
350
+ textarea.value=options.initialValue;
351
+ updatePreview();
352
+ status.innerText='';
353
+ host.ready=true;
354
+ host.dispatchEvent(
355
+ new CustomEvent(
356
+ 'markdown-editor-ready',
357
+ {bubbles:true,composed:true}
358
+ )
359
+ );
360
+ </script>
@@ -0,0 +1,8 @@
1
+ <link rel="stylesheet" href="./arcane/css/theme.css?v=1"><link rel="stylesheet" href="./arcane/css/primitives.css?v=1">
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
+ <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
+ host.configure=options=>{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;
6
+ form.addEventListener('submit',event=>{event.preventDefault();load(input.value)});root.querySelector('#platform').addEventListener('click',()=>host.dispatchEvent(new CustomEvent('media-open-platform',{bubbles:true,composed:true,detail:{url:platformUrl}})));
7
+ function load(value){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.';host.dispatchEvent(new CustomEvent('media-load',{bubbles:true,composed:true,detail:{locator,url}}));return locator}catch(error){status.textContent=error.message;frame.hidden=true;empty.hidden=false;host.dispatchEvent(new CustomEvent('media-error',{bubbles:true,composed:true,detail:{error}}));return null}}
8
+ host.ready=true;host.dispatchEvent(new CustomEvent('media-embed-ready',{bubbles:true,composed:true}));</script>