@theia/preferences 1.59.0 → 1.60.0-next.43

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 (50) hide show
  1. package/lib/browser/util/preference-layout.d.ts.map +1 -1
  2. package/lib/browser/util/preference-layout.js +73 -1
  3. package/lib/browser/util/preference-layout.js.map +1 -1
  4. package/lib/browser/util/preference-tree-generator.d.ts +6 -0
  5. package/lib/browser/util/preference-tree-generator.d.ts.map +1 -1
  6. package/lib/browser/util/preference-tree-generator.js +37 -23
  7. package/lib/browser/util/preference-tree-generator.js.map +1 -1
  8. package/lib/browser/util/preference-tree-label-provider.d.ts +1 -1
  9. package/lib/browser/util/preference-tree-label-provider.d.ts.map +1 -1
  10. package/lib/browser/util/preference-tree-label-provider.js.map +1 -1
  11. package/lib/browser/util/preference-types.d.ts +1 -1
  12. package/lib/browser/util/preference-types.d.ts.map +1 -1
  13. package/lib/browser/views/components/preference-json-input.d.ts +1 -1
  14. package/lib/browser/views/components/preference-json-input.d.ts.map +1 -1
  15. package/lib/browser/views/components/preference-node-renderer.d.ts +1 -1
  16. package/lib/browser/views/components/preference-node-renderer.d.ts.map +1 -1
  17. package/lib/browser/views/components/preference-null-input.d.ts +16 -0
  18. package/lib/browser/views/components/preference-null-input.d.ts.map +1 -0
  19. package/lib/browser/views/components/preference-null-input.js +59 -0
  20. package/lib/browser/views/components/preference-null-input.js.map +1 -0
  21. package/lib/browser/views/components/preference-number-input.d.ts.map +1 -1
  22. package/lib/browser/views/components/preference-number-input.js +44 -8
  23. package/lib/browser/views/components/preference-number-input.js.map +1 -1
  24. package/lib/browser/views/components/preference-select-input.d.ts +1 -1
  25. package/lib/browser/views/components/preference-select-input.d.ts.map +1 -1
  26. package/lib/browser/views/preference-editor-widget.d.ts +3 -0
  27. package/lib/browser/views/preference-editor-widget.d.ts.map +1 -1
  28. package/lib/browser/views/preference-editor-widget.js +15 -2
  29. package/lib/browser/views/preference-editor-widget.js.map +1 -1
  30. package/lib/browser/views/preference-scope-tabbar-widget.d.ts +1 -1
  31. package/lib/browser/views/preference-scope-tabbar-widget.d.ts.map +1 -1
  32. package/lib/browser/views/preference-scope-tabbar-widget.js +1 -1
  33. package/lib/browser/views/preference-scope-tabbar-widget.js.map +1 -1
  34. package/lib/browser/views/preference-widget-bindings.d.ts.map +1 -1
  35. package/lib/browser/views/preference-widget-bindings.js +3 -0
  36. package/lib/browser/views/preference-widget-bindings.js.map +1 -1
  37. package/package.json +8 -8
  38. package/src/browser/style/index.css +7 -10
  39. package/src/browser/util/preference-layout.ts +74 -1
  40. package/src/browser/util/preference-tree-generator.ts +38 -22
  41. package/src/browser/util/preference-tree-label-provider.ts +1 -1
  42. package/src/browser/util/preference-types.ts +1 -1
  43. package/src/browser/views/components/preference-json-input.ts +1 -1
  44. package/src/browser/views/components/preference-node-renderer.ts +1 -1
  45. package/src/browser/views/components/preference-null-input.ts +52 -0
  46. package/src/browser/views/components/preference-number-input.ts +43 -7
  47. package/src/browser/views/components/preference-select-input.ts +1 -1
  48. package/src/browser/views/preference-editor-widget.ts +13 -2
  49. package/src/browser/views/preference-scope-tabbar-widget.tsx +1 -1
  50. package/src/browser/views/preference-widget-bindings.ts +3 -0
@@ -18,7 +18,7 @@ import { PreferenceLeafNodeRenderer, PreferenceNodeRenderer } from './preference
18
18
  import { injectable, inject, interfaces } from '@theia/core/shared/inversify';
19
19
  import { CommandService, nls } from '@theia/core/lib/common';
20
20
  import { Preference, PreferencesCommands } from '../../util/preference-types';
