@omicronenergy/oscd-shell 0.0.8 → 0.0.10

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 (60) hide show
  1. package/dist/colors.d.ts +1 -0
  2. package/dist/colors.js +60 -0
  3. package/dist/colors.js.map +1 -0
  4. package/dist/foundation/cyrb64.js +0 -3
  5. package/dist/foundation/cyrb64.js.map +1 -1
  6. package/dist/foundation/events.d.ts +17 -0
  7. package/dist/foundation/events.js +2 -0
  8. package/dist/foundation/events.js.map +1 -0
  9. package/dist/foundation.js.map +1 -1
  10. package/dist/landing-page/landing-page.d.ts +26 -0
  11. package/dist/landing-page/landing-page.js +163 -0
  12. package/dist/landing-page/landing-page.js.map +1 -0
  13. package/dist/landing-page/landing-page.spec.d.ts +1 -0
  14. package/dist/landing-page/landing-page.spec.js +87 -0
  15. package/dist/landing-page/landing-page.spec.js.map +1 -0
  16. package/dist/locales/de.d.ts +0 -5
  17. package/dist/locales/de.js +0 -5
  18. package/dist/locales/de.js.map +1 -1
  19. package/dist/locales.js.map +1 -1
  20. package/dist/localization.d.ts +15 -0
  21. package/dist/localization.js +22 -0
  22. package/dist/localization.js.map +1 -0
  23. package/dist/menus/files-menu.d.ts +27 -0
  24. package/dist/menus/files-menu.js +102 -0
  25. package/dist/menus/files-menu.js.map +1 -0
  26. package/dist/menus/files-menu.spec.d.ts +1 -0
  27. package/dist/menus/files-menu.spec.js +33 -0
  28. package/dist/menus/files-menu.spec.js.map +1 -0
  29. package/dist/menus/plugins-menu.d.ts +32 -0
  30. package/dist/menus/plugins-menu.js +128 -0
  31. package/dist/menus/plugins-menu.js.map +1 -0
  32. package/dist/menus/plugins-menu.spec.d.ts +1 -0
  33. package/dist/menus/plugins-menu.spec.js +65 -0
  34. package/dist/menus/plugins-menu.spec.js.map +1 -0
  35. package/dist/oscd-shell.d.ts +71 -85
  36. package/dist/oscd-shell.js +382 -552
  37. package/dist/oscd-shell.js.map +1 -1
  38. package/dist/side-panel/editor-plugins-panel.d.ts +29 -0
  39. package/dist/side-panel/editor-plugins-panel.js +151 -0
  40. package/dist/side-panel/editor-plugins-panel.js.map +1 -0
  41. package/dist/side-panel/editor-plugins-panel.spec.d.ts +1 -0
  42. package/dist/side-panel/editor-plugins-panel.spec.js +87 -0
  43. package/dist/side-panel/editor-plugins-panel.spec.js.map +1 -0
  44. package/dist/theming.d.ts +1 -0
  45. package/dist/theming.js +76 -0
  46. package/dist/theming.js.map +1 -0
  47. package/dist/utils/plugin-utils.d.ts +1 -1
  48. package/dist/utils/plugin-utils.js +8 -11
  49. package/dist/utils/plugin-utils.js.map +1 -1
  50. package/dist/utils/plugin-utils.spec.js.map +1 -1
  51. package/dist/utils/testing/plugin-helpers.d.ts +24 -0
  52. package/dist/utils/testing/plugin-helpers.js +74 -0
  53. package/dist/utils/testing/plugin-helpers.js.map +1 -0
  54. package/dist/utils/testing/test-doc-helpers.d.ts +7 -0
  55. package/dist/utils/testing/test-doc-helpers.js +28 -0
  56. package/dist/utils/testing/test-doc-helpers.js.map +1 -0
  57. package/dist/utils/testing/test-plugins.d.ts +44 -0
  58. package/dist/utils/testing/test-plugins.js +56 -0
  59. package/dist/utils/testing/test-plugins.js.map +1 -0
  60. package/package.json +62 -126
@@ -1,186 +1,87 @@
1
- var _OpenSCD_plugins, _OpenSCD_actions;
2
- import { __classPrivateFieldGet, __classPrivateFieldSet, __decorate } from "tslib";
3
- import '@webcomponents/scoped-custom-element-registry';
4
- import { configureLocalization, localized, msg } from '@lit/localize';
1
+ import { __decorate } from "tslib";
5
2
  import { css, html, LitElement, nothing } from 'lit';
6
- import { customElement, property, query, state } from 'lit/decorators.js';
3
+ import { customElement, property, query, queryAssignedNodes, state, } from 'lit/decorators.js';
4
+ import { ScopedElementsMixin } from '@open-wc/scoped-elements/lit-element.js';
5
+ import { localized, msg } from '@lit/localize';
7
6
  import { html as staticHtml, unsafeStatic } from 'lit/static-html.js';
8
- import '@omicronenergy/oscd-ui/app-bar/oscd-app-bar.js';
9
- import '@omicronenergy/oscd-ui/dialog/oscd-dialog.js';
10
- import '@omicronenergy/oscd-ui/divider/oscd-divider.js';
11
- import '@omicronenergy/oscd-ui/iconbutton/oscd-filled-icon-button.js';
12
- import '@omicronenergy/oscd-ui/select/oscd-filled-select.js';
13
- import '@omicronenergy/oscd-ui/textfield/oscd-filled-text-field.js';
14
- import '@omicronenergy/oscd-ui/icon/oscd-icon.js';
15
- import '@omicronenergy/oscd-ui/list/oscd-list.js';
16
- import '@omicronenergy/oscd-ui/list/oscd-list-item.js';
17
- import '@omicronenergy/oscd-ui/menu/oscd-menu.js';
18
- import '@omicronenergy/oscd-ui/menu/oscd-menu-item.js';
19
- import '@omicronenergy/oscd-ui/navigation-drawer/oscd-navigation-drawer.js';
20
- import '@omicronenergy/oscd-ui/navigation-drawer/oscd-navigation-drawer-header.js';
21
- import '@omicronenergy/oscd-ui/tabs/oscd-secondary-tab.js';
22
- import '@omicronenergy/oscd-ui/select/oscd-select-option.js';
23
- import '@omicronenergy/oscd-ui/tabs/oscd-tabs.js';
24
- import '@omicronenergy/oscd-ui/button/oscd-text-button.js';
7
+ import { OscdFilledIconButton } from '@omicronenergy/oscd-ui/iconbutton/OscdFilledIconButton.js';
25
8
  import { XMLEditor } from '@omicronenergy/oscd-editor';
