@knime/kds-code-editor 6.7.1 → 6.8.1

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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,41 @@
1
1
  # @knime/kds-code-editor
2
2
 
3
+ ## 6.8.1
4
+
5
+ ### Patch Changes
6
+
7
+ - f98f6e3: `KdsCodeEditor` / `KdsCodeDiffEditor`: fixed cursor placement and selection
8
+ width being offset from the rendered text. Monaco measured the character width
9
+ before the code font was loaded and kept the fallback font's metrics for the
10
+ whole page; the code font is now loaded explicitly and the fonts are
11
+ re-measured once it arrived.
12
+ - Updated dependencies [2d8e635]
13
+ - @knime/kds-components@6.8.1
14
+ - @knime/kds-styles@6.8.1
15
+
16
+ ## 6.8.0
17
+
18
+ ### Minor Changes
19
+
20
+ - de14193: - `KdsCodeEditor`:
21
+ - added `highlighted` prop — keeps the focus highlight on while the code area
22
+ is not focused and marks the editor as the current one via `aria-current`,
23
+ for lists of editors where one stays the target of outside actions after the
24
+ focus has moved on. At most one editor of a list may set it; enforcing that
25
+ is the caller's job.
26
+ - added `preserveSubTextSpace` prop — reserves the sub-text line while no
27
+ `subText` is shown, preventing layout shifts when a validation message
28
+ appears or disappears.
29
+ - `KdsCodeDiffEditor`: added `preserveSubTextSpace` prop — reserves the
30
+ sub-text line while no `subText` is shown, preventing layout shifts when a
31
+ validation message appears or disappears.
32
+
33
+ ### Patch Changes
34
+
35
+ - Updated dependencies [de14193]
36
+ - @knime/kds-components@6.8.0
37
+ - @knime/kds-styles@6.8.0
38
+
3
39
  ## 6.7.1
4
40
 
5
41
  ### Patch Changes
package/dist/index.css CHANGED
@@ -1,13 +1,13 @@
1
1
 