21
- import { JSONValue } from '@theia/core/shared/@phosphor/coreutils';
21
+ import { JSONValue } from '@theia/core/shared/@lumino/coreutils';
22
22
  import { PreferenceLeafNodeRendererContribution } from './preference-node-renderer-creator';
23
23
 
24
24
  @injectable()
@@ -23,7 +23,7 @@ import { Preference, PreferenceMenus } from '../../util/preference-types';
23
23
  import { PreferenceTreeLabelProvider } from '../../util/preference-tree-label-provider';
24
24
  import { PreferencesScopeTabBar } from '../preference-scope-tabbar-widget';
25
25
  import { Disposable, nls } from '@theia/core/lib/common';
26
- import { JSONValue } from '@theia/core/shared/@phosphor/coreutils';
26
+ import { JSONValue } from '@theia/core/shared/@lumino/coreutils';
27
27
  import debounce = require('@theia/core/shared/lodash.debounce');
28
28
  import { PreferenceTreeModel } from '../../preference-tree-model';
29
29
  import { PreferencesSearchbarWidget } from '../preference-searchbar-widget';
@@ -0,0 +1,52 @@
1
+ // *****************************************************************************
2
+ // Copyright (C) 2025 EclipseSource GmbH and others.
3
+ //
4
+ // This program and the accompanying materials are made available under the
5
+ // terms of the Eclipse Public License v. 2.0 which is available at
6
+ // http://www.eclipse.org/legal/epl-2.0.
7
+ //
8
+ // This Source Code may also be made available under the following Secondary
9
+ // Licenses when the conditions for such availability set forth in the Eclipse
10
+ // Public License v. 2.0 are satisfied: GNU General Public License, version 2
11
+ // with the GNU Classpath Exception which is available at
12
+ // https://www.gnu.org/software/classpath/license.html.
13
+ //
14
+ // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
15
+ // *****************************************************************************
16
+
17
+ import { injectable, interfaces } from '@theia/core/shared/inversify';
18
+ import { PreferenceLeafNodeRenderer, PreferenceNodeRenderer } from './preference-node-renderer';
19
+ import { Preference } from '../../util/preference-types';
20
+ import { PreferenceLeafNodeRendererContribution } from './preference-node-renderer-creator';
21
+
22
+ @injectable()
23
+ /** For rendering preference items for which the only interesting feature is the description */
24
+ export class PreferenceNullInputRenderer extends PreferenceLeafNodeRenderer<null, HTMLElement> {
25
+ protected override createInteractable(container: HTMLElement): void {
26
+ const span = document.createElement('span');
27
+ this.interactable = span;
28
+ container.appendChild(span);
29
+ }
30
+
31
+ protected override getFallbackValue(): null {
32
+ // eslint-disable-next-line no-null/no-null
33
+ return null;
34
+ }
35
+
36
+ protected override doHandleValueChange(): void { }
37
+ }
38
+
39
+ @injectable()
40
+ export class PreferenceNullRendererContribution extends PreferenceLeafNodeRendererContribution {
41
+ static ID = 'preference-null-renderer';
42
+ id = PreferenceNullRendererContribution.ID;
43
+
44
+ canHandleLeafNode(node: Preference.LeafNode): number {
45
+ const isOnlyNull = node.preference.data.type === 'null' || Array.isArray(node.preference.data.type) && node.preference.data.type.every(candidate => candidate === 'null');
46
+ return isOnlyNull ? 5 : 0;
47
+ }
48
+
49
+ createLeafNodeRenderer(container: interfaces.Container): PreferenceNodeRenderer {
50
+ return container.get(PreferenceNullInputRenderer);
51
+ }
52
+ }
@@ -14,7 +14,7 @@
14
14
  // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
15
15
  // *****************************************************************************
16
16
 
17
- import { nls } from '@theia/core';
17
+ import { nls, isBoolean, isNumber } from '@theia/core';
18
18
  import { injectable, interfaces } from '@theia/core/shared/inversify';
19
19
  import { Preference } from '../../util/preference-types';
20
20
  import { PreferenceLeafNodeRenderer, PreferenceNodeRenderer } from './preference-node-renderer';
