@cyann/dash-lab 0.0.0-stage → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (96) hide show
  1. package/AGENTS.md +138 -0
  2. package/CHANGELOG.md +48 -0
  3. package/CONTRIBUTING.md +94 -0
  4. package/LICENSE +21 -0
  5. package/README.md +154 -2
  6. package/THIRD_PARTY_NOTICES.md +31 -0
  7. package/dist/commands/CommandContext.d.ts +19 -0
  8. package/dist/commands/CommandContext.d.ts.map +1 -0
  9. package/dist/commands/CommandPalette.d.ts +10 -0
  10. package/dist/commands/CommandPalette.d.ts.map +1 -0
  11. package/dist/commands/CommandProvider.d.ts +12 -0
  12. package/dist/commands/CommandProvider.d.ts.map +1 -0
  13. package/dist/commands/CommandRegistry.d.ts +40 -0
  14. package/dist/commands/CommandRegistry.d.ts.map +1 -0
  15. package/dist/commands/searchCommands.d.ts +3 -0
  16. package/dist/commands/searchCommands.d.ts.map +1 -0
  17. package/dist/commands/shortcuts.d.ts +7 -0
  18. package/dist/commands/shortcuts.d.ts.map +1 -0
  19. package/dist/dash-lab.css +2 -0
  20. package/dist/i18n/I18nProvider.d.ts +20 -0
  21. package/dist/i18n/I18nProvider.d.ts.map +1 -0
  22. package/dist/i18n/i18nStore.d.ts +31 -0
  23. package/dist/i18n/i18nStore.d.ts.map +1 -0
  24. package/dist/i18n/messages.d.ts +3 -0
  25. package/dist/i18n/messages.d.ts.map +1 -0
  26. package/dist/index.d.ts +32 -0
  27. package/dist/index.d.ts.map +1 -0
  28. package/dist/index.js +2561 -0
  29. package/dist/layout/DockWorkspace.d.ts +7 -0
  30. package/dist/layout/DockWorkspace.d.ts.map +1 -0
  31. package/dist/layout/LayoutControls.d.ts +5 -0
  32. package/dist/layout/LayoutControls.d.ts.map +1 -0
  33. package/dist/layout/Workbench.d.ts +40 -0
  34. package/dist/layout/Workbench.d.ts.map +1 -0
  35. package/dist/layout/layoutPersistence.d.ts +22 -0
  36. package/dist/layout/layoutPersistence.d.ts.map +1 -0
  37. package/dist/layout/layoutStore.d.ts +13 -0
  38. package/dist/layout/layoutStore.d.ts.map +1 -0
  39. package/dist/layout/panels.d.ts +21 -0
  40. package/dist/layout/panels.d.ts.map +1 -0
  41. package/dist/layout/useLayoutManagement.d.ts +21 -0
  42. package/dist/layout/useLayoutManagement.d.ts.map +1 -0
  43. package/dist/layout/useWorkbenchCommands.d.ts +14 -0
  44. package/dist/layout/useWorkbenchCommands.d.ts.map +1 -0
  45. package/dist/library.d.ts +3 -0
  46. package/dist/library.d.ts.map +1 -0
  47. package/dist/notifications/NotificationButton.d.ts +3 -0
  48. package/dist/notifications/NotificationButton.d.ts.map +1 -0
  49. package/dist/notifications/NotificationContext.d.ts +5 -0
  50. package/dist/notifications/NotificationContext.d.ts.map +1 -0
  51. package/dist/notifications/NotificationProvider.d.ts +11 -0
  52. package/dist/notifications/NotificationProvider.d.ts.map +1 -0
  53. package/dist/notifications/NotificationToasts.d.ts +2 -0
  54. package/dist/notifications/NotificationToasts.d.ts.map +1 -0
  55. package/dist/notifications/NotificationViewport.d.ts +2 -0
  56. package/dist/notifications/NotificationViewport.d.ts.map +1 -0
  57. package/dist/notifications/notificationStore.d.ts +56 -0
  58. package/dist/notifications/notificationStore.d.ts.map +1 -0
  59. package/dist/notifications/preferences.d.ts +10 -0
  60. package/dist/notifications/preferences.d.ts.map +1 -0
  61. package/dist/overlays/dialogMotion.d.ts +3 -0
  62. package/dist/overlays/dialogMotion.d.ts.map +1 -0
  63. package/dist/overlays/useDialogDismiss.d.ts +9 -0
  64. package/dist/overlays/useDialogDismiss.d.ts.map +1 -0
  65. package/dist/plugins/PluginContext.d.ts +5 -0
  66. package/dist/plugins/PluginContext.d.ts.map +1 -0
  67. package/dist/plugins/PluginRegistry.d.ts +98 -0
  68. package/dist/plugins/PluginRegistry.d.ts.map +1 -0
  69. package/dist/plugins/pluginState.d.ts +19 -0
  70. package/dist/plugins/pluginState.d.ts.map +1 -0
  71. package/dist/settings/ApplicationMenu.d.ts +2 -0
  72. package/dist/settings/ApplicationMenu.d.ts.map +1 -0
  73. package/dist/settings/SettingsDialog.d.ts +12 -0
  74. package/dist/settings/SettingsDialog.d.ts.map +1 -0
  75. package/dist/settings/configuration.d.ts +36 -0
  76. package/dist/settings/configuration.d.ts.map +1 -0
  77. package/dist/settings/useWorkbenchConfiguration.d.ts +15 -0
  78. package/dist/settings/useWorkbenchConfiguration.d.ts.map +1 -0
  79. package/dist/theme/ThemeProvider.d.ts +17 -0
  80. package/dist/theme/ThemeProvider.d.ts.map +1 -0
  81. package/dist/theme/ThemeToggle.d.ts +3 -0
  82. package/dist/theme/ThemeToggle.d.ts.map +1 -0
  83. package/dist/theme/palettes.d.ts +153 -0
  84. package/dist/theme/palettes.d.ts.map +1 -0
  85. package/dist/theme/themeStore.d.ts +31 -0
  86. package/dist/theme/themeStore.d.ts.map +1 -0
  87. package/docs/api.md +171 -0
  88. package/docs/application-guide.md +332 -0
  89. package/docs/architecture.md +59 -0
  90. package/docs/decisions/001-library-and-demo.md +9 -0
  91. package/docs/decisions/002-local-plugins-and-languages.md +17 -0
  92. package/docs/decisions/003-plugin-state-checkpoints.md +11 -0
  93. package/docs/dependencies.md +33 -0
  94. package/docs/validation.md +126 -0
  95. package/package.json +97 -4
  96. package/scripts/install-hooks.mjs +17 -0