2
2
  .kds-code-editor {
3
- &[data-v-81449d1b] {
3
+ &[data-v-03dd8fb6] {
4
4
  display: flex;
5
5
  flex-direction: column;
6
6
 
7
7
  /* No row bounds set: fill the width and height of the container. */
8
8
  }
9
9
  .editor {
10
- &[data-v-81449d1b] {
10
+ &[data-v-03dd8fb6] {
11
11
  display: flex;
12
12
  flex-direction: column;
13
13
  overflow: hidden;
@@ -15,18 +15,19 @@
15
15
  border: var(--kds-border-base-subtle);
16
16
  border-radius: var(--kds-border-radius-container-0-50x);
17
17
 
18
- /* Only outline the whole editor when the code area (Monaco) is focused —
19
- header buttons keep their own focus ring. */
18
+ /* Outline the whole editor while the code area (Monaco) is focused, or
19
+ while the owning component keeps the highlight on without it — header
20
+ buttons keep their own focus ring either way. */
20
21
 
21
22
  /* Keeps its natural height — in fill mode only the code area grows /
22
23
  shrinks with the container. */
23
24
  }
24
- &.focused[data-v-81449d1b] {
25
+ &.focused[data-v-03dd8fb6] {
25
26
  outline: var(--kds-border-action-focused);
26
27
  outline-offset: var(--kds-spacing-offset-focus);
27
28
  }
28
29
  .header {
29
- &[data-v-81449d1b] {
30
+ &[data-v-03dd8fb6] {
30
31
  display: flex;
31
32
  align-items: center;
32
33
  justify-content: space-between;
@@ -36,7 +37,7 @@
36
37
 
37
38
  /* Visually hidden, still announced by screen readers. */
38
39
  }
39
- .left-block[data-v-81449d1b] {
40
+ .left-block[data-v-03dd8fb6] {
40
41
  display: flex;
41
42
  flex: 1;
42
43
  gap: var(--kds-spacing-container-0-25x);
@@ -47,13 +48,13 @@
47
48
  buttons are present (matches the small button height). */
48
49
  min-height: var(--kds-dimension-component-height-1-5x);
49
50
  }
50
- .action-buttons[data-v-81449d1b] {
51
+ .action-buttons[data-v-03dd8fb6] {
51
52
  display: flex;
52
53
  flex-shrink: 0;
53
54
  gap: var(--kds-spacing-container-0-12x);
54
55
  align-items: center;
55
56
  }
56
- .title[data-v-81449d1b] {
57
+ .title[data-v-03dd8fb6] {
57
58
  overflow: hidden;
58
59
  text-overflow: ellipsis;
59
60
  font: var(--kds-font-base-interactive-small);
@@ -61,7 +62,7 @@
61
62
  white-space: nowrap;
62
63
  }
63
64
  .change-counts {
64
- &[data-v-81449d1b] {
65
+ &[data-v-03dd8fb6] {
65
66
  display: flex;
66
67
  flex-shrink: 0;
67
68
  gap: var(--kds-spacing-container-0-12x);
@@ -72,14 +73,14 @@
72
73
  margin-left: var(--kds-spacing-container-0-25x);
73
74
  font: var(--kds-font-base-interactive-small);
74
75
  }
75
- .added-lines[data-v-81449d1b] {
76
+ .added-lines[data-v-03dd8fb6] {
76
77
  color: var(--kds-color-text-and-icon-success);
77
78
  }
78
- .removed-lines[data-v-81449d1b] {
79
+ .removed-lines[data-v-03dd8fb6] {
79
80
  color: var(--kds-color-text-and-icon-danger);
80
81
  }
81
82
  }
82
- .change-counts-for-screen-readers[data-v-81449d1b] {
83
+ .change-counts-for-screen-readers[data-v-03dd8fb6] {
83
84
  position: absolute;
84
85
  width: 1px;
85
86
  height: 1px;
@@ -91,33 +92,33 @@
91
92
  clip-path: inset(50%);
92
93
  }
93
94
  }
94
- &.error .header[data-v-81449d1b] {
95
+ &.error .header[data-v-03dd8fb6] {
95
96
  background-color: var(--kds-color-background-static-danger-muted);
96
97
  }
97
- &.warning .header[data-v-81449d1b] {
98
+ &.warning .header[data-v-03dd8fb6] {
98
99
  background-color: var(--kds-color-background-static-warning-muted);
99
100
  }
100
- .code[data-v-81449d1b] {
101
+ .code[data-v-03dd8fb6] {
101
102
  width: 100%;
102
103
  }
103
- .footer[data-v-81449d1b] {
104
+ .footer[data-v-03dd8fb6] {
104
105
  flex-shrink: 0;
105
106
  width: 100%;
106
107
  }
107
108
  }
108
109
  &.fill {
109
- &[data-v-81449d1b] {
110
+ &[data-v-03dd8fb6] {
110
111
  width: 100%;
111
112
  height: 100%;
112
113
 
113
114
  /* A collapsed editor keeps its header height instead of stretching. */
114
115
  }
115
- .editor[data-v-81449d1b],
116
- .code[data-v-81449d1b] {
116
+ .editor[data-v-03dd8fb6],
117
+ .code[data-v-03dd8fb6] {
117
118
  flex: 1 1 auto;
118
119
  min-height: 0;
119
120
  }
120
- .editor.collapsed[data-v-81449d1b] {
121
+ .editor.collapsed[data-v-03dd8fb6] {
121
122
  flex: 0 0 auto;
122
123
  }
123
124
  }
package/dist/index.js CHANGED
@@ -52,6 +52,10 @@ var BaseCodeEditor_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ d
52
52
  default: false
53
53
  },
54
54
  subText: { default: () => void 0 },
55
+ preserveSubTextSpace: {
56
+ type: Boolean,
57
+ default: false
58
+ },
55
59
  copyable: {
56
60
  type: Boolean,
57
61
  default: true
@@ -62,7 +66,7 @@ var BaseCodeEditor_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ d
62
66
  },
63
67
  copyButtonAriaLabel: { default: "" },
64
68
  editorActions: { default: () => void 0 },
65
- focused: {
69
+ showFocusHighlight: {
66
70
  type: Boolean,
67
71
  default: false
68
72
  },
@@ -92,7 +96,7 @@ getCodeContainer: () => codeContainer.value });
92
96
  "editor",
93
97
  __props.state,
94
98
  {
95
- focused: __props.focused,
99
+ focused: __props.showFocusHighlight,
96
100
  collapsed: __props.collapsed
97
101
  }
98
102
  ]) }, [
@@ -146,18 +150,19 @@ getCodeContainer: () => codeContainer.value });
146
150
  style: normalizeStyle(__props.codeHeight ? { height: __props.codeHeight } : void 0)
147
151
  }, null, 12, _hoisted_10), [[vShow, !__props.collapsed]]),
148
152
  _ctx.$slots.footer ? withDirectives((openBlock(), createElementBlock("div", _hoisted_11, [renderSlot(_ctx.$slots, "footer", {}, void 0, true)], 512)), [[vShow, !__props.collapsed]]) : createCommentVNode("", true)
149
- ], 2), __props.subText ? (openBlock(), createBlock(unref(KdsSubText), {
150
- key: 0,
153
+ ], 2), createVNode(unref(KdsSubText), {
151
154
  id: __props.subTextId,
152
155
  "sub-text": __props.subText,
156
+ "preserve-sub-text-space": __props.preserveSubTextSpace,
153
157
  error: __props.state === unref(kdsCodeEditorState).ERROR,
154
158
  warning: __props.state === unref(kdsCodeEditorState).WARNING
155
159
  }, null, 8, [
156
160
  "id",
157
161
  "sub-text",
162
+ "preserve-sub-text-space",
158
163
  "error",
159
164
  "warning"
160
- ])) : createCommentVNode("", true)], 2);
165
+ ])], 2);
161
166
  };
162
167
  }