@@ -105,15 +105,51 @@ export class PreferenceNumberInputRenderer extends PreferenceLeafNodeRenderer<nu
105
105
  if (input === '' || isNaN(inputValue)) {
106
106
  return { value: NaN, message: nls.localizeByDefault('Value must be a number.') };
107
107
  }
108
- if (data.minimum && inputValue < data.minimum) {
109
- errorMessages.push(nls.localizeByDefault('Value must be greater than or equal to {0}.', data.minimum));
110
- };
111
- if (data.maximum && inputValue > data.maximum) {
112
- errorMessages.push(nls.localizeByDefault('Value must be less than or equal to {0}.', data.maximum));
113
- };
114
108
  if (data.type === 'integer' && !Number.isInteger(inputValue)) {
115
109
  errorMessages.push(nls.localizeByDefault('Value must be an integer.'));
116
110
  }
111
+ if (data.minimum !== undefined && isFinite(data.minimum)) {
112
+ // https://json-schema.org/understanding-json-schema/reference/numeric
113
+ // "In JSON Schema Draft 4, exclusiveMinimum and exclusiveMaximum work differently.
114
+ // There they are boolean values, that indicate whether minimum and maximum are exclusive of the value"
115
+ if (isBoolean(data.exclusiveMinimum) && data.exclusiveMinimum) {
116
+ if (inputValue <= data.minimum) {
117
+ errorMessages.push(nls.localizeByDefault('Value must be strictly greater than {0}.', data.minimum));
118
+ }
119
+ } else {
120
+ if (inputValue < data.minimum) {
121
+ errorMessages.push(nls.localizeByDefault('Value must be greater than or equal to {0}.', data.minimum));
122
+ }
123
+ }
124
+ }
125
+ if (data.maximum !== undefined && isFinite(data.maximum)) {
126
+ // https://json-schema.org/understanding-json-schema/reference/numeric
127
+ // "In JSON Schema Draft 4, exclusiveMinimum and exclusiveMaximum work differently.
128
+ // There they are boolean values, that indicate whether minimum and maximum are exclusive of the value"
129
+ if (isBoolean(data.exclusiveMaximum) && data.exclusiveMaximum) {
130
+ if (inputValue >= data.maximum) {
131
+ errorMessages.push(nls.localizeByDefault('Value must be strictly less than {0}.', data.maximum));
132
+ }
133
+ } else {
134
+ if (inputValue > data.maximum) {
135
+ errorMessages.push(nls.localizeByDefault('Value must be less than or equal to {0}.', data.maximum));
136
+ }
137
+ }
138
+ }
139
+ // Using JSON Schema before Draft 4 both exclusive and non-exclusive variants can be set
140
+ if (isNumber(data.exclusiveMinimum) && isFinite(data.exclusiveMinimum)) {
141
+ if (inputValue <= data.exclusiveMinimum) {
142
+ errorMessages.push(nls.localizeByDefault('Value must be strictly greater than {0}.', data.exclusiveMinimum));
143
+ }
144
+ }
145
+ if (isNumber(data.exclusiveMaximum) && isFinite(data.exclusiveMaximum)) {
146
+ if (inputValue >= data.exclusiveMaximum) {
147
+ errorMessages.push(nls.localizeByDefault('Value must be strictly less than {0}.', data.exclusiveMaximum));
148
+ }
149
+ }
150
+ if (isNumber(data.multipleOf) && data.multipleOf !== 0 && !Number.isInteger(inputValue / data.multipleOf)) {
151
+ errorMessages.push(nls.localizeByDefault('Value must be a multiple of {0}.', data.multipleOf));
152
+ }
117
153
 
118
154
  return {
119
155
  value: errorMessages.length ? NaN : inputValue,
@@ -16,7 +16,7 @@
16
16
 
17
17
  import { PreferenceLeafNodeRenderer, PreferenceNodeRenderer } from './preference-node-renderer';
18
18
  import { injectable, interfaces } from '@theia/core/shared/inversify';
19
- import { JSONValue } from '@theia/core/shared/@phosphor/coreutils';
19
+ import { JSONValue } from '@theia/core/shared/@lumino/coreutils';
20
20
  import { PreferenceProvider } from '@theia/core/lib/browser/preferences/preference-provider';
21
21
  import { SelectComponent, SelectOption } from '@theia/core/lib/browser/widgets/select-component';
22
22
  import { Preference } from '../../util/preference-types';
@@ -275,9 +275,12 @@ export class PreferencesEditorWidget extends BaseWidget implements StatefulWidge
275
275
  }