package/dist/index.js ADDED
@@ -0,0 +1,2561 @@
1
+ import { createContext as e, useCallback as t, useContext as n, useEffect as r, useId as i, useLayoutEffect as a, useMemo as o, useRef as s, useState as c, useSyncExternalStore as l } from "react";
2
+ import { useStore as u } from "zustand";
3
+ import { ConfigProvider as d, Dropdown as f, theme as p } from "antd";
4
+ import m from "antd/locale/en_US.js";
5
+ import h from "antd/locale/fr_FR.js";
6
+ import { createStore as g } from "zustand/vanilla";
7
+ import { Fragment as _, jsx as v, jsxs as y } from "react/jsx-runtime";
8
+ import { DockviewDefaultTab as b, DockviewReact as x, Orientation as S, themeDark as C, themeLight as w } from "dockview-react";
9
+ // src/i18n/messages.ts
10
+ var T = {
11
+ "Application menu": "Menu de l’application",
12
+ File: "Fichier",
13
+ Plugins: "Plugins",
14
+ Settings: "Réglages",
15
+ Preferences: "Préférences",
16
+ Commands: "Commandes",
17
+ "Command palette": "Palette de commandes",
18
+ "Open command palette": "Ouvrir la palette de commandes",
19
+ "Search commands": "Rechercher une commande",
20
+ "Type a command…": "Saisissez une commande…",
21
+ "Close command palette": "Fermer la palette de commandes",
22
+ "Commands (Ctrl/⌘+Shift+P)": "Commandes (Ctrl/⌘+Maj+P)",
23
+ "No commands match your search.": "Aucune commande ne correspond à votre recherche.",
24
+ "No commands are registered yet.": "Aucune commande n’est encore enregistrée.",
25
+ Unavailable: "Indisponible",
26
+ "Unavailable:": "Indisponible :",
27
+ command: "commande",
28
+ commands: "commandes",
29
+ navigate: "parcourir",
30
+ run: "exécuter",
31
+ close: "fermer",
32
+ Enter: "Entrée",
33
+ Esc: "Échap",
34
+ "Open application menu": "Ouvrir le menu de l’application",
35
+ "Open settings": "Ouvrir les réglages",
36
+ "Open preferences": "Ouvrir les préférences",
37
+ "Close settings": "Fermer les réglages",
38
+ "Workbench controls": "Contrôles de l’application",
39
+ Workspace: "Espace de travail",
40
+ Monitoring: "Monitoring",
41
+ View: "Vue",
42
+ Focus: "Focus",
43
+ "Enter focus mode": "Activer le mode focus",
44
+ "Exit focus mode": "Quitter le mode focus",
45
+ "Focus workspace": "Concentrer l’espace de travail",
46
+ "Leave Focus mode": "Quitter le mode focus",
47
+ "Hide header and footer": "Masquer l’en-tête et le pied de page",
48
+ "Show header and footer": "Afficher l’en-tête et le pied de page",
49
+ "Toggle header and footer": "Afficher ou masquer l’en-tête et le pied de page",
50
+ "Toggle header and footer (Ctrl/⌘+Alt+V)": "Afficher ou masquer l’en-tête et le pied de page (Ctrl/⌘+Alt+V)",
51
+ "Toggle header": "Afficher ou masquer l’en-tête",
52
+ "Toggle footer": "Afficher ou masquer le pied de page",
53
+ "Toggle focus mode": "Activer ou quitter le mode focus",
54
+ Azure: "Azur",
55
+ "High Contrast": "Contraste",
56
+ Emerald: "Émeraude",
57
+ Umber: "Terre d’ombre",
58
+ "Custom layout": "Layout personnalisé",
59
+ "Restore custom layout": "Restaurer le layout personnalisé",
60
+ "Changes and the custom layout are saved automatically.": "Les réglages et le layout personnalisé sont sauvegardés automatiquement.",
61
+ Light: "Clair",
62
+ Dark: "Sombre",
63
+ Theme: "Thème",
64
+ "Color theme": "Thème de couleurs",
65
+ "Toggle theme": "Changer de thème",
66
+ "Switch to dark theme": "Passer au thème sombre",
67
+ "Switch to light theme": "Passer au thème clair",
68
+ Language: "Langue",
69
+ Animations: "Animations",
70
+ "Follow system": "Suivre le système",
71
+ "Reduce motion": "Réduire les animations",
72
+ "Choose how this application looks and notifies you.": "Choisissez l’apparence de cette application et ses notifications.",
73
+ "Show notification popups": "Afficher les notifications contextuelles",
74
+ "Popup duration (seconds)": "Durée des notifications (secondes)",
75
+ "History is always available. Errors remain visible until dismissed. System reduced-motion preferences always apply.": "L’historique reste disponible. Les erreurs restent visibles jusqu’à leur fermeture. La réduction des animations du système est toujours respectée.",
76
+ Cancel: "Annuler",
77
+ Close: "Fermer",
78
+ "Apply preferences": "Appliquer les préférences",
79
+ "Changes apply immediately. Save the layout to restore it on your next visit.": "Les changements sont immédiats. Enregistrez la disposition pour la retrouver à votre prochaine visite.",
80
+ "Show header": "Afficher l’en-tête",
81
+ "Show footer": "Afficher le pied de page",
82
+ "Save workspace layout": "Enregistrer la disposition",
83
+ "Reset workspace layout": "Réinitialiser la disposition",
84
+ Configuration: "Configuration",
85
+ "Import configuration": "Importer la configuration",
86
+ "Export configuration": "Exporter la configuration",
87
+ "Import configuration…": "Importer la configuration…",
88
+ "Export configuration…": "Exporter la configuration…",
89
+ "Import configuration file": "Fichier de configuration à importer",
90
+ "Reading configuration…": "Lecture de la configuration…",
91
+ "Transfer layout, preferences, and participating plugin data as a JSON file. Notification history stays in this session.": "Transférez la disposition, les préférences et les données des plugins participants dans un fichier JSON. L’historique reste dans cette session.",
92
+ LAYOUT: "DISPOSITION",
93
+ "Layout management": "Gestion de la disposition",
94
+ "Application layout": "Disposition de l’application",
95
+ "Columns layout": "Disposition en colonnes",
96
+ "Rows layout": "Disposition en lignes",
97
+ "Save layout": "Enregistrer la disposition",
98
+ "Restore saved layout": "Restaurer la disposition enregistrée",
99
+ "Reset layout": "Réinitialiser la disposition",
100
+ "Select default layout": "Choisir la disposition de l’application",
101
+ "Select columns layout": "Choisir la disposition en colonnes",
102
+ "Select rows layout": "Choisir la disposition en lignes",
103
+ "Layout saved.": "Disposition enregistrée.",
104
+ "Layout saved for this session.": "Disposition enregistrée pour cette session.",
105
+ "Saved layout restored.": "Disposition enregistrée restaurée.",
106
+ "Application layout selected.": "Disposition de l’application sélectionnée.",
107
+ "Columns layout selected.": "Disposition en colonnes sélectionnée.",
108
+ "Rows layout selected.": "Disposition en lignes sélectionnée.",
109
+ "Application layout reset.": "Disposition de l’application réinitialisée.",
110
+ "Application layout reset. Your saved layout is still available.": "Disposition réinitialisée. Votre disposition enregistrée reste disponible.",
111
+ Notifications: "Notifications",
112
+ "Open notifications": "Ouvrir les notifications",
113
+ "Close notifications": "Fermer les notifications",
114
+ "Recent notifications": "Notifications récentes",
115
+ "Notifications ({count} unread)": "Notifications ({count} non lues)",
116
+ "{count} unread notifications": "{count} notifications non lues",
117
+ "{unread} unread · {count} in history": "{unread} non lues · {count} dans l’historique",
118
+ "Dismiss notification: {title}": "Fermer la notification : {title}",
119
+ "Mark as read: {title}": "Marquer comme lue : {title}",
120
+ "Remove notification: {title}": "Supprimer la notification : {title}",
121
+ "Mark all read": "Tout marquer comme lu",
122
+ "Clear history": "Vider l’historique",
123
+ "Mark as read": "Marquer comme lue",
124
+ Remove: "Supprimer",
125
+ "You're all caught up.": "Vous êtes à jour.",
126
+ "New notifications will appear here.": "Les nouvelles notifications apparaîtront ici.",
127
+ info: "information",
128
+ success: "succès",
129
+ warning: "avertissement",
130
+ error: "erreur",
131
+ "Preferences saved.": "Préférences enregistrées.",
132
+ "Preferences applied for this session.": "Préférences appliquées pour cette session.",
133
+ "Preferences kept for this session": "Préférences conservées pour cette session",
134
+ "Preferences could not be restored": "Impossible de restaurer les préférences",
135
+ "Browser storage is unavailable or full.": "Le stockage du navigateur est indisponible ou plein.",
136
+ "Configuration imported.": "Configuration importée.",
137
+ "Configuration exported.": "Configuration exportée.",
138
+ "Configuration imported for this session": "Configuration importée pour cette session",
139
+ "Configuration could not be imported": "Impossible d’importer la configuration",
140
+ "Configuration exceeds the 1 MB limit.": "La configuration dépasse la limite de 1 Mo.",
141
+ "Browser storage is unavailable or full. Export a copy to keep these choices.": "Le stockage du navigateur est indisponible ou plein. Exportez une copie pour conserver ces choix.",
142
+ "Command failed: {title}": "Échec de la commande : {title}",
143
+ "Command could not run": "Impossible d’exécuter la commande",
144
+ "Shortcut could not run": "Impossible d’exécuter le raccourci",
145
+ "The action failed.": "L’action a échoué.",
146
+ "The action could not be completed.": "L’action n’a pas pu être exécutée.",
147
+ "No panels have been added to this workspace.": "Aucun panneau n’a été ajouté à cet espace de travail.",
148
+ "Hello World": "Bonjour le monde",
149
+ "Getting started": "Bien démarrer",
150
+ Playground: "Bac à sable",
151
+ "YOUR FIRST WORKSPACE": "VOTRE PREMIER ESPACE DE TRAVAIL",
152
+ "A small beginning.": "Un premier pas.",
153
+ "A workbench for everything you build next.": "Un espace pour toutes vos prochaines créations.",
154
+ "LET'S MAKE IT PERSONAL": "PERSONNALISEZ VOTRE ESPACE",
155
+ "Your name": "Votre nom",
156
+ "Say hello": "Dire bonjour",
157
+ "Hello, {name}!": "Bonjour, {name} !",
158
+ "Your first interaction is one hello away.": "Votre première interaction commence par un bonjour.",
159
+ "Your Hello World plugin sent this notification.": "Votre plugin Bonjour le monde a envoyé cette notification.",
160
+ "DOCKABLE PANELS": "PANNEAUX DÉPLAÇABLES",
161
+ "MIT LICENSED": "LICENCE MIT",
162
+ "MIT licensed": "Sous licence MIT",
163
+ "A local plugin. A real starting point.": "Un plugin local. Un vrai point de départ.",
164
+ "This panel lives in your application's plugins directory.": "Ce panneau se trouve dans le répertoire de plugins de votre application.",
165
+ "MAKE YOURSELF AT HOME": "PRENEZ VOS MARQUES",
166
+ "Your space, your way.": "Votre espace, à votre façon.",
167
+ "Drag a tab to move a panel. Pull the edges to give an idea more room.": "Déplacez un onglet pour déplacer un panneau. Tirez sur les bords pour donner plus de place à une idée.",
168
+ "Shape your workspace": "Organisez votre espace",
169
+ "Dock panels beside or below each other.": "Placez les panneaux côte à côte ou les uns sous les autres.",
170
+ "Clear the distractions": "Éliminez les distractions",
171
+ "Hide the header or footer, or enter Focus mode.": "Masquez les barres ou activez le mode focus.",
172
+ "Make something yours": "Créez votre application",
173
+ "Replace this local demo with your application.": "Remplacez cette démonstration locale par votre application.",
174
+ "All panels are live React components.": "Tous les panneaux sont des composants React actifs.",
175
+ "Keyboard shortcuts": "Raccourcis clavier",
176
+ "A LITTLE ROOM TO EXPERIMENT": "UN ESPACE POUR EXPÉRIMENTER",
177
+ "Keep an idea here.": "Gardez une idée ici.",
178
+ "Your workspace note": "Votre note de travail",
179
+ "What will you build next?": "Que créerez-vous ensuite ?",
180
+ "Your note stays while you move panels or use Focus mode.": "Votre note reste présente quand vous déplacez les panneaux ou utilisez le mode focus.",
181
+ "Send info": "Envoyer une information",
182
+ "Send warning": "Envoyer un avertissement",
183
+ "Send error": "Envoyer une erreur",
184
+ "Send via command": "Envoyer par commande",
185
+ "Try failed command": "Tester une commande en échec",
186
+ "Try an application command.": "Essayez une commande de l’application.",
187
+ "runs it outside text fields.": "l’exécute hors des champs de texte.",
188
+ "Workspace ready": "Espace de travail prêt",
189
+ "All systems ready": "Tous les systèmes sont prêts",
190
+ "3 panels": "3 panneaux",
191
+ "{count} panels": "{count} panneaux",
192
+ "Local demo": "Démo locale",
193
+ "YOUR NEXT IDEA STARTS HERE": "VOTRE PROCHAINE IDÉE COMMENCE ICI",
194
+ "HELLO WORLD DEMO": "DÉMO BONJOUR LE MONDE",
195
+ "Say hello from the plugin": "Dire bonjour depuis le plugin",
196
+ "Hello World ready": "Bonjour le monde prêt",
197
+ "Local plugin active": "Plugin local actif"
198
+ };
199
+ // src/i18n/i18nStore.ts
200
+ function E(e = "en", t = []) {
201
+ let n = /* @__PURE__ */ new Map([["en", {
202
+ id: "en",
203
+ label: "English",
204
+ messages: {}
205
+ }], ["fr", {
206
+ id: "fr",
207
+ label: "Français",
208
+ messages: T
209
+ }]]);
210
+ for (let e of t) {
211
+ if (!e.id.trim() || !e.label.trim()) throw Error("Languages require an ID and display name.");
212
+ if (new Intl.DateTimeFormat(e.id), Object.values(e.messages).some((e) => typeof e != "string")) throw Error("Translation values must be strings.");
213
+ n.set(e.id, {
214
+ ...e,
215
+ messages: Object.freeze({
216
+ ...n.get(e.id)?.messages,
217
+ ...e.messages
218
+ })
219
+ });
220
+ }
221
+ let r = (e) => {
222
+ if (!n.has(e)) throw Error(`Language is not registered: ${e}`);
223
+ }, i = (e) => (t, r = {}) => {
224
+ let i = n.get(e).messages;
225
+ return (Object.hasOwn(i, t) ? i[t] : Object.hasOwn(n.get("en").messages, t) ? n.get("en").messages[t] : t).replace(/\{(\w+)\}/g, (e, t) => Object.hasOwn(r, t) ? String(r[t]) : e);
226
+ };
227
+ return r(e), g((t, a) => ({
228
+ locale: e,
229
+ locales: Object.freeze([...n.values()].map(({ id: e, label: t }) => Object.freeze({
230
+ id: e,
231
+ label: t
232
+ }))),
233
+ assertLocale: r,
234
+ t: i(e),
235
+ setLocale: (e) => {
236
+ r(e), a().locale !== e && t({
237
+ locale: e,
238
+ t: i(e)
239
+ });
240
+ }
241
+ }));
242
+ }
243
+ // src/i18n/I18nProvider.tsx
244
+ var D = e(null), O = E(), k = Object.freeze({
245
+ ...O.getInitialState(),
246
+ setLocale: () => {
247
+ throw Error("Changing languages requires I18nProvider or Workbench.");
248
+ }
249
+ });
250
+ function A({ children: e, initialLocale: t = "en", languages: n = [], antdLocales: r = {} }) {
251
+ let [i] = c(() => E(t, n)), a = u(i, (e) => e.locale), o = r[a] ?? (a === "fr" ? h : m), s = "default" in o ? o.default : o;
252
+ return /* @__PURE__ */ v(D.Provider, {
253
+ value: i,
254
+ children: /* @__PURE__ */ v(d, {
255
+ locale: s,
256
+ children: /* @__PURE__ */ v("div", {
257
+ className: "dl-i18n",
258
+ lang: a,
259
+ style: {
260
+ height: "100%",
261
+ minHeight: 0
262
+ },
263
+ children: e
264
+ })
265
+ })
266
+ });
267
+ }
268
+ function j() {
269
+ let e = n(D), t = u(e ?? O);
270
+ return e ? t : k;
271
+ }
272
+ // src/layout/panels.ts
273
+ function M(e) {
274
+ let t = /* @__PURE__ */ new Set();
275
+ for (let n of e) {
276
+ if (!n.id.trim() || !n.title.trim()) throw Error("Panel identifiers and titles must not be empty.");
277
+ if (t.has(n.id)) throw Error(`Duplicate panel identifier: ${n.id}`);
278
+ if (n.position && !t.has(n.position.referencePanel)) throw Error(`Panel ${n.id} must reference an earlier panel.`);
279
+ if ([n.initialWidth, n.initialHeight].some((e) => e !== void 0 && (!Number.isFinite(e) || e <= 0))) throw Error(`Panel ${n.id} dimensions must be positive finite numbers.`);
280
+ t.add(n.id);
281
+ }
282
+ }
283
+ // src/theme/themeStore.ts
284
+ var N = {
285
+ azure: "Azure",
286
+ contrast: "High Contrast",
287
+ emerald: "Emerald",
288
+ umber: "Umber"
289
+ };
290
+ function ee(e, t = "azure") {
291
+ return g((n) => ({
292
+ mode: e,
293
+ family: t,
294
+ setFamily: (e) => n({ family: e }),
295
+ motionPreference: "system",
296
+ setMotionPreference: (e) => n({ motionPreference: e }),
297
+ setMode: (e) => n({ mode: e }),
298
+ toggleTheme: () => n((e) => ({ mode: e.mode === "light" ? "dark" : "light" }))
299
+ }));
300
+ }
301
+ // src/theme/palettes.ts
302
+ var P = {
303
+ light: {
304
+ "--dl-canvas": "#eaf0f6",
305
+ "--dl-surface": "#ffffff",
306
+ "--dl-raised": "#f5f7fa",
307
+ "--dl-text": "#142c48",
308
+ "--dl-muted": "#526c8d",
309
+ "--dl-border": "#d4dfed",
310
+ "--dl-accent": "#315ec3",
311
+ "--dl-accent-soft": "#eaf0ff",
312
+ "--dl-on-accent": "#ffffff",
313
+ "--dl-success": "#247659",
314
+ "--dl-warning": "#8a5b06",
315
+ "--dl-error": "#bd3342"
316
+ },
317
+ dark: {
318
+ "--dl-canvas": "#10151b",
319
+ "--dl-surface": "#171c24",
320
+ "--dl-raised": "#202731",
321
+ "--dl-text": "#dde8f6",
322
+ "--dl-muted": "#9db0cb",
323
+ "--dl-border": "#2d3747",
324
+ "--dl-accent": "#8bb8ff",
325
+ "--dl-accent-soft": "#213453",
326
+ "--dl-on-accent": "#0d203e",
327
+ "--dl-success": "#76c6a1",
328
+ "--dl-warning": "#f2bf68",
329
+ "--dl-error": "#ff9da7"
330
+ }
331
+ }, F = {
332
+ azure: P,
333
+ emerald: {
334
+ light: {
335
+ ...P.light,
336
+ "--dl-canvas": "#e8f1ed",
337
+ "--dl-surface": "#ffffff",
338
+ "--dl-raised": "#f0f7f3",
339
+ "--dl-text": "#163a2c",
340
+ "--dl-muted": "#486b5b",
341
+ "--dl-border": "#c7ddd1",
342
+ "--dl-accent": "#23734f",
343
+ "--dl-accent-soft": "#e0f2e7"
344
+ },
345
+ dark: {
346
+ ...P.dark,
347
+ "--dl-canvas": "#0e1914",
348
+ "--dl-surface": "#16241d",
349
+ "--dl-raised": "#203329",
350
+ "--dl-text": "#e0f1e7",
351
+ "--dl-muted": "#a0bfae",
352
+ "--dl-border": "#355443",
353
+ "--dl-accent": "#82d4a5",
354
+ "--dl-accent-soft": "#244333",
355
+ "--dl-on-accent": "#102e20"
356
+ }
357
+ },
358
+ umber: {
359
+ light: {
360
+ ...P.light,
361
+ "--dl-canvas": "#f0eae2",
362
+ "--dl-surface": "#fffcf7",
363
+ "--dl-raised": "#f6efe5",
364
+ "--dl-text": "#3d2b1e",
365
+ "--dl-muted": "#765b45",
366
+ "--dl-border": "#deceba",
367
+ "--dl-accent": "#80512c",
368
+ "--dl-accent-soft": "#f2e4d3"
369
+ },
370
+ dark: {
371
+ ...P.dark,
372
+ "--dl-canvas": "#1a1511",
373
+ "--dl-surface": "#261e18",
374
+ "--dl-raised": "#35291f",
375
+ "--dl-text": "#f3e7d8",
376
+ "--dl-muted": "#c5ad92",
377
+ "--dl-border": "#584433",
378
+ "--dl-accent": "#e0b182",
379
+ "--dl-accent-soft": "#483323",
380
+ "--dl-on-accent": "#302014"
381
+ }
382
+ },
383
+ contrast: {
384
+ light: {
385
+ "--dl-canvas": "#ffffff",
386
+ "--dl-surface": "#ffffff",
387
+ "--dl-raised": "#f0f0f0",
388
+ "--dl-text": "#000000",
389
+ "--dl-muted": "#333333",
390
+ "--dl-border": "#595959",
391
+ "--dl-accent": "#003b80",
392
+ "--dl-accent-soft": "#e1ecff",
393
+ "--dl-on-accent": "#ffffff",
394
+ "--dl-success": "#175737",
395
+ "--dl-warning": "#704400",
396
+ "--dl-error": "#a00020"
397
+ },
398
+ dark: {
399
+ "--dl-canvas": "#000000",
400
+ "--dl-surface": "#000000",
401
+ "--dl-raised": "#181818",
402
+ "--dl-text": "#ffffff",
403
+ "--dl-muted": "#dddddd",
404
+ "--dl-border": "#aaaaaa",
405
+ "--dl-accent": "#ffdf60",
406
+ "--dl-accent-soft": "#352e10",
407
+ "--dl-on-accent": "#000000",
408
+ "--dl-success": "#9cf0bd",
409
+ "--dl-warning": "#ffe090",
410
+ "--dl-error": "#ffb5bf"
411
+ }
412
+ }
413
+ }, I = e(null);
414
+ function L({ children: e, initialMode: t = "light", initialFamily: n = "azure" }) {
415
+ let [a] = c(() => ee(t, n)), l = u(a, (e) => e.family), f = u(a, (e) => e.mode), m = u(a, (e) => e.motionPreference), [h, g] = c(() => typeof matchMedia < "u" && matchMedia("(prefers-reduced-motion: reduce)").matches), _ = h || m === "reduced", y = s(null), b = i(), x = F[l][f];
416
+ r(() => {
417
+ let e = matchMedia("(prefers-reduced-motion: reduce)"), t = () => g(e.matches);
418
+ return t(), e.addEventListener("change", t), () => e.removeEventListener("change", t);
419
+ }, []);
420
+ let S = o(() => ({
421
+ inherit: !1,
422
+ algorithm: f === "dark" ? p.darkAlgorithm : p.defaultAlgorithm,
423
+ cssVar: { key: b },
424
+ token: {
425
+ colorPrimary: x["--dl-accent"],
426
+ colorBgContainer: x["--dl-surface"],
427
+ colorBgElevated: x["--dl-surface"],
428
+ colorBgLayout: x["--dl-canvas"],
429
+ colorText: x["--dl-text"],
430
+ colorTextSecondary: x["--dl-muted"],
431
+ colorTextLightSolid: x["--dl-on-accent"],
432
+ colorBorder: x["--dl-border"],
433
+ colorBorderSecondary: x["--dl-border"],
434
+ colorSuccess: x["--dl-success"],
435
+ colorWarning: x["--dl-warning"],
436
+ colorError: x["--dl-error"],
437
+ fontFamily: "Inter, ui-sans-serif, system-ui, sans-serif",
438
+ fontSize: l === "contrast" ? 16 : 13,
439
+ borderRadius: 5,
440
+ controlHeight: l === "contrast" ? 40 : 34,
441
+ motionDurationFast: _ ? "0s" : "0.1s",
442
+ motionDurationMid: _ ? "0s" : "0.2s",
443
+ motionDurationSlow: _ ? "0s" : "0.3s"
444
+ }
445
+ }), [
446
+ l,
447
+ f,
448
+ _,
449
+ b,
450
+ x
451
+ ]);
452
+ return /* @__PURE__ */ v(I.Provider, {
453
+ value: a,
454
+ children: /* @__PURE__ */ v(d, {
455
+ theme: S,
456
+ getPopupContainer: (e) => e?.closest(".dl-theme") ?? y.current ?? document.body,
457
+ children: /* @__PURE__ */ v("div", {
458
+ ref: y,
459
+ className: "dl-theme",
460
+ "data-theme": f,
461
+ "data-theme-family": l,
462
+ "data-motion": m,
463
+ style: {
464
+ ...x,
465
+ colorScheme: f
466
+ },
467
+ children: e
468
+ })
469
+ })
470
+ });
471
+ }
472
+ function R() {
473
+ let e = n(I);
474
+ if (!e) throw Error("useTheme must be used inside ThemeProvider or Workbench.");
475
+ return u(e);
476
+ }
477
+ // src/layout/DockWorkspace.tsx
478
+ function te(e) {
479
+ return /* @__PURE__ */ v(b, {
480
+ ...e,
481
+ hideClose: !0
482
+ });
483
+ }
484
+ function ne({ panels: e, onReady: n }) {
485
+ let { t: i } = j(), a = s(null);
486
+ r(() => {
487
+ for (let t of e) a.current?.getPanel(t.id)?.api.setTitle(i(t.title));
488
+ }, [e, i]);
489
+ let { mode: c } = R(), l = o(() => ({
490
+ ...c === "dark" ? C : w,
491
+ name: `dash-lab-${c}`,
492
+ gap: 8
493
+ }), [c]), u = o(() => (M(e), Object.fromEntries(e.map(({ id: e, component: t }) => [e, () => /* @__PURE__ */ v("div", {
494
+ className: "dl-panel-content",
495
+ children: /* @__PURE__ */ v(t, {})
496
+ })]))), [e]), d = t(({ api: t }) => {
497
+ a.current = t;
498
+ for (let { id: n, title: r, position: a, initialWidth: o, initialHeight: s } of e) t.addPanel({
499
+ id: n,
500
+ title: i(r),
501
+ component: n,
502
+ ...a ? { position: a } : {},
503
+ ...o === void 0 ? {} : { initialWidth: o },
504
+ ...s === void 0 ? {} : { initialHeight: s }
505
+ });
506
+ e[0] && t.getPanel(e[0].id)?.api.setActive(), n?.(t);
507
+ }, [
508
+ e,
509
+ n,
510
+ i
511
+ ]);
512
+ return /* @__PURE__ */ v(x, {
513
+ className: "dl-dock",
514
+ components: u,
515
+ defaultTabComponent: te,
516
+ onReady: d,
517
+ theme: l,
518
+ defaultRenderer: "always"
519
+ });
520
+ }
521
+ // src/layout/layoutStore.ts
522
+ function re(e = !0, t = !0) {
523
+ return g((n) => ({
524
+ headerVisible: e,
525
+ footerVisible: t,
526
+ focusMode: !1,
527
+ toggleHeader: () => n((e) => ({ headerVisible: !e.headerVisible })),
528
+ toggleFooter: () => n((e) => ({ footerVisible: !e.footerVisible })),
529
+ toggleView: () => n((e) => ({
530
+ headerVisible: !(e.headerVisible || e.footerVisible),
531
+ footerVisible: !(e.headerVisible || e.footerVisible)
532
+ })),
533
+ toggleFocus: () => n((e) => ({ focusMode: !e.focusMode })),
534
+ setVisibility: (e, t) => n({
535
+ headerVisible: e,
536
+ footerVisible: t
537
+ })
538
+ }));
539
+ }
540
+ // src/theme/ThemeToggle.tsx
541
+ function ie() {
542
+ let { t: e } = j(), { mode: t, toggleTheme: n } = R(), r = t === "light" ? "Switch to dark theme" : "Switch to light theme";
543
+ return /* @__PURE__ */ y("button", {
544
+ type: "button",
545
+ className: "dl-icon-button dl-theme-toggle",
546
+ "aria-label": e(r ?? ""),
547
+ title: e(r ?? ""),
548
+ onClick: n,
549
+ children: [/* @__PURE__ */ v("svg", {
550
+ width: "16",
551
+ height: "16",
552
+ viewBox: "0 0 24 24",
553
+ fill: "none",
554
+ stroke: "currentColor",
555
+ strokeWidth: "1.5",
556
+ "aria-hidden": "true",
557
+ children: t === "light" ? /* @__PURE__ */ y(_, { children: [/* @__PURE__ */ v("circle", {
558
+ cx: "12",
559
+ cy: "12",
560
+ r: "4"
561
+ }), /* @__PURE__ */ v("path", { d: "M12 2v2m0 16v2M2 12h2m16 0h2M5 5l1.5 1.5m11 11L19 19M5 19l1.5-1.5m11-11L19 5" })] }) : /* @__PURE__ */ v("path", { d: "M20.5 13A9 9 0 0 1 11 3.5 8.8 8.8 0 1 0 20.5 13Z" })
562
+ }), /* @__PURE__ */ v("span", { children: e(t === "light" ? "Light" : "Dark") })]
563
+ });
564
+ }
565
+ // src/layout/LayoutControls.tsx
566
+ function z({ kind: e }) {
567
+ return /* @__PURE__ */ y("svg", {
568
+ width: "16",
569
+ height: "16",
570
+ viewBox: "0 0 24 24",
571
+ fill: "none",
572
+ stroke: "currentColor",
573
+ strokeWidth: "1.5",
574
+ "aria-hidden": "true",
575
+ children: [/* @__PURE__ */ v("rect", {
576
+ x: "3",
577
+ y: "4",
578
+ width: "18",
579
+ height: "16",
580
+ rx: "2"
581
+ }), e === "columns" ? /* @__PURE__ */ v("path", { d: "M9 4v16m6-16v16" }) : e === "rows" ? /* @__PURE__ */ v("path", { d: "M3 10h18M3 15h18" }) : e === "custom" ? /* @__PURE__ */ v("path", { d: "M11 4v16M3 12h8m0-3h10" }) : /* @__PURE__ */ v("path", { d: "M15 4v16m0-8h6" })]
582
+ });
583
+ }
584
+ function ae({ layout: e }) {
585
+ let { t } = j();
586
+ return /* @__PURE__ */ y("div", {
587
+ className: "dl-layout-controls",
588
+ role: "group",
589
+ "aria-label": t("Layout management"),
590
+ children: [
591
+ /* @__PURE__ */ v("span", {
592
+ className: "dl-toolbar-label",
593
+ children: t("LAYOUT")
594
+ }),
595
+ [
596
+ "default",
597
+ "columns",
598
+ "rows"
599
+ ].map((n) => {
600
+ let r = n === "default" ? "Application layout" : n === "columns" ? "Columns layout" : "Rows layout";
601
+ return /* @__PURE__ */ v("button", {
602
+ type: "button",
603
+ className: "dl-icon-button",
604
+ "aria-label": t(r ?? ""),
605
+ title: t(r ?? ""),
606
+ disabled: !e.ready,
607
+ onClick: () => e.selectPreset(n),
608
+ children: /* @__PURE__ */ v(z, { kind: n })
609
+ }, n);
610
+ }),
611
+ /* @__PURE__ */ v("button", {
612
+ type: "button",
613
+ className: "dl-icon-button",
614
+ "aria-label": t("Custom layout"),
615
+ title: t("Restore custom layout"),
616
+ disabled: !e.ready || !e.hasSaved,
617
+ onClick: e.restore,
618
+ children: /* @__PURE__ */ v(z, { kind: "custom" })
619
+ })
620
+ ]
621
+ });
622
+ }
623
+ // src/plugins/pluginState.ts
624
+ function B(e, t = /* @__PURE__ */ new Set()) {
625
+ if (e === null || typeof e == "string" || typeof e == "boolean" || typeof e == "number" && Number.isFinite(e)) return e;
626
+ if (typeof e != "object" || t.has(e)) throw Error("Plugin state must contain finite, non-circular JSON data.");
627
+ if (!Array.isArray(e) && Object.getPrototypeOf(e) !== Object.prototype && Object.getPrototypeOf(e) !== null) throw Error("Plugin state must use plain JSON objects and arrays.");
628
+ t.add(e);
629
+ try {
630
+ return Array.isArray(e) ? Array.from(e, (e) => B(e, t)) : Object.fromEntries(Object.entries(e).map(([e, n]) => [e, B(n, t)]));
631
+ } finally {
632
+ t.delete(e);
633
+ }
634
+ }
635
+ function V(e) {
636
+ if (!e || typeof e != "object" || Array.isArray(e)) throw Error("Plugin states must be an object keyed by plugin ID.");
637
+ let t = B(e);
638
+ if (Object.keys(t).some((e) => !e.trim())) throw Error("Plugin state IDs must not be empty.");
639
+ return t;
640
+ }
641
+ function H(e) {
642
+ return Object.fromEntries(Object.entries(e).map(([e, t]) => {
643
+ try {
644
+ return [e, B(t.exportState())];
645
+ } catch (t) {
646
+ throw Error(`Plugin state could not be exported: ${e}`, { cause: t });
647
+ }
648
+ }));
649
+ }
650
+ function U(e, t, n) {
651
+ if (t.importState(B(n)) !== void 0) throw Error(`Plugin state import must be synchronous and return void: ${e}`);
652
+ }
653
+ function W(e, t, n) {
654
+ let r = V(t), i = Object.entries(e).filter(([e]) => Object.hasOwn(r, e));
655
+ if (!i.length) return n();
656
+ let a = H(Object.fromEntries(i)), o = [];
657
+ try {
658
+ for (let [e, t] of i) o.push([e, t]), U(e, t, r[e]);
659
+ n();
660
+ } catch (e) {
661
+ let t = [e];
662
+ for (let [e, n] of o.reverse()) try {
663
+ U(e, n, a[e]);
664
+ } catch (e) {
665
+ t.push(e);
666
+ }
667
+ throw t.length > 1 ? AggregateError(t, "Plugin state restoration failed and rollback was incomplete.", { cause: e }) : Error("Plugin state restoration failed. Previous state was restored.", { cause: e });
668
+ }
669
+ }
670
+ // src/layout/layoutPersistence.ts
671
+ function G(e) {
672
+ return typeof e == "object" && !!e && !Array.isArray(e);
673
+ }
674
+ function K(e, t) {
675
+ if (!G(e) || !G(e.grid) || !G(e.panels)) throw Error("Saved layout has an invalid structure.");
676
+ let n = new Set(t.map((e) => e.id)), r = e.panels;
677
+ if (Object.keys(r).length !== n.size || Object.keys(r).some((e) => !n.has(e))) throw Error("Saved layout is incompatible with the current panels.");
678
+ for (let e of n) {
679
+ let t = r[e];
680
+ if (!G(t) || t.id !== e || t.contentComponent !== e) throw Error("Saved layout references an unknown panel component.");
681
+ }
682
+ let i = e.grid;
683
+ if (![S.HORIZONTAL, S.VERTICAL].includes(i.orientation) || ![i.width, i.height].every((e) => typeof e == "number" && Number.isFinite(e) && e > 0)) throw Error("Saved layout has invalid dimensions or orientation.");
684
+ let a = /* @__PURE__ */ new Set(), o = /* @__PURE__ */ new Set();
685
+ function s(e) {
686
+ if (!G(e) || typeof e.id != "string" || o.has(e.id) || !Array.isArray(e.views) || !e.views.length) throw Error("Saved layout contains an invalid panel group.");
687
+ o.add(e.id);
688
+ for (let t of e.views) {
689
+ if (typeof t != "string" || !n.has(t) || a.has(t)) throw Error("Saved layout has missing, duplicate, or unknown panels.");
690
+ a.add(t);
691
+ }
692
+ if (e.activeView !== void 0 && !e.views.includes(e.activeView)) throw Error("Saved layout has an invalid active panel.");
693
+ }
694
+ function c(e, t = 0) {
695
+ if (!G(e) || t > 32 || e.size !== void 0 && (typeof e.size != "number" || !Number.isFinite(e.size) || e.size < 0)) throw Error("Saved layout contains an invalid split.");
696
+ if (e.type === "leaf") s(e.data);
697
+ else if (e.type === "branch" && Array.isArray(e.data)) e.data.forEach((e) => c(e, t + 1));
698
+ else throw Error("Saved layout contains an invalid split.");
699
+ }
700
+ if (c(i.root), e.floatingGroups !== void 0) {
701
+ if (!Array.isArray(e.floatingGroups)) throw Error("Saved layout has invalid floating groups.");
702
+ for (let t of e.floatingGroups) {
703
+ if (!G(t) || !G(t.position)) throw Error("Saved layout has invalid floating groups.");
704
+ G(t.grid) ? c(t.grid.root) : s(t.data);
705
+ }
706
+ }
707
+ if (e.popoutGroups !== void 0 && (!Array.isArray(e.popoutGroups) || e.popoutGroups.length)) throw Error("Layouts with separate browser windows are not supported.");
708
+ if (a.size !== n.size) throw Error("Saved layout has missing panels.");
709
+ if (e.activeGroup !== void 0 && !o.has(e.activeGroup)) throw Error("Saved layout has an invalid active group.");
710
+ }
711
+ function oe(e, t) {
712
+ if (new TextEncoder().encode(e).byteLength > 1e6) throw Error("Saved layout is too large.");
713
+ let n = JSON.parse(e);
714
+ if (!G(n) || n.version !== 1 || typeof n.headerVisible != "boolean" || typeof n.footerVisible != "boolean") throw Error("Saved layout has an unsupported format.");
715
+ return K(n.layout, t), {
716
+ version: 1,
717
+ layout: n.layout,
718
+ headerVisible: n.headerVisible,
719
+ footerVisible: n.footerVisible,
720
+ ...n.plugins === void 0 ? {} : { plugins: V(n.plugins) }
721
+ };
722
+ }
723
+ function se(e, t, n) {
724
+ if (t === "default") return structuredClone(e);
725
+ let r = t === "columns" ? S.HORIZONTAL : S.VERTICAL, i = r === S.HORIZONTAL ? e.grid.width : e.grid.height;
726
+ return {
727
+ grid: {
728
+ ...e.grid,
729
+ orientation: r,
730
+ root: {
731
+ type: "branch",
732
+ data: n.map(({ id: e }) => ({
733
+ type: "leaf",
734
+ size: i / n.length,
735
+ data: {
736
+ id: `dash-lab-${e}`,
737
+ views: [e],
738
+ activeView: e
739
+ }
740
+ }))
741
+ }
742
+ },
743
+ panels: structuredClone(e.panels),
744
+ ...n[0] ? { activeGroup: `dash-lab-${n[0].id}` } : {}
745
+ };
746
+ }
747
+ // src/layout/useLayoutManagement.ts
748
+ function ce(e, n, i, a, o, l) {
749
+ let u = s(null), d = s(null), f = s(null), p = s(""), m = s(null), [h, g] = c(!1), [_, v] = c(null), y = t((e) => (v({
750
+ message: e instanceof Error ? e.message : "The layout could not be updated.",
751
+ error: !0
752
+ }), !1), []), b = t((t) => {
753
+ if (!e) return !1;
754
+ m.current?.(), K(t.layout, n);
755
+ let r = e.toJSON();
756
+ return W(l, t.plugins ?? {}, () => {
757
+ try {
758
+ e.fromJSON(structuredClone(t.layout), { reuseExistingPanels: !0 });
759
+ } catch (t) {
760
+ throw e.fromJSON(r, { reuseExistingPanels: !0 }), p.current = JSON.stringify(e.toJSON()), t;
761
+ }
762
+ p.current = JSON.stringify(e.toJSON()), i.getState().setVisibility(t.headerVisible, t.footerVisible);
763
+ }), !0;
764
+ }, [
765
+ e,
766
+ n,
767
+ l,
768
+ i
769
+ ]);
770
+ r(() => {
771
+ if (e && d.current !== e) {
772
+ if (d.current = e, u.current = structuredClone(e.toJSON()), a) try {
773
+ let e = localStorage.getItem(a);
774
+ if (e) {
775
+ let t = oe(e, n);
776
+ b(t), f.current = t, g(!0), v({
777
+ message: "Saved layout restored.",
778
+ error: !1
779
+ });
780
+ }
781
+ } catch (e) {
782
+ y(e);
783
+ }
784
+ o?.(e);
785
+ }
786
+ }, [
787
+ e,
788
+ b,
789
+ o,
790
+ n,
791
+ y,
792
+ a
793
+ ]);
794
+ let x = t(() => {
795
+ if (!e) return null;
796
+ let { headerVisible: t, footerVisible: r } = i.getState(), a = {
797
+ version: 1,
798
+ layout: e.toJSON(),
799
+ headerVisible: t,
800
+ footerVisible: r
801
+ }, o = H(l);
802
+ return Object.keys(o).length && (a.plugins = o), K(a.layout, n), structuredClone(a);
803
+ }, [
804
+ e,
805
+ n,
806
+ l,
807
+ i
808
+ ]), S = t((e, t = !1) => {
809
+ let n = JSON.stringify(e);
810
+ if (new TextEncoder().encode(n).byteLength > 1e6) throw Error("Saved layout is too large.");
811
+ if (f.current = JSON.parse(n), g(!0), a) try {
812
+ localStorage.setItem(a, n);
813
+ } catch {
814
+ return t || y(/* @__PURE__ */ Error("Layout kept for this session. Browser storage is unavailable or full.")), !1;
815
+ }
816
+ return t || v({
817
+ message: a ? "Layout saved." : "Layout saved for this session.",
818
+ error: !1
819
+ }), !0;
820
+ }, [y, a]), C = t((e = !1) => {
821
+ try {
822
+ let t = x();
823
+ return t ? S(t, e) : !1;
824
+ } catch (e) {
825
+ return y(e);
826
+ }
827
+ }, [
828
+ x,
829
+ S,
830
+ y
831
+ ]);
832
+ r(() => {
833
+ if (!e) return;
834
+ let t, n = "", r = {
835
+ width: e.width,
836
+ height: e.height
837
+ };
838
+ p.current = JSON.stringify(e.toJSON());
839
+ let a = (e) => {
840
+ try {
841
+ let t = e();
842
+ if (!t) return;
843
+ if (!S(t, !0)) throw Error("Layout kept for this session. Browser storage is unavailable or full.");
844
+ n = "";
845
+ } catch (e) {
846
+ let t = e instanceof Error ? e.message : "The layout could not be updated.";
847
+ t !== n && y(e), n = t;
848
+ }
849
+ }, o = () => {
850
+ t !== void 0 && (clearTimeout(t), t = void 0, a(x));
851
+ };
852
+ m.current = o, f.current || (t = setTimeout(o, 200));
853
+ let s = e.onDidLayoutChange(({ reasons: n }) => {
854
+ let i = JSON.stringify(e.toJSON()), a = r.width !== e.width || r.height !== e.height;
855
+ r = {
856
+ width: e.width,
857
+ height: e.height
858
+ }, i !== p.current && (p.current = i, (n.has("structure") || n.has("activePanel") || n.has("geometry") && !a) && (clearTimeout(t), t = setTimeout(o, 200)));
859
+ }), c = i.subscribe((e, t) => {
860
+ (e.headerVisible !== t.headerVisible || e.footerVisible !== t.footerVisible) && (o(), f.current && a(() => f.current && {
861
+ ...f.current,
862
+ headerVisible: e.headerVisible,
863
+ footerVisible: e.footerVisible
864
+ }));
865
+ }), l = () => {
866
+ document.visibilityState === "hidden" && o();
867
+ };
868
+ return window.addEventListener("pagehide", o), document.addEventListener("visibilitychange", l), () => {
869
+ s.dispose(), c(), window.removeEventListener("pagehide", o), document.removeEventListener("visibilitychange", l), o(), m.current = null;
870
+ };
871
+ }, [
872
+ e,
873
+ x,
874
+ S,
875
+ y,
876
+ i
877
+ ]);
878
+ let w = t(() => {
879
+ if (m.current?.(), !f.current) return !1;
880
+ try {
881
+ return b(f.current) ? (v({
882
+ message: "Saved layout restored.",
883
+ error: !1
884
+ }), !0) : !1;
885
+ } catch (e) {
886
+ return y(e);
887
+ }
888
+ }, [b, y]), T = t((t) => {
889
+ if (!e || !u.current) return !1;
890
+ try {
891
+ let { headerVisible: e, footerVisible: r } = i.getState();
892
+ return b({
893
+ version: 1,
894
+ layout: se(u.current, t, n),
895
+ headerVisible: e,
896
+ footerVisible: r
897
+ }), v({
898
+ message: `${t === "default" ? "Application" : t === "columns" ? "Columns" : "Rows"} layout selected.`,
899
+ error: !1
900
+ }), !0;
901
+ } catch (e) {
902
+ return y(e);
903
+ }
904
+ }, [
905
+ e,
906
+ b,
907
+ n,
908
+ y,
909
+ i
910
+ ]);
911
+ return {
912
+ save: C,
913
+ restore: w,
914
+ reset: t(() => {
915
+ if (!u.current) return !1;
916
+ try {
917
+ let { headerVisible: e, footerVisible: t } = i.getInitialState();
918
+ return b({
919
+ version: 1,
920
+ layout: u.current,
921
+ headerVisible: e,
922
+ footerVisible: t
923
+ }) ? (v({
924
+ message: f.current ? "Application layout reset. Your saved layout is still available." : "Application layout reset.",
925
+ error: !1
926
+ }), !0) : !1;
927
+ } catch (e) {
928
+ return y(e);
929
+ }
930
+ }, [
931
+ b,
932
+ y,
933
+ i
934
+ ]),
935
+ selectPreset: T,
936
+ capture: x,
937
+ apply: b,
938
+ hasSaved: h,
939
+ feedback: _,
940
+ ready: e !== null
941
+ };
942
+ }
943
+ // src/notifications/NotificationContext.ts
944
+ var q = e(null);
945
+ function J() {
946
+ let e = n(q);
947
+ if (!e) throw Error("useNotifications must be used inside NotificationProvider or Workbench.");
948
+ return u(e);
949
+ }
950
+ // src/notifications/preferences.ts
951
+ var le = {
952
+ toastsEnabled: !0,
953
+ toastDurationMs: 5e3
954
+ };
955
+ function ue(e) {
956
+ let t = e;
957
+ if (!t || typeof t.toastsEnabled != "boolean" || typeof t.toastDurationMs != "number" || !Number.isInteger(t.toastDurationMs / 1e3) || t.toastDurationMs < 1e3 || t.toastDurationMs > 3e4) throw Error("Notification preferences require a popup choice and a duration of 1–30 whole seconds.");
958
+ }
959
+ // src/notifications/notificationStore.ts
960
+ function de(e = 100) {
961
+ if (!Number.isInteger(e) || e < 1) throw Error("Notification historyLimit must be a positive integer.");
962
+ let t = 0;
963
+ return g((n, r) => ({
964
+ preferences: { ...le },
965
+ setPreferences: (e) => {
966
+ ue(e), n((t) => ({
967
+ preferences: { ...e },
968
+ toasts: e.toastsEnabled ? t.toasts : []
969
+ }));
970
+ },
971
+ items: [],
972
+ toasts: [],
973
+ open: !1,
974
+ notify: (i) => {
975
+ if (!i.title.trim()) throw Error("A notification title must not be empty.");
976
+ let a = i.level ?? "info", o = i.durationMs ?? (a === "error" ? 0 : r().preferences.toastDurationMs);
977
+ if (!Number.isFinite(o) || o < 0) throw Error("Notification duration must be a nonnegative finite number.");
978
+ let s = Date.now(), c = {
979
+ ...i,
980
+ title: i.title.trim(),
981
+ id: `${s}-${++t}`,
982
+ createdAt: s,
983
+ read: !1,
984
+ level: a,
985
+ durationMs: o
986
+ };
987
+ return n((t) => {
988
+ let n = [c, ...t.items].slice(0, e), r = new Set(n.map((e) => e.id));
989
+ return {
990
+ items: n,
991
+ toasts: t.preferences.toastsEnabled ? [c.id, ...t.toasts].filter((e) => r.has(e)).slice(0, 3) : []
992
+ };
993
+ }), c.id;
994
+ },
995
+ dismiss: (e) => n((t) => ({ toasts: t.toasts.filter((t) => t !== e) })),
996
+ markRead: (e) => n((t) => ({ items: t.items.map((t) => t.id === e ? {
997
+ ...t,
998
+ read: !0
999
+ } : t) })),
1000
+ markAllRead: () => n((e) => ({ items: e.items.map((e) => ({
1001
+ ...e,
1002
+ read: !0
1003
+ })) })),
1004
+ remove: (e) => n((t) => ({
1005
+ items: t.items.filter((t) => t.id !== e),
1006
+ toasts: t.toasts.filter((t) => t !== e)
1007
+ })),
1008
+ clearHistory: () => n({
1009
+ items: [],
1010
+ toasts: []
1011
+ }),
1012
+ setOpen: (e) => n({ open: e })
1013
+ }));
1014
+ }
1015
+ // src/notifications/NotificationToasts.tsx
1016
+ function fe({ item: e, exiting: t, onExited: n }) {
1017
+ let { t: i } = j(), { dismiss: o } = J(), c = s(null);
1018
+ return r(() => {
1019
+ if (t || e.durationMs === 0) return;
1020
+ let n = setTimeout(() => o(e.id), e.durationMs);
1021
+ return () => clearTimeout(n);
1022
+ }, [
1023
+ o,
1024
+ t,
1025
+ e.id,
1026
+ e.durationMs
1027
+ ]), a(() => {
1028
+ if (!t || !c.current) return;
1029
+ let r = c.current.getAnimations();
1030
+ if (!r.length) {
1031
+ n(e.id);
1032
+ return;
1033
+ }
1034
+ let i = !1, a = () => {
1035
+ i || n(e.id);
1036
+ }, o = Math.max(...r.map((e) => Number(e.effect?.getComputedTiming().endTime) || 0)), s = setTimeout(a, Math.min(o, 2e3) + 100);
1037
+ return Promise.allSettled(r.map((e) => e.finished)).then(a), () => {
1038
+ i = !0, clearTimeout(s);
1039
+ };
1040
+ }, [
1041
+ t,
1042
+ e.id,
1043
+ n
1044
+ ]), /* @__PURE__ */ y("article", {
1045
+ ref: c,
1046
+ className: "dl-notification-toast",
1047
+ "data-level": e.level,
1048
+ "data-exiting": t || void 0,
1049
+ inert: t,
1050
+ "aria-hidden": t || void 0,
1051
+ role: t ? void 0 : e.level === "error" ? "alert" : "status",
1052
+ children: [/* @__PURE__ */ y("div", { children: [/* @__PURE__ */ v("strong", { children: e.title }), e.description && /* @__PURE__ */ v("p", { children: e.description })] }), /* @__PURE__ */ v("button", {
1053
+ type: "button",
1054
+ className: "dl-icon-button",
1055
+ "aria-label": i("Dismiss notification: {title}", { title: e.title }),
1056
+ onClick: () => o(e.id),
1057
+ children: "×"
1058
+ })]
1059
+ });
1060
+ }
1061
+ function pe() {
1062
+ let { t: e } = j(), { items: n, toasts: r } = J(), i = o(() => r.flatMap((e) => n.find((t) => t.id === e) ?? []), [n, r]), [s, l] = c(i), u = t((e) => l((t) => t.filter((t) => t.id !== e)), []);
1063
+ return a(() => {
1064
+ l((e) => [...i.filter((t) => !e.some((e) => e.id === t.id)), ...e.map((e) => i.find((t) => t.id === e.id) ?? e)]);
1065
+ }, [i, r]), /* @__PURE__ */ v("div", {
1066
+ className: "dl-notification-toasts",
1067
+ "aria-label": e("Recent notifications"),
1068
+ children: s.map((e) => /* @__PURE__ */ v(fe, {
1069
+ item: e,
1070
+ exiting: !r.includes(e.id),
1071
+ onExited: u
1072
+ }, e.id))
1073
+ });
1074
+ }
1075
+ // src/overlays/useDialogDismiss.ts
1076
+ function me(e, t, n) {
1077
+ let r = e.getBoundingClientRect();
1078
+ return t < r.left || t > r.right || n < r.top || n > r.bottom;
1079
+ }
1080
+ function Y(e) {
1081
+ let t = s(!1);
1082
+ return {
1083
+ onCancel: (t) => {
1084
+ t.preventDefault(), e();
1085
+ },
1086
+ onKeyDown: (t) => {
1087
+ t.key !== "Escape" || t.defaultPrevented || t.nativeEvent.isComposing || (t.preventDefault(), t.repeat || e());
1088
+ },
1089
+ onPointerDown: (e) => {
1090
+ t.current = e.button === 0 && e.target === e.currentTarget && me(e.currentTarget, e.clientX, e.clientY);
1091
+ },
1092
+ onPointerCancel: () => {
1093
+ t.current = !1;
1094
+ },
1095
+ onClick: (n) => {
1096
+ let r = t.current && n.target === n.currentTarget && me(n.currentTarget, n.clientX, n.clientY);
1097
+ t.current = !1, r && e();
1098
+ }
1099
+ };
1100
+ }
1101
+ // src/overlays/dialogMotion.ts
1102
+ var he = /* @__PURE__ */ new WeakMap(), X = /* @__PURE__ */ new WeakMap();
1103
+ function ge(e) {
1104
+ let t = e.ownerDocument, n = he.get(t);
1105
+ if (n !== void 0) return n;
1106
+ let r = !1;
1107
+ if (t.defaultView?.CSS.supports("overlay", "auto") && t.defaultView.CSS.supports("transition-behavior", "allow-discrete")) {
1108
+ let e = t.createElement("div");
1109
+ e.style.cssText = "position:fixed;visibility:hidden;pointer-events:none;transition:display 1s allow-discrete !important;display:block", t.body.appendChild(e), t.defaultView.getComputedStyle(e).getPropertyValue("display"), e.style.display = "none", r = t.defaultView.getComputedStyle(e).display !== "none", e.remove();
1110
+ }
1111
+ return he.set(t, r), r;
1112
+ }
1113
+ function _e(e) {
1114
+ if (!e) return;
1115
+ let t = X.get(e);
1116
+ X.delete(e), t?.finish(), e.removeAttribute("data-closing"), e.open || e.showModal();
1117
+ }
1118
+ function Z(e) {
1119
+ if (!e?.open) return Promise.resolve();
1120
+ let t = X.get(e);
1121
+ if (t) return t.promise;
1122
+ if (ge(e)) return e.close(), Promise.resolve();
1123
+ e.ownerDocument.defaultView?.getComputedStyle(e).getPropertyValue("opacity"), e.setAttribute("data-closing", "");
1124
+ let n = e.getAnimations({ subtree: !0 }).filter((t) => t.effect?.target === e);
1125
+ if (!n.length) return e.removeAttribute("data-closing"), e.close(), Promise.resolve();
1126
+ let r, i = new Promise((e) => {
1127
+ r = e;
1128
+ }), a = Math.max(...n.map((e) => Number(e.effect?.getComputedTiming().endTime ?? 0))), o = setTimeout(() => r(), Number.isFinite(a) ? Math.min(a + 100, 2e3) : 2e3), s = {
1129
+ finish: () => {
1130
+ clearTimeout(o), r();
1131
+ },
1132
+ promise: i.then(() => {
1133
+ X.get(e) === s && (X.delete(e), e.removeAttribute("data-closing"), e.open && e.close());
1134
+ })
1135
+ };
1136
+ return X.set(e, s), Promise.allSettled(n.map((e) => e.finished)).then(s.finish), s.promise;
1137
+ }
1138
+ // src/notifications/NotificationViewport.tsx
1139
+ function ve() {
1140
+ let { t: e, locale: t } = j(), { items: n, open: a, setOpen: o, markRead: c, markAllRead: l, remove: u, clearHistory: d } = J(), f = s(null), p = Y(() => o(!1)), m = s(null), h = i(), g = n.filter((e) => !e.read).length;
1141
+ return r(() => {
1142
+ a ? (_e(f.current), m.current?.focus()) : Z(f.current);
1143
+ }, [a]), /* @__PURE__ */ y(_, { children: [/* @__PURE__ */ v(pe, {}), /* @__PURE__ */ y("dialog", {
1144
+ ...p,
1145
+ ref: f,
1146
+ className: "dl-notification-center dl-modal",
1147
+ "aria-labelledby": h,
1148
+ children: [
1149
+ /* @__PURE__ */ y("header", {
1150
+ className: "dl-notification-heading",
1151
+ children: [/* @__PURE__ */ y("div", { children: [/* @__PURE__ */ v("h2", {
1152
+ id: h,
1153
+ children: e("Notifications")
1154
+ }), /* @__PURE__ */ v("p", { children: e("{unread} unread · {count} in history", {
1155
+ unread: g,
1156
+ count: n.length
1157
+ }) })] }), /* @__PURE__ */ v("button", {
1158
+ ref: m,
1159
+ type: "button",
1160
+ className: "dl-icon-button dl-dialog-close",
1161
+ "aria-label": e("Close notifications"),
1162
+ onClick: () => o(!1),
1163
+ children: "×"
1164
+ })]
1165
+ }),
1166
+ /* @__PURE__ */ y("div", {
1167
+ className: "dl-notification-actions",
1168
+ children: [/* @__PURE__ */ v("button", {
1169
+ type: "button",
1170
+ disabled: !g,
1171
+ onClick: l,
1172
+ children: e("Mark all read")
1173
+ }), /* @__PURE__ */ v("button", {
1174
+ type: "button",
1175
+ disabled: !n.length,
1176
+ onClick: d,
1177
+ children: e("Clear history")
1178
+ })]
1179
+ }),
1180
+ /* @__PURE__ */ y("div", {
1181
+ className: "dl-notification-history",
1182
+ children: [!n.length && /* @__PURE__ */ y("div", {
1183
+ className: "dl-notification-empty",
1184
+ children: [/* @__PURE__ */ v("h3", { children: e("You're all caught up.") }), /* @__PURE__ */ v("p", { children: e("New notifications will appear here.") })]
1185
+ }), n.map((n) => /* @__PURE__ */ y("article", {
1186
+ className: "dl-notification-entry",
1187
+ "data-level": n.level,
1188
+ "data-read": n.read,
1189
+ children: [
1190
+ /* @__PURE__ */ y("div", {
1191
+ className: "dl-notification-meta",
1192
+ children: [/* @__PURE__ */ v("span", { children: e(n.level) }), /* @__PURE__ */ v("time", {
1193
+ dateTime: new Date(n.createdAt).toISOString(),
1194
+ children: new Intl.DateTimeFormat(t, {
1195
+ hour: "2-digit",
1196
+ minute: "2-digit"
1197
+ }).format(n.createdAt)
1198
+ })]
1199
+ }),
1200
+ /* @__PURE__ */ v("h3", { children: n.title }),
1201
+ n.description && /* @__PURE__ */ v("p", { children: n.description }),
1202
+ /* @__PURE__ */ y("div", {
1203
+ className: "dl-notification-entry-actions",
1204
+ children: [!n.read && /* @__PURE__ */ v("button", {
1205
+ type: "button",
1206
+ "aria-label": e("Mark as read: {title}", { title: n.title }),
1207
+ onClick: () => c(n.id),
1208
+ children: e("Mark as read")
1209
+ }), /* @__PURE__ */ v("button", {
1210
+ type: "button",
1211
+ "aria-label": e("Remove notification: {title}", { title: n.title }),
1212
+ onClick: () => u(n.id),
1213
+ children: e("Remove")
1214
+ })]
1215
+ })
1216
+ ]
1217
+ }, n.id))]
1218
+ })
1219
+ ]
1220
+ })] });
1221
+ }
1222
+ // src/notifications/NotificationProvider.tsx
1223
+ function ye({ children: e, historyLimit: t = 100 }) {
1224
+ let [n] = c(() => de(t));
1225
+ return /* @__PURE__ */ y(q.Provider, {
1226
+ value: n,
1227
+ children: [e, /* @__PURE__ */ v(ve, {})]
1228
+ });
1229
+ }
1230
+ // src/notifications/NotificationButton.tsx
1231
+ function be() {
1232
+ let { t: e } = j(), { items: t, setOpen: n } = J(), r = t.filter((e) => !e.read).length;
1233
+ return /* @__PURE__ */ y("button", {
1234
+ type: "button",
1235
+ className: "dl-icon-button dl-notification-button",
1236
+ "aria-label": e("Open notifications"),
1237
+ title: e("Notifications ({count} unread)", { count: r }),
1238
+ onClick: () => n(!0),
1239
+ children: [/* @__PURE__ */ v("svg", {
1240
+ width: "18",
1241
+ height: "18",
1242
+ viewBox: "0 0 24 24",
1243
+ fill: "none",
1244
+ stroke: "currentColor",
1245
+ strokeWidth: "1.5",
1246
+ "aria-hidden": "true",
1247
+ children: /* @__PURE__ */ v("path", { d: "M5 16h14l-2-3V9a5 5 0 0 0-10 0v4zM9 20h6" })
1248
+ }), r > 0 && /* @__PURE__ */ v("span", {
1249
+ className: "dl-notification-count",
1250
+ "aria-label": e("{count} unread notifications", { count: r }),
1251
+ children: r > 99 ? "99+" : r
1252
+ })]
1253
+ });
1254
+ }
1255
+ // src/commands/CommandContext.ts
1256
+ var Q = e(null);
1257
+ function $() {
1258
+ let e = n(Q);
1259
+ if (!e) throw Error("useCommands must be used inside CommandProvider or Workbench.");
1260
+ let t = l(e.registry.subscribe, e.registry.getCommands, e.registry.getCommands);
1261
+ return o(() => ({
1262
+ commands: t,
1263
+ register: e.registry.register,
1264
+ execute: e.execute,
1265
+ canExecute: e.registry.canExecute
1266
+ }), [t, e]);
1267
+ }
1268
+ // src/commands/shortcuts.ts
1269
+ var xe = {
1270
+ esc: "escape",
1271
+ space: " ",
1272
+ spacebar: " ",
1273
+ plus: "+",
1274
+ return: "enter"
1275
+ }, Se = /* @__PURE__ */ new Map([
1276
+ ["ctrl", "ctrl"],
1277
+ ["control", "ctrl"],
1278
+ ["meta", "meta"],
1279
+ ["cmd", "meta"],
1280
+ ["command", "meta"],
1281
+ ["alt", "alt"],
1282
+ ["option", "alt"],
1283
+ ["shift", "shift"]
1284
+ ]);
1285
+ function Ce(e) {
1286
+ let t = e.toLowerCase();
1287
+ return xe[t] ?? t;
1288
+ }
1289
+ function we(e) {
1290
+ return `${Number(e.ctrlKey)}${Number(e.metaKey)}${Number(e.altKey)}${Number(e.shiftKey)}:${Ce(e.key)}`;
1291
+ }
1292
+ function Te(e, t) {
1293
+ let n = e.split("+").map((e) => e.trim().toLowerCase()), r = n.pop();
1294
+ if (!r || !(/^[a-z0-9]$/.test(r) || /^(f[1-9]|f1[0-9]|f2[0-4]|enter|return|escape|esc|space|plus|tab|backspace|delete|insert|home|end|pageup|pagedown|arrowup|arrowdown|arrowleft|arrowright)$/.test(r))) throw Error(`Invalid shortcut key: ${e}`);
1295
+ let i = /* @__PURE__ */ new Set(), a = t === "mac" ? "meta" : "ctrl";
1296
+ for (let t of n) {
1297
+ let n = t === "mod" ? a : Se.get(t);
1298
+ if (!n || i.has(n)) throw Error(`Invalid or repeated shortcut modifier: ${e}`);
1299
+ i.add(n);
1300
+ }
1301
+ return we({
1302
+ key: Ce(r),
1303
+ ctrlKey: i.has("ctrl"),
1304
+ metaKey: i.has("meta"),
1305
+ altKey: i.has("alt"),
1306
+ shiftKey: i.has("shift")
1307
+ });
1308
+ }
1309
+ // src/commands/CommandRegistry.ts
1310
+ var Ee = class {
1311
+ platform;
1312
+ entries = /* @__PURE__ */ new Map();
1313
+ running = /* @__PURE__ */ new Set();
1314
+ listeners = /* @__PURE__ */ new Set();
1315
+ snapshot = [];
1316
+ constructor(e = "other") {
1317
+ this.platform = e;
1318
+ }
1319
+ publish() {
1320
+ this.snapshot = Object.freeze([...this.entries.values()].map((e) => e.definition));
1321
+ for (let e of this.listeners) e();
1322
+ }
1323
+ register = (e) => {
1324
+ let t = Object.freeze({ ...e });
1325
+ if (!t.id.trim() || !t.title.trim()) throw Error("Command IDs and titles must not be empty.");
1326
+ if (this.entries.has(t.id)) throw Error(`Command already registered: ${t.id}`);
1327
+ let n = t.shortcut ? Te(t.shortcut, this.platform) : void 0;
1328
+ if (n && [...this.entries.values()].some((e) => e.signature === n)) throw Error(`Shortcut already registered: ${t.shortcut}`);
1329
+ let r = {
1330
+ definition: t,
1331
+ signature: n
1332
+ };
1333
+ return this.entries.set(t.id, r), this.publish(), () => {
1334
+ this.entries.get(t.id) === r && (this.entries.delete(t.id), this.publish());
1335
+ };
1336
+ };
1337
+ getCommands = () => this.snapshot;
1338
+ subscribe = (e) => (this.listeners.add(e), () => {
1339
+ this.listeners.delete(e);
1340
+ });
1341
+ canExecute = (e) => {
1342
+ let t = this.entries.get(e);
1343
+ return !!t && !this.running.has(t) && (t.definition.isEnabled?.() ?? !0);
1344
+ };
1345
+ execute = async (e) => {
1346
+ let t = this.entries.get(e);
1347
+ if (!t || !this.canExecute(e)) return !1;
1348
+ this.running.add(t), this.publish();
1349
+ try {
1350
+ return await t.definition.execute(), !0;
1351
+ } finally {
1352
+ this.running.delete(t), this.publish();
1353
+ }
1354
+ };
1355
+ matchShortcut = (e, t = !1) => {
1356
+ if (e.defaultPrevented || e.repeat || e.isComposing || e.getModifierState("AltGraph")) return;
1357
+ let n = we(e);
1358
+ for (let { definition: e, signature: r } of this.entries.values()) if (n === r && (!t || e.allowInEditable) && this.canExecute(e.id)) return e;
1359
+ };
1360
+ };
1361
+ // src/commands/CommandProvider.tsx
1362
+ function De({ children: e, registry: r }) {
1363
+ let [i] = c(() => r ?? new Ee(typeof navigator < "u" && /Mac|iPhone|iPad/.test(navigator.platform) ? "mac" : "other")), { t: a } = j(), s = n(q), l = t(async (e) => {
1364
+ try {
1365
+ return await i.execute(e);
1366
+ } catch (t) {
1367
+ if (!s) throw t;
1368
+ let n = i.getCommands().find((t) => t.id === e);
1369
+ return s.getState().notify({
1370
+ title: a("Command failed: {title}", { title: a(n?.title ?? e) }),
1371
+ description: a(t instanceof Error ? t.message : "The action could not be completed."),
1372
+ level: "error"
1373
+ }), !1;
1374
+ }
1375
+ }, [
1376
+ i,
1377
+ s,
1378
+ a
1379
+ ]), u = o(() => ({
1380
+ registry: i,
1381
+ execute: l
1382
+ }), [i, l]);
1383
+ return /* @__PURE__ */ v(Q.Provider, {
1384
+ value: u,
1385
+ children: e
1386
+ });
1387
+ }
1388
+ // src/layout/useWorkbenchCommands.ts
1389
+ function Oe(e, i, a, o) {
1390
+ let { t: c } = j(), l = n(Q);
1391
+ if (!l) throw Error("Workbench command provider is missing.");
1392
+ let { registry: u, execute: d } = l, { toggleTheme: f } = R(), { setOpen: p, notify: m } = J(), h = s(i);
1393
+ h.current = i;
1394
+ let g = s(o);
1395
+ return g.current = o, r(() => {
1396
+ let t = [
1397
+ {
1398
+ id: "workbench.commands.open",
1399
+ title: "Open command palette",
1400
+ shortcut: "Mod+Shift+P",
1401
+ execute: a
1402
+ },
1403
+ {
1404
+ id: "workbench.settings.open",
1405
+ title: "Open settings",
1406
+ execute: () => g.current.openSettings()
1407
+ },
1408
+ {
1409
+ id: "workbench.preferences.open",
1410
+ title: "Open preferences",
1411
+ execute: () => g.current.openPreferences()
1412
+ },
1413
+ {
1414
+ id: "workbench.configuration.import",
1415
+ title: "Import configuration",
1416
+ isEnabled: () => g.current.ready && !g.current.busy,
1417
+ execute: () => g.current.importConfiguration()
1418
+ },
1419
+ {
1420
+ id: "workbench.configuration.export",
1421
+ title: "Export configuration",
1422
+ isEnabled: () => g.current.ready,
1423
+ execute: () => g.current.exportConfiguration()
1424
+ },
1425
+ {
1426
+ id: "workbench.theme.toggle",
1427
+ title: "Toggle theme",
1428
+ shortcut: "Mod+Alt+T",
1429
+ execute: f
1430
+ },
1431
+ {
1432
+ id: "workbench.view.toggle",
1433
+ title: "Toggle header and footer",
1434
+ shortcut: "Mod+Alt+V",
1435
+ execute: () => e.getState().toggleView()
1436
+ },
1437
+ {
1438
+ id: "workbench.focus.toggle",
1439
+ title: "Toggle focus mode",
1440
+ shortcut: "Mod+Alt+F",
1441
+ execute: () => e.getState().toggleFocus()
1442
+ },
1443
+ {
1444
+ id: "workbench.focus.exit",
1445
+ title: "Exit focus mode",
1446
+ shortcut: "Escape",
1447
+ isEnabled: () => e.getState().focusMode,
1448
+ execute: () => e.getState().toggleFocus()
1449
+ },
1450
+ {
1451
+ id: "workbench.header.toggle",
1452
+ title: "Toggle header",
1453
+ shortcut: "Mod+Alt+H",
1454
+ execute: () => e.getState().toggleHeader()
1455
+ },
1456
+ {
1457
+ id: "workbench.footer.toggle",
1458
+ title: "Toggle footer",
1459
+ shortcut: "Mod+Alt+B",
1460
+ execute: () => e.getState().toggleFooter()
1461
+ },
1462
+ {
1463
+ id: "workbench.notifications.open",
1464
+ title: "Open notifications",
1465
+ shortcut: "Mod+Alt+N",
1466
+ execute: () => p(!0)
1467
+ },
1468
+ {
1469
+ id: "workbench.layout.save",
1470
+ title: "Save layout",
1471
+ shortcut: "Mod+Alt+S",
1472
+ isEnabled: () => h.current.ready,
1473
+ execute: () => {
1474
+ h.current.save();
1475
+ }
1476
+ },
1477
+ {
1478
+ id: "workbench.layout.restore",
1479
+ title: "Restore custom layout",
1480
+ shortcut: "Mod+Alt+R",
1481
+ isEnabled: () => h.current.ready && h.current.hasSaved,
1482
+ execute: () => {
1483
+ h.current.restore();
1484
+ }
1485
+ },
1486
+ {
1487
+ id: "workbench.layout.reset",
1488
+ title: "Reset layout",
1489
+ shortcut: "Mod+Alt+0",
1490
+ isEnabled: () => h.current.ready,
1491
+ execute: () => {
1492
+ h.current.reset();
1493
+ }
1494
+ },
1495
+ ...[
1496
+ "default",
1497
+ "columns",
1498
+ "rows"
1499
+ ].map((e, t) => ({
1500
+ id: `workbench.layout.${e}`,
1501
+ title: `Select ${e} layout`,
1502
+ shortcut: `Mod+Alt+${t + 1}`,
1503
+ isEnabled: () => h.current.ready,
1504
+ execute: () => {
1505
+ h.current.selectPreset(e);
1506
+ }
1507
+ }))
1508
+ ], n = [];
1509
+ try {
1510
+ for (let e of t) n.push(u.register({
1511
+ ...e,
1512
+ allowInEditable: !0
1513
+ }));
1514
+ } catch (e) {
1515
+ throw n.forEach((e) => e()), e;
1516
+ }
1517
+ return () => n.forEach((e) => e());
1518
+ }, [
1519
+ u,
1520
+ e,
1521
+ f,
1522
+ p,
1523
+ a
1524
+ ]), t((e) => {
1525
+ let t = e.target;
1526
+ if (!(t instanceof Element) || t.closest("dialog[open]")) return;
1527
+ let n = !!t.closest("input, textarea, select, [role=\"textbox\"]") || t instanceof HTMLElement && t.isContentEditable;
1528
+ try {
1529
+ let t = u.matchShortcut(e.nativeEvent, n);
1530
+ t && (e.preventDefault(), d(t.id).catch((e) => m({
1531
+ title: c("Command could not run"),
1532
+ description: c(e instanceof Error ? e.message : "The action failed."),
1533
+ level: "error"
1534
+ })));
1535
+ } catch (e) {
1536
+ m({
1537
+ title: c("Shortcut could not run"),
1538
+ description: c(e instanceof Error ? e.message : "The action is unavailable."),
1539
+ level: "error"
1540
+ });
1541
+ }
1542
+ }, [
1543
+ u,
1544
+ d,
1545
+ m,
1546
+ c
1547
+ ]);
1548
+ }
1549
+ // src/commands/searchCommands.ts
1550
+ function ke(e) {
1551
+ return e.normalize("NFD").replace(/\p{Diacritic}/gu, "").toLowerCase();
1552
+ }
1553
+ function Ae(e, t) {
1554
+ let n = e.indexOf(t);
1555
+ if (n >= 0) return n === 0 ? 0 : 10 + n;
1556
+ let r = 0, i = 0;
1557
+ for (let n of t) {
1558
+ let t = e.indexOf(n, r);
1559
+ if (t < 0) return Infinity;
1560
+ i += t - r, r = t + 1;
1561
+ }
1562
+ return 100 + i;
1563
+ }
1564
+ function je(e, t, n) {
1565
+ let r = ke(t.trim()).split(/\s+/).filter(Boolean);
1566
+ return e.map((e, t) => ({
1567
+ command: e,
1568
+ order: t,
1569
+ score: r.reduce((t, n) => t + Math.min(Ae(ke(e.title), n), Ae(ke(e.id), n) + 30), 0),
1570
+ recent: n.includes(e.id) ? n.indexOf(e.id) : Infinity
1571
+ })).filter((e) => Number.isFinite(e.score)).sort((e, t) => e.score - t.score || (r.length ? 0 : e.recent - t.recent) || e.order - t.order).map((e) => e.command);
1572
+ }
1573
+ // src/commands/CommandPalette.tsx
1574
+ function Me({ open: e, onClose: t }) {
1575
+ let { t: n } = j(), a = Y(t), { commands: l, canExecute: u, execute: d } = $(), { notify: f } = J(), [p, m] = c(""), [h, g] = c(null), [_, b] = c([]), x = s(null), S = s(null), C = i(), w = `${C}-commands`, T = o(() => je(l.filter((e) => e.id !== "workbench.commands.open").map((e) => ({
1576
+ ...e,
1577
+ title: n(e.title)
1578
+ })), p, _), [
1579
+ l,
1580
+ p,
1581
+ _,
1582
+ n
1583
+ ]).map((e, t) => {
1584
+ try {
1585
+ return {
1586
+ command: e,
1587
+ index: t,
1588
+ enabled: u(e.id),
1589
+ error: ""
1590
+ };
1591
+ } catch (n) {
1592
+ return {
1593
+ command: e,
1594
+ index: t,
1595
+ enabled: !1,
1596
+ error: n instanceof Error ? n.message : "Availability check failed."
1597
+ };
1598
+ }
1599
+ }), E = T.filter((e) => e.enabled), D = E.find((e) => e.command.id === h) ?? E[0], O = D ? `${C}-command-${D.index}` : void 0;
1600
+ r(() => {
1601
+ e ? (m(""), g(null), _e(x.current), S.current?.focus()) : Z(x.current);
1602
+ }, [e]), r(() => {
1603
+ e && O && document.getElementById(O)?.scrollIntoView({ block: "nearest" });
1604
+ }, [e, O]);
1605
+ let k = async (e) => {
1606
+ try {
1607
+ if (!u(e) || (t(), await Z(x.current), x.current?.open)) return;
1608
+ await d(e) && b((t) => [e, ...t.filter((t) => t !== e)].slice(0, 6));
1609
+ } catch (e) {
1610
+ f({
1611
+ title: n("Command could not run"),
1612
+ description: n(e instanceof Error ? e.message : "The action failed."),
1613
+ level: "error"
1614
+ });
1615
+ }
1616
+ };
1617
+ return /* @__PURE__ */ y("dialog", {
1618
+ ...a,
1619
+ ref: x,
1620
+ className: "dl-command-palette dl-modal",
1621
+ "aria-label": n("Command palette"),
1622
+ children: [
1623
+ /* @__PURE__ */ y("div", {
1624
+ className: "dl-palette-search",
1625
+ children: [
1626
+ /* @__PURE__ */ v("span", {
1627
+ "aria-hidden": "true",
1628
+ children: ">"
1629
+ }),
1630
+ /* @__PURE__ */ v("input", {
1631
+ ref: S,
1632
+ role: "combobox",
1633
+ "aria-label": n("Search commands"),
1634
+ "aria-expanded": e,
1635
+ "aria-autocomplete": "list",
1636
+ "aria-controls": w,
1637
+ "aria-activedescendant": O,
1638
+ autoComplete: "off",
1639
+ placeholder: n("Type a command…"),
1640
+ value: p,
1641
+ onChange: (e) => {
1642
+ m(e.target.value), g(null);
1643
+ },
1644
+ onKeyDown: (e) => {
1645
+ if (!(e.nativeEvent.isComposing || e.repeat)) {
1646
+ if (e.key === "ArrowDown" || e.key === "ArrowUp") {
1647
+ if (e.preventDefault(), !E.length) return;
1648
+ let t = (E.findIndex((e) => e.command.id === D?.command.id) + (e.key === "ArrowDown" ? 1 : -1) + E.length) % E.length;
1649
+ g(E[t].command.id);
1650
+ } else e.key === "Enter" && (e.preventDefault(), D && k(D.command.id));
1651
+ }
1652
+ }
1653
+ }),
1654
+ /* @__PURE__ */ v("button", {
1655
+ type: "button",
1656
+ className: "dl-icon-button dl-dialog-close",
1657
+ "aria-label": n("Close command palette"),
1658
+ onClick: t,
1659
+ children: "×"
1660
+ })
1661
+ ]
1662
+ }),
1663
+ /* @__PURE__ */ y("div", {
1664
+ id: w,
1665
+ className: "dl-palette-results",
1666
+ role: "listbox",
1667
+ "aria-label": n("Commands"),
1668
+ children: [T.map(({ command: e, index: t, enabled: r, error: i }) => /* @__PURE__ */ y("div", {
1669
+ id: `${C}-command-${t}`,
1670
+ role: "option",
1671
+ "aria-selected": D?.command.id === e.id,
1672
+ "aria-disabled": !r,
1673
+ className: "dl-palette-option",
1674
+ title: n((i || void 0) ?? ""),
1675
+ onMouseDown: (e) => e.preventDefault(),
1676
+ onMouseMove: () => {
1677
+ r && g(e.id);
1678
+ },
1679
+ onClick: () => {
1680
+ r && k(e.id);
1681
+ },
1682
+ children: [
1683
+ /* @__PURE__ */ y("span", { children: [e.title, i && /* @__PURE__ */ y("small", { children: [n("Unavailable:"), i] })] }),
1684
+ e.shortcut && /* @__PURE__ */ v("kbd", { children: e.shortcut }),
1685
+ !r && /* @__PURE__ */ v("span", {
1686
+ className: "dl-palette-unavailable",
1687
+ children: n("Unavailable")
1688
+ })
1689
+ ]
1690
+ }, e.id)), !T.length && /* @__PURE__ */ v("p", {
1691
+ className: "dl-palette-empty",
1692
+ children: n(l.length ? "No commands match your search." : "No commands are registered yet.")
1693
+ })]
1694
+ }),
1695
+ /* @__PURE__ */ y("footer", {
1696
+ className: "dl-palette-footer",
1697
+ children: [/* @__PURE__ */ y("span", {
1698
+ role: "status",
1699
+ children: [
1700
+ T.length,
1701
+ " ",
1702
+ n(T.length === 1 ? "command" : "commands")
1703
+ ]
1704
+ }), /* @__PURE__ */ y("span", { children: [
1705
+ /* @__PURE__ */ v("kbd", { children: "↑ ↓" }),
1706
+ n("navigate"),
1707
+ /* @__PURE__ */ v("kbd", { children: n("Enter") }),
1708
+ n("run"),
1709
+ /* @__PURE__ */ v("kbd", { children: n("Esc") }),
1710
+ n("close")
1711
+ ] })]
1712
+ })
1713
+ ]
1714
+ });
1715
+ }
1716
+ // src/plugins/PluginRegistry.ts
1717
+ function Ne(e) {
1718
+ return typeof e == "function" ? !0 : !e || typeof e != "object" || !("$$typeof" in e) ? !1 : [
1719
+ "react.memo",
1720
+ "react.forward_ref",
1721
+ "react.lazy"
1722
+ ].some((t) => e.$$typeof === Symbol.for(t));
1723
+ }
1724
+ var Pe = class {
1725
+ plugins = /* @__PURE__ */ new Set();
1726
+ panels = /* @__PURE__ */ new Map();
1727
+ commands = /* @__PURE__ */ new Map();
1728
+ menus = /* @__PURE__ */ new Map();
1729
+ statusItems = /* @__PURE__ */ new Map();
1730
+ monitoringItems = /* @__PURE__ */ new Map();
1731
+ stateHandlers = /* @__PURE__ */ new Map();
1732
+ commandValidator = new Ee();
1733
+ snapshot;
1734
+ activating = 0;
1735
+ assertMutable() {
1736
+ if (this.snapshot) throw Error("Plugin registration is closed. Create a new registry and remount the workbench.");
1737
+ }
1738
+ add(e, t, n) {
1739
+ if (this.assertMutable(), !t || typeof t.id != "string" || !t.id.trim()) throw Error("A contribution requires a nonempty ID.");
1740
+ if (e.has(t.id)) throw Error(`Duplicate plugin contribution: ${t.id}`);
1741
+ let r = Object.freeze({ ...t });
1742
+ e.set(r.id, r);
1743
+ let i = () => {
1744
+ this.assertMutable(), e.get(r.id) === r && e.delete(r.id);
1745
+ };
1746
+ return n.push(i), i;
1747
+ }
1748
+ registerPlugin(e) {
1749
+ if (this.assertMutable(), !e || typeof e.id != "string" || !e.id.trim() || typeof e.activate != "function") throw Error("Invalid plugin definition.");
1750
+ if (this.plugins.has(e.id)) throw Error(`Duplicate plugin: ${e.id}`);
1751
+ let t = e.id, n = [], r = !0, i, a = (e) => (n) => {
1752
+ if (!r) throw Error(`Plugin ${t} is no longer active.`);
1753
+ return e(n);
1754
+ }, o = (e, t) => {
1755
+ if (!Ne(t?.component)) throw Error("A plugin item requires a React component.");
1756
+ return this.add(e, t, n);
1757
+ }, s = {
1758
+ registerPanel: a((e) => {
1759
+ if (!e?.title?.trim() || !Ne(e.component)) throw Error("A plugin panel requires a title and React component.");
1760
+ return this.add(this.panels, {
1761
+ ...e,
1762
+ ...e.position ? { position: Object.freeze({ ...e.position }) } : {}
1763
+ }, n);
1764
+ }),
1765
+ registerCommand: a((e) => {
1766
+ if (typeof e?.execute != "function") throw Error("A plugin command requires an execute function.");
1767
+ if (e?.id?.startsWith("workbench.")) throw Error("The workbench.* command namespace is reserved.");
1768
+ let t = this.commandValidator.register({
1769
+ ...e,
1770
+ execute: () => {}
1771
+ });
1772
+ n.push(t);
1773
+ let r = this.add(this.commands, e, n);
1774
+ return () => {
1775
+ r(), t();
1776
+ };
1777
+ }),
1778
+ registerMenu: a((e) => {
1779
+ if (!e?.title?.trim() || !e.commandId?.trim()) throw Error("A plugin menu requires a title and command ID.");
1780
+ return this.add(this.menus, e, n);
1781
+ }),
1782
+ registerStatusItem: a((e) => o(this.statusItems, e)),
1783
+ registerMonitoringItem: a((e) => o(this.monitoringItems, e)),
1784
+ registerState: a((e) => {
1785
+ if (typeof e?.exportState != "function" || typeof e.importState != "function") throw Error("Plugin state requires exportState and importState callbacks.");
1786
+ return this.add(this.stateHandlers, {
1787
+ id: t,
1788
+ exportState: e.exportState,
1789
+ importState: e.importState
1790
+ }, n);
1791
+ })
1792
+ };
1793
+ this.plugins.add(t), this.activating++;
1794
+ try {
1795
+ if (i = e.activate(Object.freeze(s)), i !== void 0 && typeof i != "function") throw Error("Plugin activation must be synchronous and return void or a cleanup function.");
1796
+ } catch (e) {
1797
+ throw r = !1, n.reverse().forEach((e) => e()), this.plugins.delete(t), Error(`Plugin ${t} could not start: ${e instanceof Error ? e.message : "Activation failed."}`, { cause: e });
1798
+ } finally {
1799
+ this.activating--;
1800
+ }
1801
+ return () => {
1802
+ this.assertMutable(), r && (r = !1, n.reverse().forEach((e) => e()), this.plugins.delete(t), i?.());
1803
+ };
1804
+ }
1805
+ seal() {
1806
+ if (this.activating) throw Error("Plugins must finish activating before the registry is sealed.");
1807
+ return this.snapshot ||= Object.freeze({
1808
+ pluginIds: Object.freeze([...this.plugins]),
1809
+ panels: Object.freeze([...this.panels.values()]),
1810
+ commands: Object.freeze([...this.commands.values()]),
1811
+ menus: Object.freeze([...this.menus.values()]),
1812
+ statusItems: Object.freeze([...this.statusItems.values()]),
1813
+ monitoringItems: Object.freeze([...this.monitoringItems.values()]),
1814
+ stateHandlers: Object.freeze(Object.fromEntries(this.stateHandlers))
1815
+ }), this.snapshot;
1816
+ }
1817
+ };
1818
+ function Fe(e) {
1819
+ let t = new Pe(), n = [];
1820
+ try {
1821
+ for (let r of Object.keys(e).sort()) n.push(t.registerPlugin(e[r].default));
1822
+ return t;
1823
+ } catch (e) {
1824
+ throw n.reverse().forEach((e) => e()), e;
1825
+ }
1826
+ }
1827
+ // src/plugins/PluginContext.ts
1828
+ var Ie = new Pe().seal(), Le = e(Ie);
1829
+ function Re(e) {
1830
+ let { t } = j(), { register: n, execute: i } = $(), { notify: a } = J();
1831
+ r(() => {
1832
+ let r = [];
1833
+ try {
1834
+ for (let t of e.commands) r.push(n({
1835
+ ...t,
1836
+ execute: () => t.execute({
1837
+ notify: a,
1838
+ executeCommand: i
1839
+ })
1840
+ }));
1841
+ } catch (e) {
1842
+ r.reverse().forEach((e) => e()), r.length = 0, a({
1843
+ title: t("Plugin commands could not be registered"),
1844
+ description: t(e instanceof Error ? e.message : "Command registration failed."),
1845
+ level: "error"
1846
+ });
1847
+ }
1848
+ return () => r.reverse().forEach((e) => e());
1849
+ }, [
1850
+ e,
1851
+ n,
1852
+ i,
1853
+ a,
1854
+ t
1855
+ ]);
1856
+ }
1857
+ // src/settings/ApplicationMenu.tsx
1858
+ function ze() {
1859
+ let { t: e } = j(), { family: t, setFamily: r } = R(), [i, a] = c(!1), o = s(null), { execute: l, canExecute: u } = $(), { menus: d } = n(Le), p = (e) => {
1860
+ try {
1861
+ return u(e);
1862
+ } catch {
1863
+ return !1;
1864
+ }
1865
+ };
1866
+ return /* @__PURE__ */ v(f, {
1867
+ open: i,
1868
+ onOpenChange: a,
1869
+ trigger: ["click"],
1870
+ autoFocus: !0,
1871
+ destroyOnHidden: !0,
1872
+ menu: {
1873
+ "aria-label": e("Application menu"),
1874
+ triggerSubMenuAction: "click",
1875
+ selectable: !0,
1876
+ selectedKeys: [`theme:${t}`],
1877
+ items: [
1878
+ {
1879
+ key: "file",
1880
+ label: e("File"),
1881
+ children: [
1882
+ {
1883
+ key: "workbench.settings.open",
1884
+ label: e("Settings")
1885
+ },
1886
+ {
1887
+ key: "workbench.preferences.open",
1888
+ label: e("Preferences")
1889
+ },
1890
+ { type: "divider" },
1891
+ {
1892
+ key: "workbench.configuration.import",
1893
+ label: e("Import configuration…"),
1894
+ disabled: !u("workbench.configuration.import")
1895
+ },
1896
+ {
1897
+ key: "workbench.configuration.export",
1898
+ label: e("Export configuration…"),
1899
+ disabled: !u("workbench.configuration.export")
1900
+ }
1901
+ ]
1902
+ },
1903
+ {
1904
+ key: "theme",
1905
+ label: e("Theme"),
1906
+ children: Object.entries(N).map(([t, n]) => ({
1907
+ key: `theme:${t}`,
1908
+ label: e(n)
1909
+ }))
1910
+ },
1911
+ ...d.length ? [{
1912
+ key: "plugins",
1913
+ label: e("Plugins"),
1914
+ children: d.map((t) => ({
1915
+ key: `plugin-menu:${t.id}`,
1916
+ label: e(t.title),
1917
+ disabled: !p(t.commandId)
1918
+ }))
1919
+ }] : []
1920
+ ],
1921
+ onClick: ({ key: e }) => {
1922
+ if (a(!1), o.current?.focus(), e.startsWith("theme:")) {
1923
+ r(e.slice(6));
1924
+ return;
1925
+ }
1926
+ let t = d.find((t) => `plugin-menu:${t.id}` === e);
1927
+ l(t?.commandId ?? e);
1928
+ },
1929
+ onKeyDown: (e) => {
1930
+ e.key === "Escape" && (a(!1), o.current?.focus(), e.stopPropagation());
1931
+ }
1932
+ },
1933
+ children: /* @__PURE__ */ v("button", {
1934
+ ref: o,
1935
+ type: "button",
1936
+ className: "dl-icon-button dl-menu-trigger",
1937
+ "aria-label": e("Open application menu"),
1938
+ "aria-haspopup": "menu",
1939
+ "aria-expanded": i,
1940
+ onKeyDown: (e) => {
1941
+ e.key === "ArrowDown" && (e.preventDefault(), a(!0));
1942
+ },
1943
+ children: /* @__PURE__ */ v("svg", {
1944
+ width: "18",
1945
+ height: "18",
1946
+ viewBox: "0 0 24 24",
1947
+ fill: "none",
1948
+ stroke: "currentColor",
1949
+ strokeWidth: "1.5",
1950
+ "aria-hidden": "true",
1951
+ children: /* @__PURE__ */ v("path", { d: "M4 6h16M4 12h16M4 18h16" })
1952
+ })
1953
+ })
1954
+ });
1955
+ }
1956
+ // src/settings/SettingsDialog.tsx
1957
+ function Be({ page: e, onClose: t, configuration: n, layout: a, store: o }) {
1958
+ let { t: l, locales: d } = j(), f = s(null), p = Y(t), m = s(null), [h, g] = c(n.preferences), [_, b] = c(""), [x, S] = c(e ?? "settings"), C = i(), w = u(o), { execute: T } = $(), E = s(n.preferences);
1959
+ E.current = n.preferences, r(() => {
1960
+ e ? (S(e), g(structuredClone(E.current)), b(""), _e(f.current), m.current?.focus()) : Z(f.current);
1961
+ }, [e]);
1962
+ let D = (e) => {
1963
+ e.preventDefault();
1964
+ try {
1965
+ n.savePreferences(h), t();
1966
+ } catch (e) {
1967
+ b(e instanceof Error ? e.message : "Preferences could not be applied.");
1968
+ }
1969
+ };
1970
+ return /* @__PURE__ */ y("dialog", {
1971
+ ...p,
1972
+ ref: f,
1973
+ className: "dl-settings-dialog dl-modal",
1974
+ "aria-labelledby": C,
1975
+ children: [/* @__PURE__ */ y("header", { children: [/* @__PURE__ */ v("h2", {
1976
+ id: C,
1977
+ children: l(x === "preferences" ? "Preferences" : "Settings")
1978
+ }), /* @__PURE__ */ v("button", {
1979
+ ref: m,
1980
+ type: "button",
1981
+ className: "dl-icon-button dl-dialog-close",
1982
+ "aria-label": l("Close settings"),
1983
+ onClick: t,
1984
+ children: "×"
1985
+ })] }), x === "preferences" ? /* @__PURE__ */ y("form", {
1986
+ onSubmit: D,
1987
+ children: [
1988
+ /* @__PURE__ */ v("p", { children: l("Choose how this application looks and notifies you.") }),
1989
+ /* @__PURE__ */ y("label", {
1990
+ className: "dl-settings-field",
1991
+ children: [l("Color theme"), /* @__PURE__ */ y("select", {
1992
+ value: h.theme,
1993
+ onChange: (e) => g({
1994
+ ...h,
1995
+ theme: e.target.value
1996
+ }),
1997
+ children: [/* @__PURE__ */ v("option", {
1998
+ value: "light",
1999
+ children: l("Light")
2000
+ }), /* @__PURE__ */ v("option", {
2001
+ value: "dark",
2002
+ children: l("Dark")
2003
+ })]
2004
+ })]
2005
+ }),
2006
+ /* @__PURE__ */ y("label", {
2007
+ className: "dl-settings-field",
2008
+ children: [l("Animations"), /* @__PURE__ */ y("select", {
2009
+ value: h.motion,
2010
+ onChange: (e) => g({
2011
+ ...h,
2012
+ motion: e.target.value
2013
+ }),
2014
+ children: [/* @__PURE__ */ v("option", {
2015
+ value: "system",
2016
+ children: l("Follow system")
2017
+ }), /* @__PURE__ */ v("option", {
2018
+ value: "reduced",
2019
+ children: l("Reduce motion")
2020
+ })]
2021
+ })]
2022
+ }),
2023
+ /* @__PURE__ */ y("label", {
2024
+ className: "dl-settings-field",
2025
+ children: [l("Language"), /* @__PURE__ */ v("select", {
2026
+ "aria-label": l("Language"),
2027
+ value: h.locale ?? "en",
2028
+ onChange: (e) => g({
2029
+ ...h,
2030
+ locale: e.target.value
2031
+ }),
2032
+ children: d.map((e) => /* @__PURE__ */ v("option", {
2033
+ value: e.id,
2034
+ children: e.label
2035
+ }, e.id))
2036
+ })]
2037
+ }),
2038
+ /* @__PURE__ */ y("label", {
2039
+ className: "dl-settings-field",
2040
+ children: [l("Theme"), /* @__PURE__ */ v("select", {
2041
+ value: h.themeFamily ?? "azure",
2042
+ onChange: (e) => g({
2043
+ ...h,
2044
+ themeFamily: e.target.value
2045
+ }),
2046
+ children: Object.entries(N).map(([e, t]) => /* @__PURE__ */ v("option", {
2047
+ value: e,
2048
+ children: l(t)
2049
+ }, e))
2050
+ })]
2051
+ }),
2052
+ /* @__PURE__ */ y("label", {
2053
+ className: "dl-settings-check",
2054
+ children: [/* @__PURE__ */ v("input", {
2055
+ type: "checkbox",
2056
+ checked: h.notifications.toastsEnabled,
2057
+ onChange: (e) => g({
2058
+ ...h,
2059
+ notifications: {
2060
+ ...h.notifications,
2061
+ toastsEnabled: e.target.checked
2062
+ }
2063
+ })
2064
+ }), l("Show notification popups")]
2065
+ }),
2066
+ /* @__PURE__ */ y("label", {
2067
+ className: "dl-settings-field",
2068
+ children: [l("Popup duration (seconds)"), /* @__PURE__ */ v("input", {
2069
+ type: "number",
2070
+ min: 1,
2071
+ max: 30,
2072
+ step: 1,
2073
+ required: !0,
2074
+ value: Number.isFinite(h.notifications.toastDurationMs) ? h.notifications.toastDurationMs / 1e3 : "",
2075
+ onChange: (e) => g({
2076
+ ...h,
2077
+ notifications: {
2078
+ ...h.notifications,
2079
+ toastDurationMs: e.target.valueAsNumber * 1e3
2080
+ }
2081
+ })
2082
+ })]
2083
+ }),
2084
+ /* @__PURE__ */ v("p", {
2085
+ className: "dl-settings-hint",
2086
+ children: l("History is always available. Errors remain visible until dismissed. System reduced-motion preferences always apply.")
2087
+ }),
2088
+ _ && /* @__PURE__ */ v("p", {
2089
+ role: "alert",
2090
+ className: "dl-settings-error",
2091
+ children: _
2092
+ }),
2093
+ /* @__PURE__ */ y("footer", { children: [/* @__PURE__ */ v("button", {
2094
+ type: "button",
2095
+ onClick: t,
2096
+ children: l("Cancel")
2097
+ }), /* @__PURE__ */ v("button", {
2098
+ type: "submit",
2099
+ className: "dl-settings-primary",
2100
+ children: l("Apply preferences")
2101
+ })] })
2102
+ ]
2103
+ }) : /* @__PURE__ */ y("div", { children: [
2104
+ /* @__PURE__ */ v("p", { children: l("Changes and the custom layout are saved automatically.") }),
2105
+ /* @__PURE__ */ y("fieldset", { children: [
2106
+ /* @__PURE__ */ v("legend", { children: l("Workspace") }),
2107
+ /* @__PURE__ */ y("label", {
2108
+ className: "dl-settings-check",
2109
+ children: [/* @__PURE__ */ v("input", {
2110
+ type: "checkbox",
2111
+ checked: w.headerVisible,
2112
+ onChange: w.toggleHeader
2113
+ }), l("Show header")]
2114
+ }),
2115
+ /* @__PURE__ */ y("label", {
2116
+ className: "dl-settings-check",
2117
+ children: [/* @__PURE__ */ v("input", {
2118
+ type: "checkbox",
2119
+ checked: w.footerVisible,
2120
+ onChange: w.toggleFooter
2121
+ }), l("Show footer")]
2122
+ }),
2123
+ /* @__PURE__ */ y("div", {
2124
+ className: "dl-settings-actions",
2125
+ children: [/* @__PURE__ */ v("button", {
2126
+ type: "button",
2127
+ disabled: !a.ready || !a.hasSaved,
2128
+ onClick: a.restore,
2129
+ children: l("Restore custom layout")
2130
+ }), /* @__PURE__ */ v("button", {
2131
+ type: "button",
2132
+ disabled: !a.ready,
2133
+ onClick: () => a.reset(),
2134
+ children: l("Reset workspace layout")
2135
+ })]
2136
+ })
2137
+ ] }),
2138
+ /* @__PURE__ */ y("fieldset", { children: [
2139
+ /* @__PURE__ */ v("legend", { children: l("Configuration") }),
2140
+ /* @__PURE__ */ v("p", { children: l("Transfer layout, preferences, and participating plugin data as a JSON file. Notification history stays in this session.") }),
2141
+ /* @__PURE__ */ y("div", {
2142
+ className: "dl-settings-actions",
2143
+ children: [/* @__PURE__ */ v("button", {
2144
+ type: "button",
2145
+ disabled: !n.ready || n.busy,
2146
+ onClick: () => {
2147
+ T("workbench.configuration.import");
2148
+ },
2149
+ children: l("Import configuration")
2150
+ }), /* @__PURE__ */ v("button", {
2151
+ type: "button",
2152
+ disabled: !n.ready,
2153
+ onClick: () => {
2154
+ T("workbench.configuration.export");
2155
+ },
2156
+ children: l("Export configuration")
2157
+ })]
2158
+ }),
2159
+ n.busy && /* @__PURE__ */ v("p", {
2160
+ role: "status",
2161
+ children: l("Reading configuration…")
2162
+ })
2163
+ ] }),
2164
+ /* @__PURE__ */ v("footer", { children: /* @__PURE__ */ v("button", {
2165
+ type: "button",
2166
+ onClick: t,
2167
+ children: l("Close")
2168
+ }) })
2169
+ ] })]
2170
+ });
2171
+ }
2172
+ function Ve(e) {
2173
+ let t = e;
2174
+ if (!t || !["light", "dark"].includes(t.theme ?? "") || !["system", "reduced"].includes(t.motion ?? "")) throw Error("Preferences have an invalid theme or animation choice.");
2175
+ if (t.themeFamily !== void 0 && !Object.hasOwn(N, t.themeFamily)) throw Error("Preferences have an invalid theme family.");
2176
+ if (ue(t.notifications), t.locale !== void 0 && (typeof t.locale != "string" || !/^[a-z]{2,8}(-[a-z0-9]{1,8})*$/i.test(t.locale))) throw Error("Preferences have an invalid language identifier.");
2177
+ return {
2178
+ ...t.locale === void 0 ? {} : { locale: t.locale },
2179
+ theme: t.theme,
2180
+ ...t.themeFamily === void 0 ? {} : { themeFamily: t.themeFamily },
2181
+ motion: t.motion,
2182
+ notifications: {
2183
+ toastsEnabled: t.notifications.toastsEnabled,
2184
+ toastDurationMs: t.notifications.toastDurationMs
2185
+ }
2186
+ };
2187
+ }
2188
+ function He(e, t) {
2189
+ if (new TextEncoder().encode(e).byteLength > 1e6) throw Error("Configuration exceeds the 1 MB limit.");
2190
+ let n = JSON.parse(e);
2191
+ if (!n || n.format !== "dash-lab" || n.version !== 1) throw Error("Configuration has an unsupported format or version.");
2192
+ let r = Ve(n.preferences);
2193
+ if (n.workspace === void 0) throw Error("Configuration is missing a workspace.");
2194
+ let i = n.workspace === null ? null : oe(JSON.stringify(n.workspace), t);
2195
+ if (i === null && t.length) throw Error("Configuration is missing this application’s workspace.");
2196
+ return i && delete i.plugins, {
2197
+ format: "dash-lab",
2198
+ version: 1,
2199
+ workspace: i,
2200
+ preferences: r,
2201
+ ...n.plugins === void 0 ? {} : { plugins: V(n.plugins) }
2202
+ };
2203
+ }
2204
+ // src/settings/useWorkbenchConfiguration.ts
2205
+ function Ue(e, n, i, a) {
2206
+ let { locale: o, setLocale: l, assertLocale: u, t: d } = j(), { mode: f, family: p, motionPreference: m, setMode: h, setFamily: g, setMotionPreference: _ } = R(), { preferences: v, setPreferences: y, notify: b } = J(), x = {
2207
+ locale: o,
2208
+ theme: f,
2209
+ themeFamily: p,
2210
+ motion: m,
2211
+ notifications: v
2212
+ }, S = JSON.stringify(x), C = s(S), w = s(!1), [T, E] = c(!1), [D, O] = c(!1), k = s(null), A = s(e);
2213
+ A.current = e;
2214
+ let M = t((e) => {
2215
+ let t = Ve(e);
2216
+ return u(t.locale ?? "en"), l(t.locale ?? "en"), h(t.theme), g(t.themeFamily ?? "azure"), _(t.motion), y(t.notifications), t;
2217
+ }, [
2218
+ h,
2219
+ g,
2220
+ _,
2221
+ y,
2222
+ l,
2223
+ u
2224
+ ]), N = t((e) => {
2225
+ if (C.current = JSON.stringify(e), !i) return !0;
2226
+ try {
2227
+ return localStorage.setItem(i, JSON.stringify({
2228
+ version: 1,
2229
+ preferences: e
2230
+ })), !0;
2231
+ } catch {
2232
+ return !1;
2233
+ }
2234
+ }, [i]);
2235
+ r(() => {
2236
+ if (!w.current) {
2237
+ w.current = !0;
2238
+ try {
2239
+ let e = i ? localStorage.getItem(i) : null;
2240
+ if (e) {
2241
+ if (e.length > 1e6) throw Error("Saved preferences exceed the size limit.");
2242
+ let t = JSON.parse(e);
2243
+ if (!t || t.version !== 1) throw Error("Saved preferences have an unsupported version.");
2244
+ let n = M(Ve(t.preferences));
2245
+ C.current = JSON.stringify(n);
2246
+ }
2247
+ } catch (e) {
2248
+ b({
2249
+ title: d("Preferences could not be restored"),
2250
+ description: d(e instanceof Error ? e.message : "Browser storage is unavailable."),
2251
+ level: "warning"
2252
+ });
2253
+ }
2254
+ E(!0);
2255
+ }
2256
+ }, [
2257
+ M,
2258
+ b,
2259
+ i,
2260
+ d
2261
+ ]), r(() => {
2262
+ T && S !== C.current && (N(JSON.parse(S)) || b({
2263
+ title: d("Preferences kept for this session"),
2264
+ description: d("Browser storage is unavailable or full."),
2265
+ level: "warning"
2266
+ }));
2267
+ }, [
2268
+ T,
2269
+ S,
2270
+ N,
2271
+ b,
2272
+ d
2273
+ ]);
2274
+ let ee = t((e) => {
2275
+ let t = N(M(e));
2276
+ b({
2277
+ title: d(t ? i ? "Preferences saved." : "Preferences applied for this session." : "Preferences kept for this session"),
2278
+ ...t ? {} : { description: "Browser storage is unavailable or full." },
2279
+ level: t ? "success" : "warning"
2280
+ });
2281
+ }, [
2282
+ M,
2283
+ N,
2284
+ b,
2285
+ i,
2286
+ d
2287
+ ]), P = t(async (e) => {
2288
+ O(!0);
2289
+ try {
2290
+ if (e.size > 1e6) throw Error("Configuration exceeds the 1 MB limit.");
2291
+ let t = He(await e.text(), n);
2292
+ if (u(t.preferences.locale ?? "en"), t.workspace) {
2293
+ if (!A.current.apply({
2294
+ ...t.workspace,
2295
+ plugins: t.plugins ?? {}
2296
+ })) throw Error("The workspace is not ready yet.");
2297
+ } else W(a, t.plugins ?? {}, () => {});
2298
+ let r = N(M(t.preferences)), i = !t.workspace || A.current.save(!0), o = r && i;
2299
+ b({
2300
+ title: d(o ? "Configuration imported." : "Configuration imported for this session"),
2301
+ ...o ? {} : { description: "Browser storage is unavailable or full. Export a copy to keep these choices." },
2302
+ level: o ? "success" : "warning"
2303
+ });
2304
+ } catch (e) {
2305
+ b({
2306
+ title: d("Configuration could not be imported"),
2307
+ description: d(e instanceof Error ? e.message : "The file could not be read."),
2308
+ level: "error"
2309
+ });
2310
+ } finally {
2311
+ O(!1);
2312
+ }
2313
+ }, [
2314
+ M,
2315
+ n,
2316
+ N,
2317
+ b,
2318
+ u,
2319
+ a,
2320
+ d
2321
+ ]), F = t(() => {
2322
+ let e = A.current.capture(), t = e?.plugins ?? H(a);
2323
+ e && delete e.plugins;
2324
+ let r = {
2325
+ format: "dash-lab",
2326
+ version: 1,
2327
+ workspace: e,
2328
+ preferences: JSON.parse(S),
2329
+ ...Object.keys(t).length ? { plugins: t } : {}
2330
+ };
2331
+ if (n.length && !r.workspace) throw Error("The workspace is not ready yet.");
2332
+ let i = JSON.stringify(r, null, 2);
2333
+ if (new TextEncoder().encode(i).byteLength > 1e6) throw Error("Configuration exceeds the 1 MB limit.");
2334
+ let o = URL.createObjectURL(new Blob([i], { type: "application/json" })), s = document.createElement("a");
2335
+ s.href = o, s.download = "dash-lab-configuration.json", s.hidden = !0, document.body.appendChild(s), s.click(), s.remove(), setTimeout(() => URL.revokeObjectURL(o), 1e3), b({
2336
+ title: d("Configuration exported."),
2337
+ level: "success"
2338
+ });
2339
+ }, [
2340
+ S,
2341
+ n.length,
2342
+ b,
2343
+ a,
2344
+ d
2345
+ ]);
2346
+ return {
2347
+ preferences: x,
2348
+ savePreferences: ee,
2349
+ importFile: P,
2350
+ chooseImport: t(() => k.current?.click(), []),
2351
+ exportConfiguration: F,
2352
+ input: k,
2353
+ busy: D,
2354
+ ready: T && (!n.length || e.ready)
2355
+ };
2356
+ }
2357
+ // src/layout/Workbench.tsx
2358
+ var We = [];
2359
+ function Ge({ name: e }) {
2360
+ return /* @__PURE__ */ v("svg", {
2361
+ width: "16",
2362
+ height: "16",
2363
+ viewBox: "0 0 24 24",
2364
+ fill: "none",
2365
+ stroke: "currentColor",
2366
+ strokeWidth: "1.5",
2367
+ "aria-hidden": "true",
2368
+ children: e === "focus" ? /* @__PURE__ */ v("path", { d: "M8 3H3v5m13-5h5v5M3 16v5h5m13-5v5h-5" }) : /* @__PURE__ */ y(_, { children: [/* @__PURE__ */ v("rect", {
2369
+ x: "3",
2370
+ y: "4",
2371
+ width: "18",
2372
+ height: "16",
2373
+ rx: "2"
2374
+ }), /* @__PURE__ */ v("path", { d: "M3 9h18M3 15h18" })] })
2375
+ });
2376
+ }
2377
+ function Ke(e) {
2378
+ return n(D) ? /* @__PURE__ */ v(qe, { ...e }) : /* @__PURE__ */ v(A, { children: /* @__PURE__ */ v(qe, { ...e }) });
2379
+ }
2380
+ function qe(e) {
2381
+ return n(I) ? /* @__PURE__ */ v(Je, { ...e }) : /* @__PURE__ */ v(L, { children: /* @__PURE__ */ v(Je, { ...e }) });
2382
+ }
2383
+ function Je(e) {
2384
+ return n(q) ? /* @__PURE__ */ v(Ye, { ...e }) : /* @__PURE__ */ v(ye, { children: /* @__PURE__ */ v(Ye, { ...e }) });
2385
+ }
2386
+ function Ye(e) {
2387
+ return n(Q) ? /* @__PURE__ */ v(Xe, { ...e }) : /* @__PURE__ */ v(De, { children: /* @__PURE__ */ v(Xe, { ...e }) });
2388
+ }
2389
+ function Xe({ title: e, subtitle: n, logo: i, headerActions: a, controlBar: l, monitoringBar: d, footer: f, panels: p = We, plugins: m, onWorkspaceReady: h, initialHeaderVisible: g = !0, initialFooterVisible: _ = !0, layoutStorageKey: b, preferencesStorageKey: x, children: S }) {
2390
+ let { t: C } = j(), [w] = c(() => m?.seal() ?? Ie), T = o(() => [...w.panels, ...p], [w, p]), [E] = c(() => re(g, _)), [D, O] = c(null), [k] = c(() => b ?? `dash-lab:${encodeURIComponent(e)}:layout:v1`), A = ce(D, T, E, k, h, w.stateHandlers), [M] = c(() => x ?? `dash-lab:${encodeURIComponent(e)}:preferences:v1`), N = Ue(A, T, M, w.stateHandlers), [ee, P] = c(null), F = t(() => P(null), []), [I, L] = c(!1), R = t(() => L(!0), []), te = t(() => L(!1), []), z = Oe(E, A, R, {
2391
+ openSettings: () => P("settings"),
2392
+ openPreferences: () => P("preferences"),
2393
+ importConfiguration: N.chooseImport,
2394
+ exportConfiguration: N.exportConfiguration,
2395
+ ready: N.ready,
2396
+ busy: N.busy
2397
+ });
2398
+ Re(w);
2399
+ let B = s(null), { notify: V } = J(), H = s(A.feedback), U = u(E), W = s(null), G = s(null), K = s(!1);
2400
+ return r(() => {
2401
+ document.activeElement === document.body && B.current?.focus({ preventScroll: !0 });
2402
+ }, []), r(() => {
2403
+ A.feedback && H.current !== A.feedback && (H.current = A.feedback, V({
2404
+ title: C(A.feedback.message),
2405
+ level: A.feedback.error ? "error" : "info"
2406
+ }));
2407
+ }, [
2408
+ A.feedback,
2409
+ V,
2410
+ C
2411
+ ]), r(() => {
2412
+ U.focusMode ? W.current?.focus() : K.current && G.current?.focus(), K.current = U.focusMode;
2413
+ }, [U.focusMode]), /* @__PURE__ */ v(Le.Provider, {
2414
+ value: w,
2415
+ children: /* @__PURE__ */ y("section", {
2416
+ className: "dl-workbench",
2417
+ ref: B,
2418
+ tabIndex: -1,
2419
+ "aria-label": C(e ?? ""),
2420
+ "data-focus-mode": U.focusMode,
2421
+ onKeyDown: z,
2422
+ children: [
2423
+ !U.focusMode && U.headerVisible && /* @__PURE__ */ y("header", {
2424
+ className: "dl-header",
2425
+ children: [/* @__PURE__ */ y("div", {
2426
+ className: "dl-identity",
2427
+ children: [
2428
+ i,
2429
+ /* @__PURE__ */ v("strong", { children: e }),
2430
+ n && /* @__PURE__ */ v("span", {
2431
+ className: "dl-subtitle",
2432
+ children: n
2433
+ })
2434
+ ]
2435
+ }), /* @__PURE__ */ v("div", {
2436
+ className: "dl-header-actions",
2437
+ children: a
2438
+ })]
2439
+ }),
2440
+ !U.focusMode && /* @__PURE__ */ y("div", {
2441
+ className: "dl-control-bar",
2442
+ role: "toolbar",
2443
+ "aria-label": C("Workbench controls"),
2444
+ children: [/* @__PURE__ */ y("div", {
2445
+ className: "dl-application-controls",
2446
+ children: [/* @__PURE__ */ v(ze, {}), l]
2447
+ }), /* @__PURE__ */ y("div", {
2448
+ className: "dl-view-controls",
2449
+ children: [
2450
+ /* @__PURE__ */ y("button", {
2451
+ type: "button",
2452
+ className: "dl-icon-button dl-palette-trigger",
2453
+ "aria-label": C("Open command palette"),
2454
+ "aria-haspopup": "dialog",
2455
+ "aria-expanded": I,
2456
+ title: C("Commands (Ctrl/⌘+Shift+P)"),
2457
+ onClick: R,
2458
+ children: [/* @__PURE__ */ y("svg", {
2459
+ width: "15",
2460
+ height: "15",
2461
+ viewBox: "0 0 24 24",
2462
+ fill: "none",
2463
+ stroke: "currentColor",
2464
+ strokeWidth: "1.5",
2465
+ "aria-hidden": "true",
2466
+ children: [/* @__PURE__ */ v("circle", {
2467
+ cx: "10",
2468
+ cy: "10",
2469
+ r: "6"
2470
+ }), /* @__PURE__ */ v("path", { d: "m15 15 6 6" })]
2471
+ }), /* @__PURE__ */ v("span", { children: C("Commands") })]
2472
+ }),
2473
+ /* @__PURE__ */ v("span", { className: "dl-divider" }),
2474
+ /* @__PURE__ */ v(be, {}),
2475
+ /* @__PURE__ */ v("span", { className: "dl-divider" }),
2476
+ /* @__PURE__ */ v(ae, { layout: A }),
2477
+ /* @__PURE__ */ v("span", { className: "dl-divider" }),
2478
+ /* @__PURE__ */ v(ie, {}),
2479
+ /* @__PURE__ */ v("span", { className: "dl-divider" }),
2480
+ /* @__PURE__ */ y("button", {
2481
+ type: "button",
2482
+ className: "dl-icon-button",
2483
+ "aria-label": C(U.headerVisible || U.footerVisible ? "Hide header and footer" : "Show header and footer"),
2484
+ title: C("Toggle header and footer (Ctrl/⌘+Alt+V)"),
2485
+ "aria-pressed": U.headerVisible === U.footerVisible ? U.headerVisible : "mixed",
2486
+ onClick: U.toggleView,
2487
+ children: [/* @__PURE__ */ v(Ge, { name: "view" }), /* @__PURE__ */ v("span", { children: C("View") })]
2488
+ }),
2489
+ /* @__PURE__ */ v("span", { className: "dl-divider" }),
2490
+ /* @__PURE__ */ y("button", {
2491
+ type: "button",
2492
+ ref: G,
2493
+ className: "dl-icon-button dl-focus-button",
2494
+ "aria-label": C("Enter focus mode"),
2495
+ title: C("Focus workspace"),
2496
+ onClick: U.toggleFocus,
2497
+ children: [/* @__PURE__ */ v(Ge, { name: "focus" }), /* @__PURE__ */ v("span", { children: C("Focus") })]
2498
+ })
2499
+ ]
2500
+ })]
2501
+ }),
2502
+ !U.focusMode && (d || w.monitoringItems.length > 0) && /* @__PURE__ */ y("aside", {
2503
+ className: "dl-monitoring-bar",
2504
+ "aria-label": C("Monitoring"),
2505
+ children: [d, w.monitoringItems.map(({ id: e, component: t }) => /* @__PURE__ */ v("span", {
2506
+ "data-plugin-monitoring-item": e,
2507
+ children: /* @__PURE__ */ v(t, {})
2508
+ }, e))]
2509
+ }),
2510
+ /* @__PURE__ */ v("main", {
2511
+ className: "dl-workspace",
2512
+ "aria-label": C("Workspace"),
2513
+ children: T.length ? /* @__PURE__ */ v(ne, {
2514
+ panels: T,
2515
+ onReady: O
2516
+ }) : /* @__PURE__ */ v("div", {
2517
+ className: "dl-empty-workspace",
2518
+ children: S ?? C("No panels have been added to this workspace.")
2519
+ })
2520
+ }),
2521
+ !U.focusMode && U.footerVisible && (f || w.statusItems.length > 0) && /* @__PURE__ */ y("footer", {
2522
+ className: "dl-footer",
2523
+ children: [f, w.statusItems.map(({ id: e, component: t }) => /* @__PURE__ */ v("span", {
2524
+ "data-plugin-status-item": e,
2525
+ children: /* @__PURE__ */ v(t, {})
2526
+ }, e))]
2527
+ }),
2528
+ /* @__PURE__ */ v(Me, {
2529
+ open: I,
2530
+ onClose: te
2531
+ }),
2532
+ /* @__PURE__ */ v(Be, {
2533
+ page: ee,
2534
+ onClose: F,
2535
+ configuration: N,
2536
+ layout: A,
2537
+ store: E
2538
+ }),
2539
+ /* @__PURE__ */ v("input", {
2540
+ type: "file",
2541
+ ref: N.input,
2542
+ hidden: !0,
2543
+ accept: "application/json,.json",
2544
+ "aria-label": C("Import configuration file"),
2545
+ onChange: (e) => {
2546
+ let t = e.target.files?.[0];
2547
+ e.target.value = "", t && N.importFile(t);
2548
+ }
2549
+ }),
2550
+ U.focusMode && /* @__PURE__ */ y("button", {
2551
+ ref: W,
2552
+ type: "button",
2553
+ className: "dl-exit-focus",
2554
+ onClick: U.toggleFocus,
2555
+ children: [C("Exit focus mode"), /* @__PURE__ */ v("kbd", { children: C("Esc") })]
2556
+ })
2557
+ ]
2558
+ })
2559
+ });
2560
+ }
2561
+ export { Me as CommandPalette, De as CommandProvider, Ee as CommandRegistry, A as I18nProvider, be as NotificationButton, ye as NotificationProvider, Pe as PluginRegistry, L as ThemeProvider, ie as ThemeToggle, Ke as Workbench, He as decodeConfiguration, Fe as registerLocalPlugins, $ as useCommands, j as useI18n, J as useNotifications, R as useTheme };