163
168
  });
@@ -170,7 +175,7 @@ var _plugin_vue_export_helper_default = (sfc, props) => {
170
175
  };
171
176
  //#endregion
172
177
  //#region src/_helper/BaseCodeEditor.vue
173
- var BaseCodeEditor_default = /*#__PURE__*/ _plugin_vue_export_helper_default(BaseCodeEditor_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-81449d1b"]]);
178
+ var BaseCodeEditor_default = /*#__PURE__*/ _plugin_vue_export_helper_default(BaseCodeEditor_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-03dd8fb6"]]);
174
179
  //#endregion
175
180
  //#region ../styles/dist/tokens/ts/color.js
176
181
  /**
@@ -5690,11 +5695,30 @@ var registerTomlLanguage = () => {
5690
5695
  };
5691
5696
  //#endregion
5692
5697
  //#region src/CodeEditor/monacoEnvironment.ts
5693
- document.fonts?.ready.then(() => {
5694
- editor.remeasureFonts();
5695
- });
5698
+ var MEASURED_CHARACTERS = "n 0123456789|/-_ilm%·";
5699
+ var fontRemeasureScheduled = false;
5700
+ /**
5701
+ * Monaco measures character widths when an editor is created, caches them for
5702
+ * the whole page, and derives cursor placement and selection width from them.
5703
+ * That measurement is also the first use of the code font, so it happens
5704
+ * before the font is loaded and keeps the fallback font's metrics — cursor and
5705
+ * selection then drift away from the glyphs (KDS-1002).
5706
+ *
5707
+ * `document.fonts.ready` does not help: it resolves while nothing is pending,
5708
+ * which is the case before any editor exists. So load the code font explicitly
5709
+ * and re-measure once it is there — also when loading failed, in which case
5710
+ * the fallback metrics are at least measured consistently.
5711
+ */
5712
+ var remeasureFontsWhenCodeFontLoaded = () => {
5713
+ if (fontRemeasureScheduled || !document.fonts) return;
5714
+ fontRemeasureScheduled = true;
5715
+ document.fonts.load(codeFont.css.value, MEASURED_CHARACTERS).catch(() => []).then(() => {
5716
+ editor.remeasureFonts();
5717
+ });
5718
+ };
5696
5719
  var setupMonacoEnvironment = () => {
5697
5720
  registerTomlLanguage();
5721
+ remeasureFontsWhenCodeFontLoaded();
5698
5722
  if (self.MonacoEnvironment) return;
5699
5723
  self.MonacoEnvironment = { getWorker: async (_workerId, label) => {
5700
5724
  if (label === "json") {
@@ -5725,7 +5749,15 @@ var KdsCodeEditor_default = /* @__PURE__ */ defineComponent({
5725
5749
  type: Boolean,
5726
5750
  default: false
5727
5751
  },
5752
+ highlighted: {
5753
+ type: Boolean,
5754
+ default: false
5755
+ },
5728
5756
  subText: { default: () => void 0 },
5757
+ preserveSubTextSpace: {
5758
+ type: Boolean,
5759
+ default: false
5760
+ },
5729
5761
  copyable: {
5730
5762
  type: Boolean,
5731
5763
  default: true
@@ -5746,6 +5778,7 @@ var KdsCodeEditor_default = /* @__PURE__ */ defineComponent({
5746
5778
  let editorInstance;
5747
5779
  let overflowWidgetsDomNode;
5748
5780
  const isEditorFocused = ref(false);
5781
+ const showFocusHighlight = computed(() => isEditorFocused.value || __props.highlighted);
5749
5782
  const headerLabel = computed(() => __props.languageLabel ?? __props.language.toUpperCase());
5750
5783
  const editorAriaLabel = computed(() => `${headerLabel.value} code editor${__props.readOnly ? ", read-only" : ""}. Press Escape followed by Tab to move focus out of the editor.`);
5751
5784
  const fillContainer = computed(() => __props.minRows === void 0 && __props.maxRows === void 0);
@@ -5767,8 +5800,14 @@ var KdsCodeEditor_default = /* @__PURE__ */ defineComponent({
5767
5800
  else input.removeAttribute("aria-describedby");
5768
5801
  if (__props.state === kdsCodeEditorState.ERROR) input.setAttribute("aria-invalid", "true");
5769
5802
  else input.removeAttribute("aria-invalid");
5803
+ if (__props.highlighted) input.setAttribute("aria-current", "true");
5804
+ else input.removeAttribute("aria-current");
5770
5805
  };
5771
- watch([() => __props.subText, () => __props.state], syncEditorInputAria);
5806
+ watch([
5807
+ () => __props.subText,
5808
+ () => __props.state,
5809
+ () => __props.highlighted
5810
+ ], syncEditorInputAria);
5772
5811
  const { copy, copied } = useClipboard({ copiedDuring: 2e3 });
5773
5812
  const copyButtonAriaLabel = computed(() => copied.value ? `Copied ${headerLabel.value} to clipboard` : `Copy ${headerLabel.value} to clipboard`);
5774
5813
  const copyToClipboard = () => {
@@ -5846,11 +5885,12 @@ getEditor: () => editorInstance });
5846
5885
  state: __props.state,
5847
5886
  "read-only": __props.readOnly,
5848
5887
  "sub-text": __props.subText,
5888
+ "preserve-sub-text-space": __props.preserveSubTextSpace,
5849
5889
  copyable: __props.copyable,
5850
5890
  copied: unref(copied),
5851
5891
  "copy-button-aria-label": copyButtonAriaLabel.value,
5852
5892
  "editor-actions": __props.editorActions,
5853
- focused: isEditorFocused.value,
5893
+ "show-focus-highlight": showFocusHighlight.value,
5854
5894
  fill: fillContainer.value,
5855
5895
  "code-height": editorHeight.value,
5856
5896
  onCopy: copyToClipboard
@@ -5865,11 +5905,12 @@ getEditor: () => editorInstance });
5865
5905
  "state",
5866
5906
  "read-only",
5867
5907
  "sub-text",
5908
+ "preserve-sub-text-space",
5868
5909
  "copyable",
5869
5910
  "copied",
5870
5911
  "copy-button-aria-label",
5871
5912
  "editor-actions",
5872
- "focused",
5913
+ "show-focus-highlight",
5873
5914
  "fill",
5874
5915
  "code-height"
5875
5916
  ]);
@@ -5905,6 +5946,10 @@ var KdsCodeDiffEditor_default = /* @__PURE__ */ defineComponent({
5905
5946
  default: false
5906
5947
  },
5907
5948
  subText: { default: () => void 0 },
5949
+ preserveSubTextSpace: {
5950
+ type: Boolean,
5951
+ default: false
5952
+ },
5908
5953
  editorActions: { default: () => void 0 },
5909
5954
  minRows: { default: () => void 0 },
5910
5955
  maxRows: { default: () => void 0 },
@@ -6085,9 +6130,10 @@ getEditor: () => diffEditorInstance });
6085
6130
  state: __props.state,
6086
6131
  "read-only": __props.readOnly,
6087
6132
  "sub-text": __props.subText,
6133
+ "preserve-sub-text-space": __props.preserveSubTextSpace,
6088
6134
  copyable: false,
6089
6135
  "editor-actions": __props.editorActions,
6090
- focused: isEditorFocused.value,
6136
+ "show-focus-highlight": isEditorFocused.value,
6091
6137
  fill: fillContainer.value,
6092
6138
  "code-height": editorHeight.value,
6093
6139
  "change-summary": __props.changeSummary,
@@ -6102,8 +6148,9 @@ getEditor: () => diffEditorInstance });
6102
6148
  "state",
6103
6149
  "read-only",
6104
6150
  "sub-text",
6151
+ "preserve-sub-text-space",
6105
6152
  "editor-actions",
6106
- "focused",
6153
+ "show-focus-highlight",
6107
6154
  "fill",
6108
6155
  "code-height",
6109
6156
  "change-summary",