276
276
  }
277
277
 
278
+ protected shouldUpdateModelSelection = true;
279
+
278
280
  protected setFirstVisibleChildID(id?: string): void {
279
281
  if (id && id !== this.firstVisibleChildID) {
280
282
  this.firstVisibleChildID = id;
283
+ if (!this.shouldUpdateModelSelection) { return; }
281
284
  let currentNode = this.model.getNode(id);
282
285
  let expansionAncestor;
283
286
  let selectionAncestor;
@@ -314,18 +317,26 @@ export class PreferencesEditorWidget extends BaseWidget implements StatefulWidge
314
317
  if (renderer?.visible) {
315
318
  // When filtered, treat the first visible child as the selected node, since it will be the one scrolled to.
316
319
  this.lastUserSelection = renderer.nodeId;
317
- renderer.node.scrollIntoView();
320
+ this.scrollWithoutModelUpdate(renderer.node);
318
321
  return;
319
322
  }
320
323
  }
321
324
  } else {
322
325
  const { id, collection } = this.analyzeIDAndGetRendererGroup(node.id);
323
326
  const renderer = collection.get(id);
324
- renderer?.node.scrollIntoView();
327
+ this.scrollWithoutModelUpdate(renderer?.node);
325
328
  }
326
329
  }
327
330
  }
328
331
 
332
+ /** Ensures that we don't set the model's selection while attempting to scroll in reaction to a model selection change. */
333
+ protected scrollWithoutModelUpdate(node?: HTMLElement): void {
334
+ if (!node) { return; }
335
+ this.shouldUpdateModelSelection = false;
336
+ node.scrollIntoView();
337
+ requestAnimationFrame(() => this.shouldUpdateModelSelection = true);
338
+ }
339
+
329
340
  protected analyzeIDAndGetRendererGroup(nodeID: string): { id: string, group: string, collection: Map<string, GeneralPreferenceNodeRenderer> } {
330
341
  const { id, group } = Preference.TreeNode.getGroupAndIdFromNodeId(nodeID);
331
342
  const collection = group === COMMONLY_USED_SECTION_PREFIX ? this.commonlyUsedRenderers : this.renderers;
@@ -15,7 +15,7 @@
15
15
  // *****************************************************************************
16
16
 
17
17
  import { inject, injectable, postConstruct } from '@theia/core/shared/inversify';
18
- import { TabBar, Widget, Title } from '@theia/core/shared/@phosphor/widgets';
18
+ import { TabBar, Widget, Title } from '@theia/core/shared/@lumino/widgets';
19
19
  import { PreferenceScope, Message, ContextMenuRenderer, LabelProvider, StatefulWidget, codicon } from '@theia/core/lib/browser';
20
20
  import { WorkspaceService } from '@theia/workspace/lib/browser/workspace-service';
21
21
  import URI from '@theia/core/lib/common/uri';
@@ -36,6 +36,7 @@ import { PreferencesScopeTabBar } from './preference-scope-tabbar-widget';
36
36
  import { PreferencesSearchbarWidget } from './preference-searchbar-widget';
37
37
  import { PreferencesTreeWidget } from './preference-tree-widget';
38
38
  import { PreferencesWidget } from './preference-widget';
39
+ import { PreferenceNullInputRenderer, PreferenceNullRendererContribution } from './components/preference-null-input';
39
40
 
40
41
  export function bindPreferencesWidgets(bind: interfaces.Bind): void {
41
42
  bind(PreferenceTreeLabelProvider).toSelf().inSingletonScope();
@@ -58,6 +59,8 @@ export function bindPreferencesWidgets(bind: interfaces.Bind): void {
58
59
 
59
60
  bind(PreferenceStringInputRenderer).toSelf();
60
61
  bind(PreferenceNodeRendererContribution).to(PreferenceStringInputRendererContribution).inSingletonScope();
62
+ bind(PreferenceNullInputRenderer).toSelf();
63
+ bind(PreferenceNodeRendererContribution).to(PreferenceNullRendererContribution).inSingletonScope();
61
64
 
62
65
  bind(PreferenceBooleanInputRenderer).toSelf();
63
66
  bind(PreferenceNodeRendererContribution).to(PreferenceBooleanInputRendererContribution).inSingletonScope();