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,1048 @@
1
+ <link rel="stylesheet" href="./arcane/css/layout.css?v=3">
2
+ <link rel="stylesheet" href="./arcane/css/theme.css?v=1">
3
+ <link rel="stylesheet" href="./arcane/css/primitives.css?v=1">
4
+
5
+ <style>
6
+ :host{
7
+ color:var(--text-color);
8
+ display:block;
9
+ min-width:0;
10
+ }
11
+
12
+ [hidden]{
13
+ display:none !important;
14
+ }
15
+
16
+ .markdown-document{
17
+ min-width:0;
18
+ }
19
+
20
+ .document-state{
21
+ background:var(--secondary-color);
22
+ border:1px solid var(--border-color);
23
+ border-radius:.5rem;
24
+ color:var(--muted-text-color);
25
+ margin:0;
26
+ padding:1rem;
27
+ }
28
+
29
+ .document-state[data-state="error"]{
30
+ border-inline-start:.3rem solid var(--danger-color);
31
+ color:var(--text-color);
32
+ }
33
+
34
+ .table-of-contents{
35
+ background:var(--secondary-color);
36
+ border:1px solid var(--border-color);
37
+ border-radius:.5rem;
38
+ margin-block:0 1.5rem;
39
+ padding:1rem 1.25rem;
40
+ }
41
+
42
+ .table-of-contents h2{
43
+ font-size:1rem;
44
+ margin:0 0 .6rem;
45
+ }
46
+
47
+ .table-of-contents ol{
48
+ margin:0;
49
+ padding-inline-start:1.5rem;
50
+ }
51
+
52
+ .table-of-contents li+li{
53
+ margin-block-start:.35rem;
54
+ }
55
+
56
+ .table-of-contents li[data-level="3"]{
57
+ margin-inline-start:1rem;
58
+ }
59
+
60
+ .table-of-contents li[data-level="4"],
61
+ .table-of-contents li[data-level="5"],
62
+ .table-of-contents li[data-level="6"]{
63
+ margin-inline-start:2rem;
64
+ }
65
+
66
+ .document-content{
67
+ line-height:1.65;
68
+ min-width:0;
69
+ overflow-wrap:break-word;
70
+ }
71
+
72
+ .document-content:focus{
73
+ outline:none;
74
+ }
75
+
76
+ .document-content :where(h1,h2,h3,h4,h5,h6){
77
+ line-height:1.25;
78
+ scroll-margin-block-start:1rem;
79
+ }
80
+
81
+ .document-content :where(h1,h2,h3,h4,h5,h6):focus{
82
+ border-radius:.25rem;
83
+ outline:3px solid var(--focus-color);
84
+ outline-offset:.2rem;
85
+ }
86
+
87
+ .document-content a,
88
+ .table-of-contents a{
89
+ color:var(--focus-color);
90
+ text-decoration-thickness:.08em;
91
+ text-underline-offset:.15em;
92
+ }
93
+
94
+ .document-content a:focus-visible,
95
+ .table-of-contents a:focus-visible{
96
+ border-radius:.2rem;
97
+ outline:3px solid var(--focus-color);
98
+ outline-offset:.2rem;
99
+ }
100
+
101
+ .document-content blockquote{
102
+ border-inline-start:.25rem solid var(--border-color);
103
+ color:var(--muted-text-color);
104
+ margin-inline:0;
105
+ padding-inline-start:1rem;
106
+ }
107
+
108
+ .document-content :where(code,kbd){
109
+ background:var(--secondary-color);
110
+ border-radius:.25rem;
111
+ font-family:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", monospace;
112
+ padding:.08em .3em;
113
+ }
114
+
115
+ .document-content pre{
116
+ background:var(--secondary-color);
117
+ border:1px solid var(--border-color);
118
+ border-radius:.5rem;
119
+ overflow:auto;
120
+ padding:1rem;
121
+ }
122
+
123
+ .document-content pre code{
124
+ background:transparent;
125
+ padding:0;
126
+ }
127
+
128
+ .document-content img{
129
+ block-size:auto;
130
+ border-radius:.35rem;
131
+ max-inline-size:100%;
132
+ }
133
+
134
+ .document-content table{
135
+ border-collapse:collapse;
136
+ display:block;
137
+ inline-size:100%;
138
+ max-inline-size:100%;
139
+ overflow-x:auto;
140
+ overscroll-behavior-inline:contain;
141
+ }
142
+
143
+ .document-content table :where(code,kbd){
144
+ overflow-wrap:normal;
145
+ white-space:normal;
146
+ word-break:normal;
147
+ }
148
+
149
+ .document-content table:focus-visible{
150
+ outline:3px solid var(--focus-color);
151
+ outline-offset:.2rem;
152
+ }
153
+
154
+ .document-content :where(th,td){
155
+ border:1px solid var(--border-color);
156
+ padding:.5rem;
157
+ text-align:start;
158
+ vertical-align:top;
159
+ }
160
+
161
+ .document-content th{
162
+ background:var(--secondary-color);
163
+ }
164
+
165
+ @media (forced-colors:active){
166
+ .document-state,
167
+ .table-of-contents,
168
+ .document-content pre,
169
+ .document-content :where(th,td){
170
+ border-color:CanvasText;
171
+ }
172
+
173
+ .document-content :where(h1,h2,h3,h4,h5,h6):focus,
174
+ .document-content a:focus-visible,
175
+ .document-content table:focus-visible,
176
+ .table-of-contents a:focus-visible{
177
+ outline-color:Highlight;
178
+ }
179
+ }
180
+ </style>
181
+
182
+ <section id="document" class="markdown-document" part="container" aria-busy="false">
183
+ <p
184
+ id="status"
185
+ class="document-state"
186
+ part="status"
187
+ role="status"
188
+ aria-live="polite"
189
+ aria-atomic="true"
190
+ tabindex="-1"
191
+ ></p>
192
+
193
+ <nav
194
+ id="tableOfContents"
195
+ class="table-of-contents"
196
+ part="table-of-contents"
197
+ aria-labelledby="tableOfContentsTitle"
198
+ hidden
199
+ >
200
+ <h2 id="tableOfContentsTitle"></h2>
201
+ <ol id="tableOfContentsList"></ol>
202
+ </nav>
203
+
204
+ <article
205
+ id="content"
206
+ class="document-content"
207
+ part="content"
208
+ tabindex="-1"
209
+ hidden
210
+ ></article>
211
+ </section>
212
+
213
+ <script type="module">
214
+ const host=this;
215
+ host.ready=false;
216
+
217
+ const componentURL=new URL(
218
+ host.getAttribute('href')||'./arcane/components/markdown-document.html',
219
+ document.baseURI
220
+ );
221
+ const moduleURL=name=>new URL(`../modules/${name}`,componentURL).href;
222
+ const {default:MD}=await import(moduleURL('MD.js?v=2'));
223
+
224
+ const documentElement=host.shadowRoot.querySelector('#document');
225
+ const statusElement=host.shadowRoot.querySelector('#status');
226
+ const tableOfContentsElement=host.shadowRoot.querySelector('#tableOfContents');
227
+ const tableOfContentsTitle=host.shadowRoot.querySelector('#tableOfContentsTitle');
228
+ const tableOfContentsList=host.shadowRoot.querySelector('#tableOfContentsList');
229
+ const contentElement=host.shadowRoot.querySelector('#content');
230
+
231
+ // BEGIN MARKDOWN_DOCUMENT_POLICY
232
+ const MARKDOWN_DOCUMENT_ALLOWED_ELEMENTS=Object.freeze([
233
+ 'A','ABBR','BLOCKQUOTE','BR','CODE','DEL','EM',
234
+ 'H1','H2','H3','H4','H5','H6','HR','IMG','KBD','LI',
235
+ 'OL','P','PRE','S','STRONG','SUB','SUP','TABLE','TBODY',
236
+ 'TD','TFOOT','TH','THEAD','TR','UL'
237
+ ]);
238
+ const MARKDOWN_DOCUMENT_ALLOWED_ATTRIBUTES=Object.freeze(
239
+ {
240
+ A:Object.freeze(['href','title']),
241
+ ABBR:Object.freeze(['title']),
242
+ CODE:Object.freeze(['class']),
243
+ IMG:Object.freeze(['alt','src','title']),
244
+ LI:Object.freeze(['value']),
245
+ OL:Object.freeze(['start']),
246
+ TD:Object.freeze(['colspan','rowspan']),
247
+ TH:Object.freeze(['colspan','rowspan','scope'])
248
+ }
249
+ );
250
+ const MARKDOWN_DOCUMENT_LINK_PROTOCOLS=new Set(['http:','https:','mailto:']);
251
+ const MARKDOWN_DOCUMENT_ASSET_PROTOCOLS=new Set(['http:','https:']);
252
+
253
+ function markdownDocumentElementAllowed(name=''){
254
+ return MARKDOWN_DOCUMENT_ALLOWED_ELEMENTS.includes(
255
+ String(name||'').toUpperCase()
256
+ );
257
+ }
258
+
259
+ function markdownDocumentAllowedAttributes(name=''){
260
+ return MARKDOWN_DOCUMENT_ALLOWED_ATTRIBUTES[
261
+ String(name||'').toUpperCase()
262
+ ]||Object.freeze([]);
263
+ }
264
+
265
+ function markdownDocumentCleanURLInput(value=''){
266
+ const input=String(value??'').trim();
267
+ if(!input||/[\u0000-\u001F\u007F]/.test(input)){
268
+ return '';
269
+ }
270
+ return input;
271
+ }
272
+
273
+ function markdownDocumentDecodeFragment(value=''){
274
+ try{
275
+ return decodeURIComponent(String(value||''));
276
+ }catch{
277
+ return String(value||'');
278
+ }
279
+ }
280
+
281
+ function markdownDocumentSourceURL(value='',baseURL='',pageOrigin=''){
282
+ const fallback=baseURL||document.baseURI;
283
+ const expectedOrigin=pageOrigin
284
+ ||globalThis.location?.origin
285
+ ||new URL(fallback).origin;
286
+ const input=markdownDocumentCleanURLInput(value||fallback);
287
+ if(!input){
288
+ return '';
289
+ }
290
+
291
+ try{
292
+ const url=new URL(input,fallback);
293
+ if(
294
+ !MARKDOWN_DOCUMENT_ASSET_PROTOCOLS.has(url.protocol)
295
+ ||url.origin!==expectedOrigin
296
+ ||url.username
297
+ ||url.password
298
+ ){
299
+ return '';
300
+ }
301
+ return url.href;
302
+ }catch{
303
+ return '';
304
+ }
305
+ }
306
+
307
+ function markdownDocumentLinkPolicy(value='',sourceURL='',pageOrigin=''){
308
+ const input=markdownDocumentCleanURLInput(value);
309
+ if(!input){
310
+ return null;
311
+ }
312
+
313
+ const expectedOrigin=pageOrigin
314
+ ||globalThis.location?.origin
315
+ ||new URL(sourceURL).origin;
316
+
317
+ if(input.startsWith('#')){
318
+ const fragment=markdownDocumentDecodeFragment(input.slice(1))
319
+ .replace(/[\u0000-\u001F\u007F]/g,'')
320
+ .slice(0,256);
321
+ if(!fragment){
322
+ return null;
323
+ }
324
+ return Object.freeze(
325
+ {
326
+ external:false,
327
+ fragment,
328
+ href:`#${encodeURIComponent(fragment)}`,
329
+ kind:'fragment',
330
+ targetURL:new URL(`#${encodeURIComponent(fragment)}`,sourceURL).href
331
+ }
332
+ );
333
+ }
334
+
335
+ try{
336
+ const url=new URL(input,sourceURL);
337
+ if(
338
+ !MARKDOWN_DOCUMENT_LINK_PROTOCOLS.has(url.protocol)
339
+ ||url.username
340
+ ||url.password
341
+ ){
342
+ return null;
343
+ }
344
+
345
+ const sameOrigin=url.origin===expectedOrigin;
346
+ const markdown=sameOrigin&&/\.(?:md|markdown)$/i.test(url.pathname);
347
+ return Object.freeze(
348
+ {
349
+ external:!sameOrigin,
350
+ fragment:markdownDocumentDecodeFragment(url.hash.slice(1)).slice(0,256),
351
+ href:url.href,
352
+ kind:markdown?'markdown':'link',
353
+ targetURL:url.href
354
+ }
355
+ );
356
+ }catch{
357
+ return null;
358
+ }
359
+ }
360
+
361
+ function markdownDocumentAssetURL(value='',sourceURL='',pageOrigin=''){
362
+ const input=markdownDocumentCleanURLInput(value);
363
+ if(!input){
364
+ return '';
365
+ }
366
+
367
+ const expectedOrigin=pageOrigin
368
+ ||globalThis.location?.origin
369
+ ||new URL(sourceURL).origin;
370
+ try{
371
+ const url=new URL(input,sourceURL);
372
+ if(
373
+ !MARKDOWN_DOCUMENT_ASSET_PROTOCOLS.has(url.protocol)
374
+ ||url.origin!==expectedOrigin
375
+ ||url.username
376
+ ||url.password
377
+ ){
378
+ return '';
379
+ }
380
+ return url.href;
381
+ }catch{
382
+ return '';
383
+ }
384
+ }
385
+
386
+ function markdownDocumentHeadingBase(value=''){
387
+ const identifier=String(value||'')
388
+ .normalize('NFKD')
389
+ .replace(/[\u0300-\u036f]/g,'')
390
+ .toLowerCase()
391
+ .replace(/&/g,' and ')
392
+ .replace(/[^a-z0-9]+/g,'-')
393
+ .replace(/^-+|-+$/g,'')
394
+ .slice(0,80);
395
+ return identifier||'section';
396
+ }
397
+
398
+ function markdownDocumentNextHeadingIdentifier(value='',usedIdentifiers=new Set()){
399
+ const base=markdownDocumentHeadingBase(value);
400
+ let candidate=base;
401
+ let suffix=2;
402
+ while(usedIdentifiers.has(candidate)){
403
+ candidate=`${base}-${suffix++}`;
404
+ }
405
+ usedIdentifiers.add(candidate);
406
+ return candidate;
407
+ }
408
+ // END MARKDOWN_DOCUMENT_POLICY
409
+
410
+ const pageOrigin=globalThis.location?.origin||new URL(document.baseURI).origin;
411
+ const defaultSourceURL=markdownDocumentSourceURL(
412
+ document.baseURI,
413
+ document.baseURI,
414
+ pageOrigin
415
+ );
416
+ const defaultOptions=Object.freeze(
417
+ {
418
+ labels:Object.freeze(
419
+ {
420
+ content:'Document content',
421
+ empty:'No document content is available.',
422
+ error:'Unable to display this document.',
423
+ loading:'Loading document…',
424
+ tableOfContents:'On this page'
425
+ }
426
+ ),
427
+ onNavigate:null,
428
+ showTableOfContents:true,
429
+ sourceURL:defaultSourceURL
430
+ }
431
+ );
432
+
433
+ let currentMarkdown='';
434
+ let currentSourceURL=defaultSourceURL;
435
+ let loadSequence=0;
436
+ let options=normalizeOptions(optionsFromDataset(),defaultOptions);
437
+ let state='empty';
438
+ let tableOfContents=[];
439
+
440
+ host.clear=clear;
441
+ host.configure=configure;
442
+ host.fail=fail;
443
+ host.focus=focusDocument;
444
+ host.focusFragment=focusFragment;
445
+ host.load=load;
446
+ host.render=render;
447
+
448
+ Object.defineProperties(
449
+ host,
450
+ {
451
+ options:{get:getOptions,set:configure},
452
+ sourceURL:{get:()=>currentSourceURL,set:setSourceURL},
453
+ state:{get:()=>state},
454
+ tableOfContents:{get:()=>tableOfContents.map(entry=>({...entry}))},
455
+ value:{get:()=>currentMarkdown,set:value=>render(value)}
456
+ }
457
+ );
458
+
459
+ documentElement.addEventListener('click',handleNavigation);
460
+
461
+ function optionsFromDataset(){
462
+ const configured={};
463
+ if(host.dataset.sourceUrl!==undefined){
464
+ configured.sourceURL=host.dataset.sourceUrl;
465
+ }
466
+ if(host.dataset.showTableOfContents!==undefined){
467
+ configured.showTableOfContents=host.dataset.showTableOfContents!=='false';
468
+ }
469
+ return configured;
470
+ }
471
+
472
+ function normalizeOptions(input={},previous=defaultOptions){
473
+ if(!input||typeof input!=='object'||Array.isArray(input)){
474
+ throw new TypeError('Markdown document options must be an object.');
475
+ }
476
+
477
+ const labelInput=input.labels===undefined?{}:input.labels;
478
+ if(!labelInput||typeof labelInput!=='object'||Array.isArray(labelInput)){
479
+ throw new TypeError('Markdown document labels must be an object.');
480
+ }
481
+
482
+ const labels={...previous.labels};
483
+ for(const name of ['content','empty','error','loading','tableOfContents']){
484
+ if(labelInput[name]!==undefined){
485
+ if(typeof labelInput[name]!=='string'||!labelInput[name].trim()){
486
+ throw new TypeError(`Markdown document labels.${name} must be a nonempty string.`);
487
+ }
488
+ labels[name]=labelInput[name].trim();
489
+ }
490
+ }
491
+
492
+ const sourceInput=input.sourceURL??input.sourceUrl??previous.sourceURL;
493
+ const sourceURL=markdownDocumentSourceURL(
494
+ sourceInput,
495
+ previous.sourceURL||document.baseURI,
496
+ pageOrigin
497
+ );
498
+ if(!sourceURL){
499
+ throw new TypeError('Markdown document sourceURL must resolve to a same-origin HTTP(S) URL.');
500
+ }
501
+
502
+ const onNavigate=input.onNavigate===undefined
503
+ ?previous.onNavigate
504
+ :input.onNavigate;
505
+ if(onNavigate!==null&&typeof onNavigate!=='function'){
506
+ throw new TypeError('Markdown document onNavigate must be a function or null.');
507
+ }
508
+
509
+ const showTableOfContents=input.showTableOfContents===undefined
510
+ ?previous.showTableOfContents
511
+ :input.showTableOfContents;
512
+ if(typeof showTableOfContents!=='boolean'){
513
+ throw new TypeError('Markdown document showTableOfContents must be boolean.');
514
+ }
515
+
516
+ return Object.freeze(
517
+ {
518
+ labels:Object.freeze(labels),
519
+ onNavigate,
520
+ showTableOfContents,
521
+ sourceURL
522
+ }
523
+ );
524
+ }
525
+
526
+ function getOptions(){
527
+ return {
528
+ labels:{...options.labels},
529
+ onNavigate:options.onNavigate,
530
+ showTableOfContents:options.showTableOfContents,
531
+ sourceURL:options.sourceURL
532
+ };
533
+ }
534
+
535
+ function configure(input={}){
536
+ const priorSourceURL=options.sourceURL;
537
+ options=normalizeOptions(input,options);
538
+ renderLabels();
539
+
540
+ if(!currentMarkdown){
541
+ currentSourceURL=options.sourceURL;
542
+ updateStateDOM();
543
+ }else if(priorSourceURL!==options.sourceURL){
544
+ render(currentMarkdown,{sourceURL:options.sourceURL});
545
+ }else{
546
+ buildTableOfContents(tableOfContents);
547
+ updateStateDOM();
548
+ }
549
+
550
+ return getOptions();
551
+ }
552
+
553
+ function renderLabels(){
554
+ contentElement.setAttribute('aria-label',options.labels.content);
555
+ tableOfContentsTitle.textContent=options.labels.tableOfContents;
556
+ updateStateDOM();
557
+ }
558
+
559
+ function sourceURLFrom(input={},fallback=options.sourceURL){
560
+ if(!input||typeof input!=='object'||Array.isArray(input)){
561
+ throw new TypeError('Markdown document render options must be an object.');
562
+ }
563
+ const candidate=input.sourceURL??input.sourceUrl??fallback;
564
+ const result=markdownDocumentSourceURL(
565
+ candidate,
566
+ fallback||document.baseURI,
567
+ pageOrigin
568
+ );
569
+ if(!result){
570
+ throw new TypeError('Markdown document sourceURL must resolve to a same-origin HTTP(S) URL.');
571
+ }
572
+ return result;
573
+ }
574
+
575
+ function setSourceURL(value=''){
576
+ options=normalizeOptions({sourceURL:value},options);
577
+ if(currentMarkdown){
578
+ render(currentMarkdown,{sourceURL:options.sourceURL});
579
+ }else{
580
+ currentSourceURL=options.sourceURL;
581
+ updateStateDOM();
582
+ }
583
+ return currentSourceURL;
584
+ }
585
+
586
+ async function load(source='',loadOptions={}){
587
+ const sequence=++loadSequence;
588
+ let sourceURL;
589
+ try{
590
+ sourceURL=sourceURLFrom(loadOptions,currentSourceURL||options.sourceURL);
591
+ }catch(error){
592
+ if(sequence===loadSequence){
593
+ showError(error);
594
+ }
595
+ return false;
596
+ }
597
+
598
+ currentSourceURL=sourceURL;
599
+ transition('loading');
600
+
601
+ try{
602
+ const pending=typeof source==='function'
603
+ ?source({sourceURL})
604
+ :source;
605
+ const result=await pending;
606
+ if(sequence!==loadSequence){
607
+ return false;
608
+ }
609
+
610
+ if(
611
+ result
612
+ &&typeof result==='object'
613
+ &&!Array.isArray(result)
614
+ ){
615
+ sourceURL=sourceURLFrom(
616
+ result,
617
+ sourceURL
618
+ );
619
+ return renderMarkdown(result.markdown??result.value??'',sourceURL);
620
+ }
621
+ return renderMarkdown(result??'',sourceURL);
622
+ }catch(error){
623
+ if(sequence===loadSequence){
624
+ showError(error);
625
+ }
626
+ return false;
627
+ }
628
+ }
629
+
630
+ function render(markdown='',renderOptions={}){
631
+ ++loadSequence;
632
+ try{
633
+ const sourceURL=sourceURLFrom(
634
+ renderOptions,
635
+ currentSourceURL||options.sourceURL
636
+ );
637
+ return renderMarkdown(markdown,sourceURL);
638
+ }catch(error){
639
+ showError(error);
640
+ return false;
641
+ }
642
+ }
643
+
644
+ function renderMarkdown(markdown='',sourceURL=options.sourceURL){
645
+ if(typeof markdown!=='string'){
646
+ throw new TypeError('Markdown document content must be a string.');
647
+ }
648
+
649
+ currentMarkdown=markdown;
650
+ currentSourceURL=sourceURL;
651
+ contentElement.replaceChildren();
652
+ tableOfContents=[];
653
+ tableOfContentsList.replaceChildren();
654
+
655
+ if(!markdown.trim()){
656
+ transition('empty');
657
+ return true;
658
+ }
659
+
660
+ // MD.safeRendered is the shared first pass. The detached template used
661
+ // below is inert while the stricter positive policy removes anything
662
+ // that the shared sanitizer intentionally leaves available.
663
+ const safeRendered=new MD(markdown).safeRendered;
664
+ const fragment=strictMarkdownFragment(safeRendered,sourceURL);
665
+ const meaningful=Boolean(
666
+ fragment.textContent?.trim()
667
+ ||fragment.querySelector('img,hr,table')
668
+ );
669
+ if(!meaningful){
670
+ transition('empty');
671
+ return true;
672
+ }
673
+
674
+ tableOfContents=decorateHeadings(fragment);
675
+ decorateTables(fragment);
676
+ contentElement.replaceChildren(fragment);
677
+ buildTableOfContents(tableOfContents);
678
+ transition(
679
+ 'ready',
680
+ {
681
+ characters:markdown.length,
682
+ headings:tableOfContents.map(entry=>({...entry}))
683
+ }
684
+ );
685
+ return true;
686
+ }
687
+
688
+ function strictMarkdownFragment(html='',sourceURL=options.sourceURL){
689
+ const template=document.createElement('template');
690
+ template.innerHTML=html;
691
+
692
+ const elements=Array.from(template.content.querySelectorAll('*'));
693
+ for(const element of elements){
694
+ const name=element.tagName.toUpperCase();
695
+ if(!markdownDocumentElementAllowed(name)){
696
+ // Removing the complete subtree rejects custom elements such as
697
+ // html-import rather than preserving executable descendants.
698
+ element.remove();
699
+ continue;
700
+ }
701
+
702
+ const allowedAttributes=new Set(markdownDocumentAllowedAttributes(name));
703
+ for(const attribute of Array.from(element.attributes)){
704
+ if(!allowedAttributes.has(attribute.name.toLowerCase())){
705
+ element.removeAttribute(attribute.name);
706
+ }
707
+ }
708
+
709
+ sanitizeAllowedAttributeValues(element,name);
710
+ if(name==='A'){
711
+ sanitizeLink(element,sourceURL);
712
+ }else if(name==='IMG'){
713
+ sanitizeImage(element,sourceURL);
714
+ }
715
+ }
716
+
717
+ const comments=[];
718
+ const commentWalker=document.createTreeWalker(
719
+ template.content,
720
+ globalThis.NodeFilter?.SHOW_COMMENT||128
721
+ );
722
+ while(commentWalker.nextNode()){
723
+ comments.push(commentWalker.currentNode);
724
+ }
725
+ comments.forEach(comment=>comment.remove());
726
+ return template.content;
727
+ }
728
+
729
+ function sanitizeAllowedAttributeValues(element,name){
730
+ for(const attribute of Array.from(element.attributes)){
731
+ if(attribute.value.length>2048){
732
+ element.setAttribute(attribute.name,attribute.value.slice(0,2048));
733
+ }
734
+ }
735
+
736
+ if(name==='CODE'&&element.hasAttribute('class')){
737
+ const className=element.getAttribute('class').trim();
738
+ if(!/^language-[a-z0-9][a-z0-9_+-]{0,63}$/i.test(className)){
739
+ element.removeAttribute('class');
740
+ }
741
+ }
742
+
743
+ for(const attribute of ['colspan','rowspan']){
744
+ if(element.hasAttribute(attribute)){
745
+ sanitizeIntegerAttribute(element,attribute,1,100);
746
+ }
747
+ }
748
+ if(name==='OL'&&element.hasAttribute('start')){
749
+ sanitizeIntegerAttribute(element,'start',-100000,100000);
750
+ }
751
+ if(name==='LI'&&element.hasAttribute('value')){
752
+ sanitizeIntegerAttribute(element,'value',-100000,100000);
753
+ }
754
+ if(name==='TH'&&element.hasAttribute('scope')){
755
+ const scope=element.getAttribute('scope').toLowerCase();
756
+ if(!['col','colgroup','row','rowgroup'].includes(scope)){
757
+ element.removeAttribute('scope');
758
+ }else{
759
+ element.setAttribute('scope',scope);
760
+ }
761
+ }
762
+ }
763
+
764
+ function sanitizeIntegerAttribute(element,name,min,max){
765
+ const value=Number(element.getAttribute(name));
766
+ if(!Number.isSafeInteger(value)||value<min||value>max){
767
+ element.removeAttribute(name);
768
+ return;
769
+ }
770
+ element.setAttribute(name,String(value));
771
+ }
772
+
773
+ function sanitizeLink(link,sourceURL){
774
+ const originalHref=link.getAttribute('href')||'';
775
+ const policy=markdownDocumentLinkPolicy(
776
+ originalHref,
777
+ sourceURL,
778
+ pageOrigin
779
+ );
780
+ if(!policy){
781
+ link.removeAttribute('href');
782
+ return;
783
+ }
784
+
785
+ link.setAttribute('href',policy.href);
786
+ link.dataset.markdownKind=policy.kind;
787
+ link.dataset.markdownOriginalHref=originalHref.slice(0,2048);
788
+ link.dataset.markdownTargetUrl=policy.targetURL;
789
+ link.dataset.markdownFragment=policy.fragment;
790
+
791
+ if(
792
+ policy.external
793
+ &&/^https?:$/i.test(new URL(policy.targetURL).protocol)
794
+ ){
795
+ link.target='_blank';
796
+ link.rel='noopener noreferrer';
797
+ link.referrerPolicy='no-referrer';
798
+ }
799
+ }
800
+
801
+ function sanitizeImage(image,sourceURL){
802
+ const resolved=markdownDocumentAssetURL(
803
+ image.getAttribute('src')||'',
804
+ sourceURL,
805
+ pageOrigin
806
+ );
807
+ if(resolved){
808
+ image.setAttribute('src',resolved);
809
+ }else{
810
+ image.removeAttribute('src');
811
+ }
812
+ image.alt=image.getAttribute('alt')||'';
813
+ image.loading='lazy';
814
+ image.decoding='async';
815
+ image.referrerPolicy='no-referrer';
816
+ }
817
+
818
+ function decorateHeadings(fragment){
819
+ const usedHeadingIds=new Set();
820
+ return Array.from(fragment.querySelectorAll('h1,h2,h3,h4,h5,h6'))
821
+ .map(
822
+ heading=>{
823
+ const text=heading.textContent.trim()||'Untitled section';
824
+ const id=markdownDocumentNextHeadingIdentifier(
825
+ text,
826
+ usedHeadingIds
827
+ );
828
+ const level=Number(heading.tagName.slice(1));
829
+ heading.id=id;
830
+ heading.tabIndex=-1;
831
+ return Object.freeze({id,level,text});
832
+ }
833
+ );
834
+ }
835
+
836
+ function decorateTables(fragment){
837
+ Array.from(fragment.querySelectorAll('table')).forEach(
838
+ (table,index)=>{
839
+ const headers=Array.from(table.querySelectorAll('thead th'));
840
+ headers.forEach(header=>{
841
+ header.scope='col';
842
+ });
843
+ const headingText=headers
844
+ .map(header=>header.textContent.trim())
845
+ .filter(Boolean)
846
+ .join(', ');
847
+ const prefix=`Data table ${index+1}`;
848
+ const label=headingText?`${prefix}: ${headingText}`:prefix;
849
+
850
+ table.tabIndex=0;
851
+ table.setAttribute('aria-label',label.slice(0,256));
852
+ }
853
+ );
854
+ }
855
+
856
+ function buildTableOfContents(entries=[]){
857
+ const fragment=document.createDocumentFragment();
858
+ for(const entry of entries){
859
+ const item=document.createElement('li');
860
+ const link=document.createElement('a');
861
+ const href=`#${encodeURIComponent(entry.id)}`;
862
+ const targetURL=new URL(href,currentSourceURL).href;
863
+
864
+ item.dataset.level=String(entry.level);
865
+ link.href=href;
866
+ link.textContent=entry.text;
867
+ link.dataset.markdownKind='fragment';
868
+ link.dataset.markdownOriginalHref=href;
869
+ link.dataset.markdownTargetUrl=targetURL;
870
+ link.dataset.markdownFragment=entry.id;
871
+ item.append(link);
872
+ fragment.append(item);
873
+ }
874
+ tableOfContentsList.replaceChildren(fragment);
875
+ }
876
+
877
+ function clear(){
878
+ ++loadSequence;
879
+ currentMarkdown='';
880
+ currentSourceURL=options.sourceURL;
881
+ contentElement.replaceChildren();
882
+ tableOfContents=[];
883
+ tableOfContentsList.replaceChildren();
884
+ transition('empty');
885
+ return true;
886
+ }
887
+
888
+ function fail(error){
889
+ ++loadSequence;
890
+ return showError(error);
891
+ }
892
+
893
+ function showError(error){
894
+ currentMarkdown='';
895
+ contentElement.replaceChildren();
896
+ tableOfContents=[];
897
+ tableOfContentsList.replaceChildren();
898
+ const message=error instanceof Error
899
+ ?error.message
900
+ :String(error||options.labels.error);
901
+ transition('error',{message:message.slice(0,2048)});
902
+ return false;
903
+ }
904
+
905
+ function transition(nextState,detail={}){
906
+ state=nextState;
907
+ updateStateDOM();
908
+
909
+ const eventDetail=Object.freeze(
910
+ {
911
+ ...detail,
912
+ sourceURL:currentSourceURL,
913
+ state
914
+ }
915
+ );
916
+ host.dispatchEvent(
917
+ new CustomEvent(
918
+ 'markdown-document-state',
919
+ {bubbles:true,composed:true,detail:eventDetail}
920
+ )
921
+ );
922
+
923
+ const stateEvent={
924
+ empty:'markdown-document-empty',
925
+ error:'markdown-document-error',
926
+ loading:'markdown-document-loading',
927
+ ready:'markdown-document-rendered'
928
+ }[state];
929
+ if(stateEvent){
930
+ host.dispatchEvent(
931
+ new CustomEvent(
932
+ stateEvent,
933
+ {bubbles:true,composed:true,detail:eventDetail}
934
+ )
935
+ );
936
+ }
937
+ return eventDetail;
938
+ }
939
+
940
+ function updateStateDOM(){
941
+ const readyState=state==='ready';
942
+ const loadingState=state==='loading';
943
+ documentElement.setAttribute('aria-busy',String(loadingState));
944
+ host.setAttribute('aria-busy',String(loadingState));
945
+ host.dataset.state=state;
946
+ statusElement.dataset.state=state;
947
+ statusElement.hidden=readyState;
948
+ contentElement.hidden=!readyState;
949
+ tableOfContentsElement.hidden=(
950
+ !readyState
951
+ ||!options.showTableOfContents
952
+ ||tableOfContents.length===0
953
+ );
954
+
955
+ statusElement.textContent={
956
+ empty:options.labels.empty,
957
+ error:options.labels.error,
958
+ loading:options.labels.loading,
959
+ ready:''
960
+ }[state]||'';
961
+ }
962
+
963
+ function focusDocument(){
964
+ if(state==='ready'){
965
+ const heading=contentElement.querySelector('h1,h2,h3,h4,h5,h6');
966
+ (heading||contentElement).focus({preventScroll:true});
967
+ return true;
968
+ }
969
+ statusElement.focus({preventScroll:true});
970
+ return false;
971
+ }
972
+
973
+ function handleNavigation(event){
974
+ if(event.defaultPrevented||event.button!==0){
975
+ return;
976
+ }
977
+ const link=event.composedPath().find(
978
+ node=>node?.tagName==='A'&&documentElement.contains(node)
979
+ );
980
+ if(!link||!link.hasAttribute('href')){
981
+ return;
982
+ }
983
+
984
+ const detail=Object.freeze(
985
+ {
986
+ fragment:link.dataset.markdownFragment||'',
987
+ href:link.dataset.markdownOriginalHref||link.getAttribute('href'),
988
+ kind:link.dataset.markdownKind||'link',
989
+ sourceURL:currentSourceURL,
990
+ targetURL:link.dataset.markdownTargetUrl||link.href
991
+ }
992
+ );
993
+ const navigationEvent=new CustomEvent(
994
+ 'markdown-document-navigate',
995
+ {
996
+ bubbles:true,
997
+ cancelable:true,
998
+ composed:true,
999
+ detail
1000
+ }
1001
+ );
1002
+ const continueNavigation=host.dispatchEvent(navigationEvent);
1003
+
1004
+ if(detail.kind==='fragment'||detail.kind==='markdown'){
1005
+ event.preventDefault();
1006
+ }
1007
+ if(!continueNavigation){
1008
+ event.preventDefault();
1009
+ return;
1010
+ }
1011
+
1012
+ if(detail.kind==='fragment'){
1013
+ focusFragment(detail.fragment);
1014
+ }else if(detail.kind==='markdown'&&options.onNavigate){
1015
+ Promise.resolve(options.onNavigate(detail)).catch(
1016
+ error=>console.error('Markdown document navigation callback failed.',error)
1017
+ );
1018
+ }
1019
+ }
1020
+
1021
+ function focusFragment(fragment=''){
1022
+ const decoded=markdownDocumentDecodeFragment(fragment);
1023
+ const generatedIdentifier=markdownDocumentHeadingBase(decoded);
1024
+ const target=Array.from(contentElement.querySelectorAll('[id]')).find(
1025
+ element=>element.id===decoded||element.id===generatedIdentifier
1026
+ );
1027
+ if(!target){
1028
+ return false;
1029
+ }
1030
+ target.focus({preventScroll:true});
1031
+ target.scrollIntoView({block:'start'});
1032
+ return true;
1033
+ }
1034
+
1035
+ renderLabels();
1036
+ host.ready=true;
1037
+ transition('empty');
1038
+ host.dispatchEvent(
1039
+ new CustomEvent(
1040
+ 'markdown-document-ready',
1041
+ {
1042
+ bubbles:true,
1043
+ composed:true,
1044
+ detail:{component:host,state}
1045
+ }
1046
+ )
1047
+ );
1048
+ </script>