26
- import { sourceLocale, targetLocales } from './locales.js';
27
9
  import { loadSourcedPlugins } from './utils/plugin-utils.js';
28
- const _customElementsDefine = window.customElements.define;
29
- window.customElements.define = (name, cl, conf) => {
30
- if (!customElements.get(name)) {
31
- _customElementsDefine.call(window.customElements, name, cl, conf);
32
- }
33
- };
34
- const { getLocale, setLocale } = configureLocalization({
35
- sourceLocale,
36
- targetLocales,
37
- loadLocale: locale => import(new URL(`./locales/${locale}.js`, import.meta.url).href),
38
- });
39
- function renderActionItem(control, slot = 'actionItems') {
40
- return html `<oscd-filled-icon-button
41
- slot="${slot}"
42
- aria-label="${control.getName()}"
43
- ?disabled=${control.isDisabled()}
44
- @click=${control.action}
45
- ><oscd-icon>${control.icon}</oscd-icon></oscd-filled-icon-button
46
- >`;
47
- }
48
- function renderMenuItem(control) {
49
- return html `
50
- <oscd-list-item
51
- type="button"
52
- .disabled=${control.isDisabled()}
53
- @click=${control.action}
54
- >
55
- <oscd-icon slot="start">${control.icon}</oscd-icon>
56
- <span>${control.getName()}</span>
57
- </oscd-list-item>
58
- `;
59
- }
60
- let OpenSCD = class OpenSCD extends LitElement {
61
- isEditable(docName) {
62
- return !!this.editable.find(ext => docName.toLowerCase().endsWith(`.${ext}`));
63
- }
64
- get editableDocs() {
65
- return Object.keys(this.docs).filter(name => this.isEditable(name));
66
- }
67
- /** The set of `XMLDocument`s currently loaded */
68
- get docs() {
69
- return this._docs;
70
- }
71
- set docs(newDocs) {
72
- this._docs = newDocs;
73
- this.onDocsChanged();
74
- }
75
- onDocsChanged() {
76
- this.stateVersion += 1;
77
- }
78
- get doc() {
79
- return this.docs[this.docName];
80
- }
81
- get last() {
82
- return this.xmlEditor.past.length - 1;
83
- }
84
- get canUndo() {
85
- return this.xmlEditor.past.length >= 0;
10
+ import { getLocale, setLocale, } from './localization.js';
11
+ import { theming } from './theming.js';
12
+ import { EditorPluginsPanel } from './side-panel/editor-plugins-panel.js';
13
+ import { PluginsMenu } from './menus/plugins-menu.js';
14
+ import { LandingPage } from './landing-page/landing-page.js';
15
+ import { FilesMenu } from './menus/files-menu.js';
16
+ import { OscdAppBar } from '@omicronenergy/oscd-ui/app-bar/OscdAppBar.js';
17
+ import { OscdIcon } from '@omicronenergy/oscd-ui/icon/OscdIcon.js';
18
+ let OscdShell = class OscdShell extends ScopedElementsMixin(LitElement) {
19
+ get locale() {
20
+ return getLocale();
86
21
  }
87
- get canRedo() {
88
- return this.xmlEditor.future.length >= 0;
22
+ set locale(tag) {
23
+ try {
24
+ if (tag) {
25
+ setLocale(tag);
26
+ }
27
+ }
28
+ catch {
29
+ // don't change locale if tag is invalid
30
+ }
89
31
  }
90
32
  get plugins() {
91
- return __classPrivateFieldGet(this, _OpenSCD_plugins, "f");
33
+ return this._plugins;
92
34
  }
93
35
  set plugins(plugins) {
94
- __classPrivateFieldSet(this, _OpenSCD_plugins, Object.entries(plugins).reduce((acc, [pluginType, kind]) => {
95
- const convertedPlugins = loadSourcedPlugins(kind);
36
+ this._plugins = Object.entries(plugins).reduce((acc, [pluginType, kind]) => {
37
+ const convertedPlugins = loadSourcedPlugins(kind, this.registry);
96
38
  acc[pluginType] = convertedPlugins;
97
39
  return acc;
98
- }, { menu: [], editor: [], background: [] }), "f");
40
+ }, { menu: [], editor: [], background: [] });
99
41
  }
100
- handleOpenDoc({ detail: { docName, doc } }) {
101
- this.docs = {
102
- ...this.docs,
103
- [docName]: doc,
104
- };
105
- if (this.isEditable(docName)) {
106
- this.docName = docName;
107
- }
108
- this.requestUpdate();
42
+ /*
43
+ * States
44
+ */
45
+ get canRedo() {
46
+ return this.xmlEditor.future.length >= 1;
109
47
  }
110
- /** Undo the last `n` [[Edit]]s committed */
111
- undo(n = 1) {
112
- if (!this.canUndo || n < 1) {
113
- return;
114
- }
115
- this.xmlEditor.undo();
116
- if (n > 1) {
117
- this.undo(n - 1);
118
- }
119
- this.requestUpdate();
48
+ get canUndo() {
49
+ return this.xmlEditor.past.length >= 1;
120
50
  }
121
- /** Redo the last `n` [[Edit]]s that have been undone */
122
- redo(n = 1) {
123
- if (!this.canRedo || n < 1) {
124
- return;
125
- }
126
- this.xmlEditor.redo();
127
- if (n > 1) {
128
- this.redo(n - 1);
129
- }
130
- this.requestUpdate();
51
+ get editor() {
52
+ return this.plugins.editor[this.editorIndex]?.tagName ?? '';
131
53
  }
132
- get locale() {
133
- return getLocale();
54
+ get doc() {
55
+ return this.docs[this.docName];
134
56
  }
135
- set locale(tag) {
136
- try {
137
- setLocale(tag);
138
- }
139
- catch {
140
- // don't change locale if tag is invalid
141
- }
57
+ get docs() {
58
+ return this._docs;
142
59
  }
143
- get editor() {
144
- return this.editors[this.editorIndex]?.tagName ?? '';
145
- }
146
- get menu() {
147
- return (this.plugins.menu
148
- ?.map(({ name, tagName, requireDoc, icon, translations }) => ({
149
- icon,
150
- getName: () => translations?.[this.locale] ||
151
- name,
152
- isDisabled: () => (requireDoc && !this.docName) ?? false,
153
- tagName,
154
- action: () => {
155
- if (tagName) {
156
- this.shadowRoot.querySelector(tagName).run?.();
157
- this.menuUI.opened = false;
158
- }
159
- },
160
- }))
161
- .filter(p => p !== undefined)).concat(__classPrivateFieldGet(this, _OpenSCD_actions, "f"));
162
- }
163
- get editors() {
164
- return this.plugins.editor?.map(({ name, tagName, requireDoc, icon, translations, }) => ({
165
- icon,
166
- getName: () => translations?.[this.locale] ||
167
- name,
168
- isDisabled: () => (requireDoc && !this.docName) ?? false,
169
- tagName,
170
- }));
171
- }
172
- handleKeyPress(e) {
173
- if (!e.ctrlKey) {
174
- return;
175
- }
176
- if (!Object.prototype.hasOwnProperty.call(this.hotkeys, e.key)) {
177
- return;
178
- }
179
- this.hotkeys[e.key]();
180
- e.preventDefault();
60
+ set docs(newDocs) {
61
+ this._docs = newDocs;
62
+ this.onDocsChanged();
63
+ }
64
+ get editableDocs() {
65
+ return Object.keys(this.docs).filter(name => this.isEditable(name));
181
66
  }
67
+ get last() {
68
+ return this.xmlEditor.past.length - 1;
69
+ }
70
+ /*
71
+ * Constructor & life cycle methods
72
+ */
182
73
  constructor() {
183
74
  super();
75
+ /*
76
+ * Properties
77
+ */
78
+ /**
79
+ * Url to the app icon displayed in the app bar
80
+ */
81
+ this.appIcon = '';
82
+ this.appTitle = 'OpenSCD';
83
+ this.landingPageHeading = 'Welcome to OpenSCD';
84
+ this.landingPageSubHeading = 'Open Source IEC-61850-6 SCL Editing Platform';
184
85
  /** The file endings of editable files */
185
86
  this.editable = [
186
87
  'cid',
@@ -190,71 +91,129 @@ let OpenSCD = class OpenSCD extends LitElement {
190
91
  'sed',
191
92
  'ssd',
192
93
  ];
193
- this._docs = {};
94
+ this._plugins = { menu: [], editor: [], background: [] };
95
+ this.editorIndex = 0;
194
96
  /** The name of the [[`doc`]] currently being edited */
195
97
  this.docName = '';
98
+ /** The set of `XMLDocument`s currently loaded */
99
+ this._docs = {};
100
+ this.docVersion = -1;
196
101
  this.xmlEditor = new XMLEditor();
197
- this.stateVersion = -1;
198
- _OpenSCD_plugins.set(this, { menu: [], editor: [], background: [] });
199
- this.editorIndex = 0;
200
- this.controls = {
201
- undo: {
202
- icon: 'undo',
203
- getName: () => msg('Undo'),
204
- action: () => {
205
- this.undo();
206
- this.menuUI.opened = false;
207
- },
208
- isDisabled: () => !this.canUndo,
209
- },
210
- redo: {
211
- icon: 'redo',
212
- getName: () => msg('Redo'),
213
- action: () => {
214
- this.redo();
215
- this.menuUI.opened = false;
216
- },
217
- isDisabled: () => !this.canRedo,
218
- },
219
- menu: {
220
- icon: 'menu',
221
- getName: () => msg('Menu'),
222
- action: async () => {
223
- this.menuUI.opened = !this.menuUI.opened;
224
- await this.menuUI.updateComplete;
225
- if (this.menuUI.opened) {
226
- this.menuUI.querySelector('oscd-list').focus();
227
- }
228
- },
229
- isDisabled: () => false,
230
- },
102
+ /*
103
+ * Event Handlers
104
+ */
105
+ this.handleOpenDoc = ({ detail: { docName, doc } }) => {
106
+ this.docs = {
107
+ ...this.docs,
108
+ [docName]: doc,
109
+ };
110
+ if (this.isEditable(docName)) {
111
+ this.docName = docName;
112
+ }
113
+ this.requestUpdate();
114
+ };
115
+ this.handleRenameDoc = (customEvent) => {
116
+ const { oldName, newName } = customEvent.detail;
117
+ if (!this.docs[oldName] || newName === oldName || this.docs[newName]) {
118
+ return;
119
+ }
120
+ const doc = this.docs[oldName];
121
+ delete this.docs[oldName];
122
+ this.docs = {
123
+ ...this.docs,
124
+ [newName]: doc,
125
+ };
126
+ this.docName = newName;
127
+ };
128
+ this.handleEditV2 = (event) => {
129
+ const { edit, title, squash } = event.detail;
130
+ this.xmlEditor.commit(edit, { title, squash });
131
+ };
132
+ this.handleCloseDoc = (event) => {
133
+ const docName = event.detail.docName;
134
+ delete this.docs[docName];
135
+ if (this.docName === docName) {
136
+ this.docName = this.editableDocs[0] || '';
137
+ }
138
+ };
139
+ this.handleUndo = () => {
140
+ this.undo();
141
+ };
142
+ this.handleRedo = () => {
143
+ this.redo();
144
+ };
145
+ this.handleKeyPress = (e) => {
146
+ if (!e.ctrlKey) {
147
+ return;
148
+ }
149
+ if (!Object.prototype.hasOwnProperty.call(this.hotkeys, e.key)) {
150
+ return;
151
+ }
152
+ this.hotkeys[e.key].call(this);
153
+ e.preventDefault();
154
+ };
155
+ this.handleOpenPluginMenu = () => {
156
+ this.pluginsMenu.open();
157
+ };
158
+ /** Undo the last `n` [[Edit]]s committed */
159
+ this.undo = (n = 1) => {
160
+ if (!this.canUndo || n < 1) {
161
+ return;
162
+ }
163
+ this.xmlEditor.undo();
164
+ if (n > 1) {
165
+ this.undo(n - 1);
166
+ }
167
+ this.requestUpdate();
168
+ };
169
+ /** Redo the last `n` [[Edit]]s that have been undone */
170
+ this.redo = (n = 1) => {
171
+ if (!this.canRedo || n < 1) {
172
+ return;
173
+ }
174
+ this.xmlEditor.redo();
175
+ if (n > 1) {
176
+ this.redo(n - 1);
177
+ }
178
+ this.requestUpdate();
231
179
  };
232
- _OpenSCD_actions.set(this, [this.controls.undo, this.controls.redo]);
233
180
  this.hotkeys = {
234
- m: this.controls.menu.action,
235
- z: this.controls.undo.action,
236
- y: this.controls.redo.action,
237
- Z: this.controls.redo.action,
181
+ m: this.handleOpenPluginMenu,
182
+ z: this.undo,
183
+ y: this.redo,
184
+ Z: this.redo,
238
185
  };
239
- document.addEventListener('keydown', event => this.handleKeyPress(event));
240
- this.addEventListener('oscd-open', event => this.handleOpenDoc(event));
241
- this.addEventListener('oscd-edit-v2', (event) => {
242
- this.xmlEditor.commit(event.detail.edit);
243
- });
244
186
  // Catch all edits (from commits AND events) and trigger an update
245
187
  this.xmlEditor.subscribe(() => {
246
- this.stateVersion += 1;
188
+ this.docVersion += 1;
247
189
  });
248
190
  }
249
- updated(changedProps) {
250
- super.updated(changedProps);
251
- this.updateComplete.then(() => {
252
- // Ensure the active tab is set after tabs are rendered
253
- const oscdTabs = this.shadowRoot.querySelector('oscd-tabs');
254
- if (oscdTabs && oscdTabs.activeTabIndex !== this.editorIndex) {
255
- oscdTabs.activeTabIndex = this.editorIndex;
256
- }
257
- });
191
+ connectedCallback() {
192
+ super.connectedCallback();
193
+ document.addEventListener('keydown', this.handleKeyPress);
194
+ this.addEventListener('oscd-open', this.handleOpenDoc);
195
+ this.addEventListener('oscd-rename', this.handleRenameDoc);
196
+ this.addEventListener('oscd-close', this.handleCloseDoc);
197
+ this.addEventListener('oscd-edit-v2', this.handleEditV2);
198
+ this.addEventListener('oscd-undo', this.handleUndo);
199
+ this.addEventListener('oscd-redo', this.handleRedo);
200
+ }
201
+ disconnectedCallback() {
202
+ super.disconnectedCallback();
203
+ // Remove event listeners
204
+ document.removeEventListener('keydown', this.handleKeyPress);
205
+ this.removeEventListener('oscd-open', this.handleOpenDoc);
206
+ this.removeEventListener('oscd-rename', this.handleRenameDoc);
207
+ this.removeEventListener('oscd-edit-v2', this.handleEditV2);
208
+ this.removeEventListener('oscd-undo', this.handleUndo);
209
+ this.removeEventListener('oscd-redo', this.handleRedo);
210
+ this.removeEventListener('oscd-close', this.handleCloseDoc);
211
+ }
212
+ isEditable(docName) {
213
+ return !!this.editable.find(ext => docName.toLowerCase().endsWith(`.${ext}`));
214
+ }
215
+ onDocsChanged() {
216
+ this.docVersion += 1;
258
217
  }
259
218
  renderPlugin(tagName) {
260
219
  const tag = unsafeStatic(tagName);
@@ -263,315 +222,204 @@ let OpenSCD = class OpenSCD extends LitElement {
263
222
  .docName="${this.docName}"
264
223
  .doc=${this.doc}
265
224
  .docs=${this.docs}
266
- .editCount=${this.stateVersion}
267
- .stateVersion=${this.stateVersion}
225
+ .editCount=${this.docVersion}
226
+ .docVersion=${this.docVersion}
268
227
  .editor=${this.xmlEditor}>
269
228
  </${tag}>`;
270
229
  }
271
- render() {
272
- return html `<oscd-app-bar slot="appContent">
273
- ${renderActionItem(this.controls.menu, 'actionStart')}
274
- <div slot="title" id="title">
275
- ${this.editableDocs.length > 1
276
- ? html `<oscd-filled-icon-button
277
- id="fileMenuButton"
278
- @click=${() => this.fileMenuUI.show()}
279
- ><oscd-icon>arrow_drop_down</oscd-icon></oscd-filled-icon-button
280
- >`
281
- : nothing}
282
- ${this.docName}
283
- ${this.docName
284
- ? html `<oscd-filled-icon-button
285
- @click=${() => this.editFileUI.show()}
286
- ><oscd-icon>edit</oscd-icon></oscd-filled-icon-button
287
- >`
288
- : nothing}
289
- <oscd-menu
290
- fixed
291
- id="fileMenu"
292
- anchor="fileMenuButton"
293
- corner="BOTTOM_END"
294
- >
295
- ${this.editableDocs.map((name, index) => html `<oscd-menu-item
296
- @click=${() => {
297
- this.docName = name;
298
- }}
299
- ?disabled=${!this.isEditable(name)}
300
- ?selected=${this.docName === name}
301
- id=${index}
302
- >${name}</oscd-menu-item
303
- >`)}
304
- </oscd-menu>
230
+ onMenuPluginSelect(customEvent) {
231
+ const plugin = customEvent.detail.plugin;
232
+ if (plugin.tagName) {
233
+ this.shadowRoot.querySelector(plugin.tagName).run?.();
234
+ }
235
+ }
236
+ renderOffScreenPlugins() {
237
+ return html `
238
+ <section class="off-screen-plugin-container" aria-hidden="true">
239
+ <div class="menu-plugins">
240
+ ${this.plugins.menu
241
+ .filter(plugin => !plugin.requireDoc || !!this.docName)
242
+ .map(plugin => this.renderPlugin(plugin.tagName))}
305
243
  </div>
306
-
307
- <div slot="actionEnd">
308
- ${__classPrivateFieldGet(this, _OpenSCD_actions, "f").map(op => renderActionItem(op))}
244
+ <div class="background-plugins">
245
+ ${this.plugins.background
246
+ .filter(plugin => !plugin.requireDoc || !!this.docName)
247
+ .map(plugin => this.renderPlugin(plugin.tagName))}
309
248
  </div>
310
-
311
- <oscd-tabs
312
- .activeTabIndex=${this.editorIndex}
249
+ </section>
250
+ `;
251
+ }
252
+ renderDefaultLandingPage() {
253
+ return html `
254
+ <landing-page
255
+ heading=${this.landingPageHeading}
256
+ subHeading=${this.landingPageSubHeading}
257
+ .menuPlugins=${this.plugins.menu.filter(plugin => !plugin.requireDoc || !!this.docName)}
258
+ .locale=${this.locale}
259
+ @menu-plugin-select=${(event) => this.onMenuPluginSelect(event)}
260
+ >
261
+ </landing-page>
262
+ `;
263
+ }
264
+ render() {
265
+ const hasCustomLandingPage = !!this._landingPageNodes?.length;
266
+ if (this.editableDocs.length === 0) {
267
+ return html ` <slot
268
+ name="landing-page"
269
+ @slotchange=${() => this.requestUpdate()}
270
+ ></slot>
271
+ ${!hasCustomLandingPage ? this.renderDefaultLandingPage() : nothing}
272
+ ${this.renderOffScreenPlugins()}`;
273
+ }
274
+ return html ` <oscd-app-bar>
275
+ <plugins-menu
276
+ slot="alignStart"
277
+ appTitle=${this.appTitle}
278
+ appIcon=${this.appIcon}
279
+ .editableDocs=${this.editableDocs}
280
+ .menuPlugins=${this.plugins.menu}
281
+ .locale=${this.locale}
282
+ @menu-plugin-select=${(event) => this.onMenuPluginSelect(event)}
283
+ ></plugins-menu>
284
+
285
+ <files-menu
286
+ slot="alignMiddle"
287
+ .selectedDocName=${this.docName}
288
+ .editableDocs=${this.editableDocs}
289
+ .locale=${this.locale}
313
290
  @change=${(event) => {
314
- const tabs = event.currentTarget;
315
- this.editorIndex = tabs.activeTabIndex;
316
- }}
317
- >
318
- ${this.editors.map(editor => editor.isDisabled()
319
- ? nothing
320
- : html `<oscd-secondary-tab>
321
- <oscd-icon slot="icon">${editor.icon}</oscd-icon>
322
- ${editor.getName()}
323
- </oscd-secondary-tab>`)}
324
- </oscd-tabs>
325
- </oscd-app-bar>
326
-
327
- <oscd-navigation-drawer hasheader type="modal" id="menu">
328
- <oscd-navigation-drawer-header>
329
- <span slot="headline">${msg('Menu')}</span>
330
- ${this.docName
331
- ? html `<span slot="supporting-text">${this.docName}</span>`
332
- : ''}
333
- </oscd-navigation-drawer-header>
334
- <oscd-list>
335
- <oscd-divider></oscd-divider>
336
- ${this.menu.map(renderMenuItem)}
337
- </oscd-list>
338
- </oscd-navigation-drawer>
339
-
340
- ${this.editor ? this.renderPlugin(this.editor) : nothing}
341
-
342
- <oscd-dialog
343
- id="editFile"
344
- @closed=${(event) => {
345
- const dialog = event.target;
346
- if (dialog.returnValue === 'remove') {
347
- delete this.docs[this.docName];
348
- this.docName = this.editableDocs[0] || '';
349
- }
291
+ const name = event.detail.name;
292
+ this.docName = name;
350
293
  }}
351
- >
352
- <div slot="headline">
353
- <oscd-icon>description</oscd-icon>${this.docName}
354
- </div>
355
- <form slot="content" id="edit-file-form" method="dialog">
356
- <oscd-filled-text-field
357
- id="fileName"
358
- label="${msg('Filename')}"
359
- value="${this.docName.replace(/\.[^.]+$/, '')}"
360
- @input=${(event) => {
361
- const input = event.target;
362
- const { value } = input;
363
- const name = `${value}.${this.fileExtensionUI.value}`;
364
- if (name in this.docs && name !== this.docName) {
365
- input.setCustomValidity('File already exists!');
366
- }
367
- else {
368
- input.setCustomValidity('');
369
- }
370
- input.reportValidity();
294
+ ></files-menu>
295
+
296
+ <div slot="alignEnd">
297
+ <oscd-filled-icon-button
298
+ aria-label="${msg('Undo')}"
299
+ ?disabled=${!this.canUndo}
300
+ @click=${async () => {
301
+ this.dispatchEvent(new CustomEvent('oscd-undo', {
302
+ bubbles: true,
303
+ composed: true,
304
+ }));
371
305
  }}
372
- ></oscd-filled-text-field>
373
- <oscd-filled-select
374
- label="${msg('Extension')}"
375
- fixedMenuPosition
376
- id="fileExtension"
377
- @selected=${() => this.fileNameUI.reportValidity()}
378
- >
379
- ${this.editable.map(ext => html `<oscd-select-option
380
- ?selected=${this.docName.endsWith(`.${ext}`)}
381
- value="${ext}"
382
- >${ext}</oscd-select-option
383
- >`)}
384
- </oscd-filled-select>
385
- </form>
386
- <div slot="actions">
387
- <oscd-text-button
388
- form="edit-file-form"
389
- class="edit-dialog-remove-button"
390
- value="remove"
306
+ ><oscd-icon>undo</oscd-icon></oscd-filled-icon-button
391
307
  >
392
- <oscd-icon slot="icon">delete</oscd-icon>
393
- ${msg('Close file')}
394
- </oscd-text-button>
395
- <oscd-text-button form="edit-file-form" value="close">
396
- ${msg('Cancel')}
397
- </oscd-text-button>
398
- <oscd-text-button
399
- @click=${() => {
400
- const valid = this.fileNameUI.checkValidity();
401
- if (!valid) {
402
- this.fileNameUI.reportValidity();
403
- return;
404
- }
405
- const newDocName = `${this.fileNameUI.value}.${this.fileExtensionUI.value}`;
406
- const doc = this.docs[this.docName];
407
- delete this.docs[this.docName];
408
- this.docs = {
409
- ...this.docs,
410
- [newDocName]: doc,
411
- };
412
- this.docName = newDocName;
413
- this.editFileUI.close();
308
+ <oscd-filled-icon-button
309
+ aria-label="${msg('Redo')}"
310
+ ?disabled=${!this.canRedo}
311
+ @click=${async () => {
312
+ this.dispatchEvent(new CustomEvent('oscd-redo', {
313
+ bubbles: true,
314
+ composed: true,
315
+ }));
414
316
  }}
415
- trailing-icon
317
+ ><oscd-icon>redo</oscd-icon></oscd-filled-icon-button
416
318
  >
417
- <oscd-icon slot="icon">edit</oscd-icon>
418
- ${msg('Rename')}
419
- </oscd-text-button>
420
319
  </div>
421
- </oscd-dialog>
320
+ </oscd-app-bar>
422
321
 
423
- <aside>
424
- <div class="menu-plugins">
425
- ${this.plugins.menu.map(plugin => this.renderPlugin(plugin.tagName))}
426
- </div>
427
- <div class="background-plugins">
428
- ${this.plugins.background
429
- .filter(plugin => !plugin.requireDoc || !!this.docName)
430
- .map(plugin => this.renderPlugin(plugin.tagName))}
431
- </div>
432
- </aside> `;
433
- }
434
- firstUpdated() {
435
- const background = getComputedStyle(this.menuUI).getPropertyValue('--oscd-base2');
436
- document.body.style.background = background;
322
+ <main>
323
+ <section class="editors-side-panel-section">
324
+ <editor-plugins-panel
325
+ .editors=${this.plugins.editor}
326
+ .editorIndex=${this.editorIndex}
327
+ .locale=${this.locale}
328
+ @editor-select=${(e) => {
329
+ this.editorIndex = e.detail.index;
330
+ }}
331
+ ></editor-plugins-panel>
332
+ </section>
333
+
334
+ <section class="editor-container">
335
+ ${this.editor ? this.renderPlugin(this.editor) : nothing}
336
+ </section>
337
+
338
+ ${this.renderOffScreenPlugins()}
339
+ </main>`;
437
340
  }
438
341
  };
439
- _OpenSCD_plugins = new WeakMap();
440
- _OpenSCD_actions = new WeakMap();
441
- OpenSCD.styles = css `
442
- .fileext {
443
- opacity: 0.81;
342
+ OscdShell.scopedElements = {
343
+ 'oscd-app-bar': OscdAppBar,
344
+ 'oscd-filled-icon-button': OscdFilledIconButton,
345
+ 'oscd-icon': OscdIcon,
346
+ 'files-menu': FilesMenu,
347
+ 'plugins-menu': PluginsMenu,
348
+ 'editor-plugins-panel': EditorPluginsPanel,
349
+ 'landing-page': LandingPage,
350
+ };
351
+ OscdShell.styles = css `
352
+ ${theming}
353
+
354
+ * {
355
+ --app-bar-height: 54px;
356
+ --side-panel-width: 280px;
444
357
  }
445
358
 
446
- .filename {
447
- caret-color: var(--oscd-secondary);
359
+ :host {
360
+ height: 100%;
361
+ display: grid;
362
+ grid-template-rows: min-content 1fr;
363
+ grid-template-columns: 1fr;
364
+ grid-template-areas:
365
+ 'header'
366
+ 'main';
448
367
  }
449
368
 
450
- .filename:focus {
451
- outline: none;
369
+ oscd-app-bar {
370
+ grid-area: header;
371
+ box-shadow: var(--md-sys-elevation-level-2);
372
+ z-index: 10;
452
373
  }
453
374
 
454
- aside {
455
- position: absolute;
456
- top: 0;
457
- left: 0;
458
- width: 0;
459
- height: 0;
375
+ main {
376
+ grid-area: main;
377
+ display: grid;
378
+ grid-template-columns: var(--side-panel-width) 1fr;
379
+ grid-template-areas: 'sidebar editor';
460
380
  overflow: hidden;
461
- margin: 0;
462
- padding: 0;
463
381
  }
464
382
 
465
- abbr {
466
- text-decoration: none;
383
+ /* Side panel collapsed state */
384
+ main.sidebar-collapsed {
385
+ grid-template-columns: 0 1fr;
467
386
  }
468
387
 
469
- @media (prefers-color-scheme: light) {
470
- * {
471
- --oscd-primary: var(--oscd-theme-primary, #2aa198);
472
- --oscd-secondary: var(--oscd-theme-secondary, #6c71c4);
473
- --oscd-base03: var(--oscd-theme-base03, #002b36);
474
- --oscd-base02: var(--oscd-theme-base02, #073642);
475
- --oscd-base01: var(--oscd-theme-base01, #586e75);
476
- --oscd-base00: var(--oscd-theme-base00, #657b83);
477
- --oscd-base0: var(--oscd-theme-base0, #839496);
478
- --oscd-base1: var(--oscd-theme-base1, #93a1a1);
479
- --oscd-base2: var(--oscd-theme-base2, #eee8d5);
480
- --oscd-base3: var(--oscd-theme-base3, #fdf6e3);
481
-
482
- --mdc-theme-text-disabled-on-light: rgba(255, 255, 255, 0.38);
483
- }
388
+ section.editors-side-panel-section {
389
+ grid-area: sidebar;
390
+ overflow-y: auto;
391
+ overflow-x: hidden;
392
+ transition: transform 0.3s ease-in-out;
484
393
  }
485
394
 
486
- @media (prefers-color-scheme: dark) {
487
- * {
488
- --oscd-primary: var(--oscd-theme-secondary, #6c71c4);
489
- --oscd-secondary: var(--oscd-theme-primary, #2aa198);
490
- --oscd-base03: var(--oscd-theme-base3, #fdf6e3);
491
- --oscd-base02: var(--oscd-theme-base2, #eee8d5);
492
- --oscd-base01: var(--oscd-theme-base1, #93a1a1);
493
- --oscd-base00: var(--oscd-theme-base0, #839496);
494
- --oscd-base0: var(--oscd-theme-base00, #657b83);
495
- --oscd-base1: var(--oscd-theme-base01, #586e75);
496
- --oscd-base2: var(--oscd-theme-base02, #073642);
497
- --oscd-base3: var(--oscd-theme-base03, #002b36);
498
- }
395
+ /* Hide side panel when collapsed */
396
+ main.sidebar-collapsed section.editors-side-panel-section {
397
+ transform: translateX(-100%);
499
398
  }
500
399
 
501
- * {
502
- --oscd-error: var(--oscd-theme-error, #dc322f);
503
-
504
- --oscd-text-font: var(--oscd-theme-text-font, 'Roboto');
505
- --oscd-icon-font: var(--oscd-theme-icon-font, 'Material Icons');
506
- --oscd-text-font-mono: var(--oscd-theme-text-font-mono, 'Roboto Mono');
507
-
508
- --oscd-warning: var(--oscd-theme-warning, #b58900);
509
- --md-sys-color-primary: var(--oscd-primary);
510
- --md-sys-color-on-primary: var(--oscd-base3);
511
-
512
- --md-sys-color-secondary: var(--oscd-secondary);
513
- --md-sys-color-on-secondary: var(--oscd-base3);
514
- --md-sys-color-secondary-container: var(--oscd-base2);
515
-
516
- --md-sys-color-surface: var(--oscd-base3);
517
- --md-sys-color-on-surface: var(--oscd-base00);
518
- --md-sys-color-surface-variant: var(--oscd-base3);
519
- --md-sys-color-on-surface-variant: var(--oscd-base00);
520
- --md-sys-color-surface-bright: var(--oscd-base2);
521
- --md-sys-color-surface-container: var(--oscd-base3);
522
- --md-sys-color-surface-container-high: var(--oscd-base3);
523
- --md-sys-color-surface-container-highest: var(--oscd-base3);
524
-
525
- --md-sys-color-outline-variant: var(--oscd-primary);
526
- --md-sys-color-scrim: #000000;
527
- --md-sys-color-error: var(--oscd-error);
528
- --md-sys-color-on-error: var(--oscd-base3);
529
-
530
- /* --md-menu-item-selected-label-text-color: var(--oscd-base01); */
531
- --md-icon-button-disabled-icon-color: var(--oscd-base3);
532
-
533
- /* MDC Theme Colors
534
- * Needed for supporting any pluggins still using the depricated MWC Components
535
- */
536
- --mdc-theme-primary: var(--oscd-primary);
537
- --mdc-theme-secondary: var(--oscd-secondary);
538
- --mdc-theme-background: var(--oscd-base3);
539
- --mdc-theme-surface: var(--oscd-base3);
540
- --mdc-theme-on-primary: var(--oscd-base2);
541
- --mdc-theme-on-secondary: var(--oscd-base02);
542
- --mdc-theme-on-background: var(--oscd-base00);
543
- --mdc-theme-on-surface: var(--oscd-base00);
544
- --mdc-theme-text-primary-on-background: var(--oscd-base01);
545
- --mdc-theme-text-secondary-on-background: var(--oscd-base00);
546
- --mdc-theme-text-icon-on-background: var(--oscd-base00);
547
- --mdc-theme-error: var(--oscd-error);
548
-
549
- --mdc-button-disabled-ink-color: var(--oscd-base1);
550
-
551
- --mdc-drawer-heading-ink-color: var(--oscd-base00);
552
-
553
- --mdc-dialog-heading-ink-color: var(--oscd-base00);
554
-
555
- --mdc-text-field-fill-color: var(--oscd-base2);
556
- --mdc-text-field-ink-color: var(--oscd-base02);
557
- --mdc-text-field-label-ink-color: var(--oscd-base01);
558
- --mdc-text-field-idle-line-color: var(--oscd-base00);
559
- --mdc-text-field-hover-line-color: var(--oscd-base02);
560
-
561
- --mdc-select-fill-color: var(--oscd-base2);
562
- --mdc-select-ink-color: var(--oscd-base02);
563
- --mdc-select-label-ink-color: var(--oscd-base01);
564
- --mdc-select-idle-line-color: var(--oscd-base00);
565
- --mdc-select-hover-line-color: var(--oscd-base02);
566
- --mdc-select-dropdown-icon-color: var(--oscd-base01);
400
+ section.editor-container {
401
+ grid-area: editor;
402
+ background-color: var(--slate-100);
403
+ padding: 8px;
404
+ overflow: auto;
405
+ position: relative;
406
+ }
567
407
 
568
- --mdc-typography-font-family: var(--oscd-text-font);
569
- --mdc-icon-font: var(--oscd-icon-font);
408
+ .off-screen-plugin-container {
409
+ position: absolute;
410
+ top: 0;
411
+ left: 0;
412
+ width: 0;
413
+ height: 0;
414
+ overflow: hidden;
415
+ margin: 0;
416
+ padding: 0;
570
417
  }
571
418
 
572
419
  oscd-navigation-drawer-header {
573
420
  --md-list-item-supporting-text-color: var(--md-sys-color-on-surface);
574
421
  }
422
+
575
423
  oscd-app-bar * {
576
424
  --md-filled-icon-button-disabled-container-opacity: 0;
577
425
  --md-filled-icon-button-disabled-icon-color: var(
@@ -579,107 +427,89 @@ OpenSCD.styles = css `
579
427
  );
580
428
  }
581
429
 
582
- oscd-tabs {
583
- display: flex;
584
- flex-grow: 1;
585
- --md-secondary-tab-container-color: var(--oscd-primary);
586
- }
587
- oscd-secondary-tab {
588
- --md-sys-color-on-surface: var(--md-sys-color-on-primary);
589
- --md-sys-color-on-surface-variant: var(--md-sys-color-on-primary);
590
- --md-secondary-tab-active-indicator-color: var(--oscd-base2);
591
- }
592
-
593
430
  .edit-dialog-remove-button {
594
431
  --md-text-button-icon-color: var(--oscd-error);
595
432
  --md-text-button-label-text-color: var(--oscd-error);
596
-
597
433
  --md-text-button-focus-label-text-color: var(--oscd-error);
598
434
  --md-text-button-focus-icon-color: var(--oscd-error);
599
-
600
435
  --md-text-button-hover-label-text-color: var(--oscd-error);
601
436
  --md-text-button-hover-state-layer-color: var(--oscd-error);
602
437
  --md-text-button-hover-icon-color: var(--oscd-error);
603
-
604
438
  --md-text-button-pressed-label-text-color: var(--oscd-error);
605
439
  --md-text-button-pressed-state-layer-color: var(--oscd-error);
606
440
  --md-text-button-pressed-icon-color: var(--oscd-error);
607
441
  }
608
-
609
442
  #title {
610
443
  position: relative;
611
444
  }
612
445
  `;
613
446
  __decorate([
614
- property({ type: Array, reflect: true })
615
- ], OpenSCD.prototype, "editable", void 0);
447
+ property({ type: String })
448
+ ], OscdShell.prototype, "appIcon", void 0);
616
449
  __decorate([
617
- state()
618
- ], OpenSCD.prototype, "editableDocs", null);
450
+ property({ type: String })
451
+ ], OscdShell.prototype, "appTitle", void 0);
619
452
  __decorate([
620
- state()
621
- ], OpenSCD.prototype, "docs", null);
453
+ property({ type: String })
454
+ ], OscdShell.prototype, "landingPageHeading", void 0);
455
+ __decorate([
456
+ property({ type: String })
457
+ ], OscdShell.prototype, "landingPageSubHeading", void 0);
458
+ __decorate([
459
+ property({ type: Array, reflect: true })
460
+ ], OscdShell.prototype, "editable", void 0);
622
461
  __decorate([
623
462
  property({ type: String, reflect: true })
624
- ], OpenSCD.prototype, "docName", void 0);
463
+ ], OscdShell.prototype, "locale", null);
625
464
  __decorate([
626
- state()
627
- /** The `XMLDocument` currently being edited */
628
- ], OpenSCD.prototype, "doc", null);
465
+ property({ type: Object })
466
+ ], OscdShell.prototype, "plugins", null);
629
467
  __decorate([
630
468
  state()
631
- ], OpenSCD.prototype, "xmlEditor", void 0);
469
+ ], OscdShell.prototype, "canRedo", null);
632
470
  __decorate([
633
471
  state()
634
- ], OpenSCD.prototype, "stateVersion", void 0);
472
+ ], OscdShell.prototype, "canUndo", null);
635
473
  __decorate([
636
474
  state()
637
- ], OpenSCD.prototype, "last", null);
475
+ ], OscdShell.prototype, "editor", null);
638
476
  __decorate([
639
477
  state()
640
- ], OpenSCD.prototype, "canUndo", null);
478
+ ], OscdShell.prototype, "editorIndex", void 0);
641
479
  __decorate([
642
480
  state()
643
- ], OpenSCD.prototype, "canRedo", null);
644
- __decorate([
645
- property({ type: Object })
646
- ], OpenSCD.prototype, "plugins", null);
647
- __decorate([
648
- query('#editFile')
649
- ], OpenSCD.prototype, "editFileUI", void 0);
650
- __decorate([
651
- query('#menu')
652
- ], OpenSCD.prototype, "menuUI", void 0);
653
- __decorate([
654
- query('#fileName')
655
- ], OpenSCD.prototype, "fileNameUI", void 0);
656
- __decorate([
657
- query('#fileExtension')
658
- ], OpenSCD.prototype, "fileExtensionUI", void 0);
659
- __decorate([
660
- query('#fileMenu')
661
- ], OpenSCD.prototype, "fileMenuUI", void 0);
662
- __decorate([
663
- query('#fileMenuButton')
664
- ], OpenSCD.prototype, "fileMenuButtonUI", void 0);
481
+ /** The `XMLDocument` currently being edited */
482
+ ], OscdShell.prototype, "doc", null);
665
483
  __decorate([
666
484
  property({ type: String, reflect: true })
667
- ], OpenSCD.prototype, "locale", null);
485
+ ], OscdShell.prototype, "docName", void 0);
486
+ __decorate([
487
+ state()
488
+ ], OscdShell.prototype, "docs", null);
668
489
  __decorate([
669
490
  state()
670
- ], OpenSCD.prototype, "editorIndex", void 0);
491
+ ], OscdShell.prototype, "docVersion", void 0);
671
492
  __decorate([
672
493
  state()
673
- ], OpenSCD.prototype, "editor", null);
494
+ ], OscdShell.prototype, "editableDocs", null);
674
495
  __decorate([
675
496
  state()
676
- ], OpenSCD.prototype, "menu", null);
497
+ ], OscdShell.prototype, "last", null);
677
498
  __decorate([
678
499
  state()
679
- ], OpenSCD.prototype, "editors", null);
680
- OpenSCD = __decorate([
681
- customElement('oscd-shell'),
682
- localized()
683
- ], OpenSCD);
684
- export { OpenSCD };
500
+ ], OscdShell.prototype, "xmlEditor", void 0);
501
+ __decorate([
502
+ query('plugins-menu')
503
+ ], OscdShell.prototype, "pluginsMenu", void 0);
504
+ __decorate([
505
+ query('editor-plugins-panel')
506
+ ], OscdShell.prototype, "editorPluginsPanel", void 0);
507
+ __decorate([
508
+ queryAssignedNodes({ slot: 'landing-page' })
509
+ ], OscdShell.prototype, "_landingPageNodes", void 0);
510
+ OscdShell = __decorate([
511
+ localized(),
512
+ customElement('oscd-shell')
513
+ ], OscdShell);
514
+ export { OscdShell };
685
515
  //# sourceMappingURL=oscd-shell.js.map