@gravitee/ui-components 3.24.3-migrate-codemirror-bed237b → 3.24.4-migrate-codemirror-6bf640d

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,3 +1,10 @@
1
+ ## [3.24.4](https://github.com/gravitee-io/gravitee-ui-components/compare/v3.24.3...v3.24.4) (2021-12-16)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * remove unnecessary perform update ([1b8fee6](https://github.com/gravitee-io/gravitee-ui-components/commit/1b8fee6711bf1af63bf40ca9aca2fac570590076))
7
+
1
8
  ## [3.24.3](https://github.com/gravitee-io/gravitee-ui-components/compare/v3.24.2...v3.24.3) (2021-12-15)
2
9
 
3
10
 
@@ -18,9 +18,6 @@
18
18
  "empty": "No data to display",
19
19
  "error": "An error has occurred"
20
20
  },
21
- "gv-code": {
22
- "copy": "Copy to clipboard"
23
- },
24
21
  "gv-confirm": {
25
22
  "cancel": "No",
26
23
  "ok": "Yes"
@@ -18,9 +18,6 @@
18
18
  "empty": "Aucune donnée à afficher ici",
19
19
  "error": "Une erreur est survenue pendant le chargement"
20
20
  },
21
- "gv-code": {
22
- "copy": "Copier dans le presse papier"
23
- },
24
21
  "gv-confirm": {
25
22
  "cancel": "Non",
26
23
  "ok": "Oui"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gravitee/ui-components",
3
- "version": "3.24.3-migrate-codemirror-bed237b",
3
+ "version": "3.24.4-migrate-codemirror-6bf640d",
4
4
  "description": "Gravitee.io UI Components library, based on Web Components",
5
5
  "repository": {
6
6
  "type": "git",
@@ -64,6 +64,7 @@
64
64
  "@codemirror/language-data": "^0.19.1",
65
65
  "@codemirror/matchbrackets": "^0.19.3",
66
66
  "@codemirror/state": "^0.19.6",
67
+ "@codemirror/stream-parser": "^0.19.3",
67
68
  "@codemirror/view": "^0.19.32",
68
69
  "@formatjs/intl-locale": "^2.4.40",
69
70
  "@formatjs/intl-relativetimeformat": "^9.3.2",
@@ -99,7 +100,6 @@
99
100
  "babel-plugin-template-html-minifier": "4.1.0",
100
101
  "bundle-phobia-cli": "0.14.13",
101
102
  "chromatic": "6.1.0",
102
- "codemirror-asciidoc": "1.0.4",
103
103
  "danger": "10.7.1",
104
104
  "del": "6.0.0",
105
105
  "eslint": "8.4.0",
@@ -146,7 +146,6 @@
146
146
  "@highcharts/map-collection": "^1.0.0",
147
147
  "asciidoctor": "^2.2.4",
148
148
  "asciidoctor-highlight.js": "^0.3.0 || ^0.4.0",
149
- "codemirror-asciidoc": "^1.0.4",
150
149
  "highcharts": "^8.0.0 || ^9.0.0",
151
150
  "highlight.js": "^10.7.0 || ^11.1.0"
152
151
  },
@@ -163,9 +162,6 @@
163
162
  "asciidoctor-highlight.js": {
164
163
  "optional": true
165
164
  },
166
- "codemirror-asciidoc": {
167
- "optional": true
168
- },
169
165
  "highcharts": {
170
166
  "optional": true
171
167
  },
@@ -322,14 +322,6 @@ export class GvButton extends LitElement {
322
322
  }
323
323
  }
324
324
 
325
- async performUpdate() {
326
- super.performUpdate();
327
- const icon = this.shadowRoot.querySelector('gv-icon');
328
- if (icon) {
329
- icon.performUpdate();
330
- }
331
- }
332
-
333
325
  render() {
334
326
  const classes = {
335
327
  button: true,
@@ -111,8 +111,12 @@ export class GvInput extends InputElement(LitElement) {
111
111
  --gv-icon--s: 22px;
112
112
  }
113
113
 
114
- .box-icon.copied gv-icon {
115
- --gv-icon--c: #339900;
114
+ .copied {
115
+ --gv-input--bdc: var(--gv-theme-color-success-light, #81c784);
116
+ }
117
+
118
+ .copied .box-icon gv-icon {
119
+ --gv-icon--c: var(--gv-theme-color-success-dark, #388e3c);
116
120
  }
117
121
 
118
122
  div.box-icon gv-icon.loading,
@@ -272,19 +276,7 @@ export class GvInput extends InputElement(LitElement) {
272
276
  firstUpdated(changedProperties) {
273
277
  super.firstUpdated(changedProperties);
274
278
 
275
- const defaultInputElement = this.getInputElement();
276
- for (const node of this.childNodes) {
277
- if (node.nodeType === 1) {
278
- const child = node.nodeName.toLowerCase() === 'input' ? node : node.querySelector('input');
279
- if (child) {
280
- this._input = child;
281
- break;
282
- }
283
- }
284
- }
285
- if (this._input) {
286
- defaultInputElement.remove();
287
- }
279
+ this.catchSlot();
288
280
 
289
281
  if (this.clipboard) {
290
282
  import('clipboard-copy').then(
@@ -304,13 +296,6 @@ export class GvInput extends InputElement(LitElement) {
304
296
 
305
297
  setTimeout(() => {
306
298
  const clipboardPopover = this.shadowRoot.querySelector('.clipboard__popover');
307
- if (this.readonly) {
308
- this.getInputElement().addEventListener('click', (e) => {
309
- e.preventDefault();
310
- e.stopPropagation();
311
- clipboardPopover.click();
312
- });
313
- }
314
299
  clipboardPopover.addEventListener('click', (e) => {
315
300
  e.preventDefault();
316
301
  e.stopPropagation();
@@ -325,11 +310,32 @@ export class GvInput extends InputElement(LitElement) {
325
310
  }
326
311
 
327
312
  this.getInputElement().id = this._id;
313
+
314
+ this.bindInputEvents();
315
+ }
316
+
317
+ bindInputEvents() {
328
318
  this.getInputElement().addEventListener('input', this._onInput.bind(this));
329
319
  this.getInputElement().addEventListener('keyup', this._onKeyUp.bind(this));
330
320
  this.getInputElement().addEventListener('keypress', this._onKeyPress.bind(this));
331
321
  }
332
322
 
323
+ catchSlot() {
324
+ const defaultInputElement = this.getInputElement();
325
+ for (const node of this.childNodes) {
326
+ if (node.nodeType === 1) {
327
+ const child = node.nodeName.toLowerCase() === 'input' ? node : node.querySelector('input');
328
+ if (child) {
329
+ this._input = child;
330
+ break;
331
+ }
332
+ }
333
+ }
334
+ if (this._input) {
335
+ defaultInputElement.remove();
336
+ }
337
+ }
338
+
333
339
  updateState(value) {
334
340
  super.updateState(value);
335
341
  if (this.valid === true && !this.readonly) {
@@ -481,7 +487,7 @@ export class GvInput extends InputElement(LitElement) {
481
487
  return !this.loading;
482
488
  }
483
489
 
484
- _renderIcon() {
490
+ renderIcon() {
485
491
  let shape = null;
486
492
  if ((!this.isPassword && this.icon) || this.iconLeft) {
487
493
  shape = (!this.isPassword && this.icon) || this.iconLeft;
@@ -495,7 +501,6 @@ export class GvInput extends InputElement(LitElement) {
495
501
  'box-icon': true,
496
502
  'box-icon-left': this.iconLeft != null || this.clearable,
497
503
  'box-icon-bgc': this.hasBackground,
498
- copied: this.hasClipboard && this._copied,
499
504
  };
500
505
 
501
506
  const iconClasses = {
@@ -538,6 +543,7 @@ export class GvInput extends InputElement(LitElement) {
538
543
  'icon-left': !!this.iconLeft || (!!this.icon && this.clearable),
539
544
  clipboard: this.hasClipboard,
540
545
  required: this.required,
546
+ copied: this.hasClipboard && this._copied,
541
547
  };
542
548
 
543
549
  return html`
@@ -545,7 +551,7 @@ export class GvInput extends InputElement(LitElement) {
545
551
  ${this.renderLabel()}
546
552
  <input />
547
553
  <slot></slot>
548
- ${this._renderClearIcon()} ${this._renderIcon()} ${this._renderPasswordIcon()}
554
+ ${this._renderClearIcon()} ${this.renderIcon()} ${this._renderPasswordIcon()}
549
555
  </div>
550
556
  ${this.description != null ? html`<div class="description" .innerHTML="${this.description}"></div>` : ''}
551
557
  `;
@@ -0,0 +1,642 @@
1
+ /*
2
+ * Copyright (C) 2021 The Gravitee team (http://gravitee.io)
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+ // Ace highlight rules function imported below.
17
+ const HighlightRules = function () {
18
+ const identifierRe = '[a-zA-Z\u00a1-\uffff]+\\b';
19
+ /* eslint no-useless-escape: "off" */
20
+ this.$rules = {
21
+ start: [
22
+ { token: 'empty', regex: /$/ },
23
+ { token: 'literal', regex: /^\.{4,}\s*$/, next: 'listingBlock' },
24
+ { token: 'literal', regex: /^-{4,}\s*$/, next: 'literalBlock' },
25
+ { token: 'literal', regex: /^\+{4,}\s*$/, next: 'passthroughBlock' },
26
+ { token: 'keyword', regex: /^={4,}\s*$/ },
27
+ { token: 'text', regex: /^\s*$/ },
28
+ // immediately return to the start mode without matching anything
29
+ { token: 'empty', regex: '', next: 'dissallowDelimitedBlock' },
30
+ ],
31
+
32
+ dissallowDelimitedBlock: [
33
+ { include: 'paragraphEnd' },
34
+ { token: 'comment', regex: '^//.+$' },
35
+ { token: 'keyword', regex: '^(?:NOTE|TIP|IMPORTANT|WARNING|CAUTION):\\s' },
36
+
37
+ { include: 'listStart' },
38
+ { token: 'literal', regex: /^\s+.+$/, next: 'indentedBlock' },
39
+ { token: 'empty', regex: '', next: 'text' },
40
+ ],
41
+
42
+ paragraphEnd: [
43
+ { token: 'doc.comment', regex: /^\/{4,}\s*$/, next: 'commentBlock' },
44
+ { token: 'tableBlock', regex: /^\s*[|!]=+\s*$/, next: 'tableBlock' },
45
+ // open block, ruler
46
+ { token: 'keyword', regex: /^(?:--|''')\s*$/, next: 'start' },
47
+ { token: 'option', regex: /^\[.*\]\s*$/, next: 'start' },
48
+ { token: 'pageBreak', regex: /^>{3,}$/, next: 'start' },
49
+ { token: 'literal', regex: /^\.{4,}\s*$/, next: 'listingBlock' },
50
+ { token: 'titleUnderline', regex: /^(?:={2,}|-{2,}|~{2,}|\^{2,}|\+{2,})\s*$/, next: 'start' },
51
+ { token: 'singleLineTitle', regex: /^={1,6}\s+\S.*$/, next: 'start' },
52
+
53
+ { token: 'otherBlock', regex: /^(?:\*{2,}|_{2,})\s*$/, next: 'start' },
54
+ // .optional title
55
+ { token: 'optionalTitle', regex: /^\.[^.\s].+$/, next: 'start' },
56
+ ],
57
+
58
+ listStart: [
59
+ {
60
+ token: 'keyword',
61
+ regex: /^\s*(?:\d+\.|[a-zA-Z]\.|[ixvmIXVM]+\)|\*{1,5}|-|\.{1,5})\s/,
62
+ next: 'listText',
63
+ },
64
+ { token: 'meta.tag', regex: /^.+(?::{2,4}|;;)(?: |$)/, next: 'listText' },
65
+ // continuation
66
+ { token: 'keyword', regex: /^\+\s*$/, next: 'start' },
67
+ ],
68
+
69
+ text: [
70
+ {
71
+ token: ['link', 'link'],
72
+ regex: /((?:https?:\/\/|ftp:\/\/|file:\/\/|mailto:|callto:)[^\s\[]+)(\[.*?\])/,
73
+ },
74
+ { token: ['link', 'link'], regex: /(?:https?:\/\/|ftp:\/\/|file:\/\/|mailto:|callto:)[^\s\[]+/ },
75
+ { token: 'link', regex: /\b[\w\.\/\-]+@[\w\.\/\-]+\b/ },
76
+ { include: 'macros' },
77
+ { include: 'paragraphEnd' },
78
+ { token: 'literal', regex: /\+{3,}/, next: 'smallPassthrough' },
79
+ {
80
+ token: 'escape',
81
+ regex: /\((?:C|TM|R)\)|\.{3}|->|<-|=>|<=|&#(?:\d+|x[a-fA-F\d]+);|(?: |^)--(?=\s+\S)/,
82
+ },
83
+ { token: 'escape', regex: /\\[_*'`+#]|\\{2}[_*'`+#]{2}/ },
84
+ { token: 'keyword', regex: /\s\+$/ },
85
+ // any word
86
+ { token: 'text', regex: identifierRe },
87
+ {
88
+ token: ['keyword', 'string', 'keyword'],
89
+ regex: /(<<[\w\d\-$]+,)(.*?)(>>|$)/,
90
+ },
91
+ { token: 'keyword', regex: /<<[\w\d\-$]+,?|>>/ },
92
+ { token: 'constant.character', regex: /\({2,3}.*?\){2,3}/ },
93
+ // List of callouts
94
+ { token: 'support.function.list.callout', regex: /^(?:<\d+>|\d+>|>) /, next: 'text' },
95
+ // Anchor
96
+ { token: 'keyword', regex: /\[\[.+?\]\]/ },
97
+ // bibliography
98
+ { token: 'support', regex: /^\[{3}[\w\d =\-]+\]{3}/ },
99
+
100
+ { include: 'quotes' },
101
+ // text block end
102
+ { token: 'empty', regex: /^\s*$/, next: 'start' },
103
+ ],
104
+
105
+ listText: [{ include: 'listStart' }, { include: 'text' }],
106
+
107
+ indentedBlock: [
108
+ { token: 'literal', regex: /^[\s\w].+$/, next: 'indentedBlock' },
109
+ { token: 'literal', regex: '', next: 'start' },
110
+ ],
111
+
112
+ listingBlock: [
113
+ { token: 'literal', regex: /^\.{4,}\s*$/, next: 'dissallowDelimitedBlock' },
114
+ { token: 'constant.numeric', regex: '<\\d+>' },
115
+ { token: 'literal', regex: '[^<]+' },
116
+ { token: 'literal', regex: '<' },
117
+ ],
118
+ literalBlock: [
119
+ { token: 'literal', regex: /^-{4,}\s*$/, next: 'dissallowDelimitedBlock' },
120
+ { token: 'constant.numeric', regex: '<\\d+>' },
121
+ { token: 'literal', regex: '[^<]+' },
122
+ { token: 'literal', regex: '<' },
123
+ ],
124
+ passthroughBlock: [
125
+ { token: 'literal', regex: /^\+{4,}\s*$/, next: 'dissallowDelimitedBlock' },
126
+ { token: 'literal', regex: identifierRe + '|\\d+' },
127
+ { include: 'macros' },
128
+ { token: 'literal', regex: '.' },
129
+ ],
130
+
131
+ smallPassthrough: [
132
+ { token: 'literal', regex: /[+]{3,}/, next: 'dissallowDelimitedBlock' },
133
+ { token: 'literal', regex: /^\s*$/, next: 'dissallowDelimitedBlock' },
134
+ { token: 'literal', regex: identifierRe + '|\\d+' },
135
+ { include: 'macros' },
136
+ ],
137
+
138
+ commentBlock: [
139
+ { token: 'doc.comment', regex: /^\/{4,}\s*$/, next: 'dissallowDelimitedBlock' },
140
+ { token: 'doc.comment', regex: '^.*$' },
141
+ ],
142
+ tableBlock: [
143
+ { token: 'tableBlock', regex: /^\s*\|={3,}\s*$/, next: 'dissallowDelimitedBlock' },
144
+ { token: 'tableBlock', regex: /^\s*!={3,}\s*$/, next: 'innerTableBlock' },
145
+ { token: 'tableBlock', regex: /\|/ },
146
+ { include: 'text', noEscape: true },
147
+ ],
148
+ innerTableBlock: [
149
+ { token: 'tableBlock', regex: /^\s*!={3,}\s*$/, next: 'tableBlock' },
150
+ { token: 'tableBlock', regex: /^\s*|={3,}\s*$/, next: 'dissallowDelimitedBlock' },
151
+ { token: 'tableBlock', regex: /\!/ },
152
+ ],
153
+ macros: [
154
+ { token: 'macro', regex: /{[\w\-$]+}/ },
155
+ {
156
+ token: ['text', 'string', 'text', 'constant.character', 'text'],
157
+ regex: /({)([\w\-$]+)(:)?(.+)?(})/,
158
+ },
159
+ {
160
+ token: ['text', 'markup.list.macro', 'keyword', 'string'],
161
+ regex: /(\w+)(footnote(?:ref)?::?)([^\s\[]+)?(\[.*?\])?/,
162
+ },
163
+ {
164
+ token: ['markup.list.macro', 'keyword', 'string'],
165
+ regex: /([a-zA-Z\-][\w\.\/\-]*::?)([^\s\[]+)(\[.*?\])?/,
166
+ },
167
+ { token: ['markup.list.macro', 'keyword'], regex: /([a-zA-Z\-][\w\.\/\-]+::?)(\[.*?\])/ },
168
+ { token: 'keyword', regex: /^:.+?:(?= |$)/ },
169
+ ],
170
+
171
+ quotes: [
172
+ { token: 'string.italic', regex: /__[^_\s].*?__/ },
173
+ { token: 'string.italic', regex: quoteRule('_') },
174
+
175
+ { token: 'keyword.bold', regex: /\*\*[^*\s].*?\*\*/ },
176
+ { token: 'keyword.bold', regex: quoteRule('\\*') },
177
+
178
+ { token: 'literal', regex: /\+\+[^+\s].*?\+\+/ },
179
+ { token: 'literal', regex: quoteRule('\\+') },
180
+
181
+ { token: 'literal', regex: /\$\$.+?\$\$/ },
182
+ { token: 'literal', regex: quoteRule('\\$') },
183
+
184
+ { token: 'literal', regex: /``[^`\s].*?``/ },
185
+ { token: 'literal', regex: quoteRule('`') },
186
+
187
+ { token: 'keyword', regex: /\^[^\^].*?\^/ },
188
+ { token: 'keyword', regex: quoteRule('\\^') },
189
+ { token: 'keyword', regex: /~[^~].*?~/ },
190
+ { token: 'keyword', regex: quoteRule('~') },
191
+
192
+ { token: 'keyword', regex: /##?/ },
193
+ { token: 'keyword', regex: /(?:\B|^)``|\b''/ },
194
+ ],
195
+ };
196
+
197
+ function quoteRule(ch) {
198
+ const prefix = /\w/.test(ch) ? '\\b' : '(?:\\B|^)';
199
+ return prefix + ch + '[^' + ch + '].*?' + ch + '(?![\\w*])';
200
+ }
201
+
202
+ // addQuoteBlock("text")
203
+
204
+ const tokenMap = {
205
+ macro: 'constant.character',
206
+ tableBlock: 'doc.comment',
207
+ titleUnderline: 'markup.heading',
208
+ singleLineTitle: 'markup.heading',
209
+ pageBreak: 'string',
210
+ option: 'string.regexp',
211
+ otherBlock: 'markup.list',
212
+ literal: 'support.function',
213
+ optionalTitle: 'constant.numeric',
214
+ escape: 'constant.language.escape',
215
+ link: 'markup.underline.list',
216
+ };
217
+
218
+ for (const state in this.$rules) {
219
+ const stateRules = this.$rules[state];
220
+ for (let i = stateRules.length; i--; ) {
221
+ const rule = stateRules[i];
222
+ if (rule.include || typeof rule === 'string') {
223
+ let args = [i, 1].concat(this.$rules[rule.include || rule]);
224
+ if (rule.noEscape) {
225
+ args = args.filter(function (x) {
226
+ return !x.next;
227
+ });
228
+ }
229
+ stateRules.splice.apply(stateRules, args);
230
+ } else if (rule.token in tokenMap) {
231
+ rule.token = tokenMap[rule.token];
232
+ }
233
+ }
234
+ }
235
+ };
236
+
237
+ // Ace's Syntax Tokenizer.
238
+
239
+ // tokenizing lines longer than this makes editor very slow
240
+ let MAX_TOKEN_COUNT = 1000;
241
+ const Tokenizer = function (rules) {
242
+ this.states = rules;
243
+
244
+ this.regExps = {};
245
+ this.matchMappings = {};
246
+ for (const key in this.states) {
247
+ const state = this.states[key];
248
+ const ruleRegExps = [];
249
+ let matchTotal = 0;
250
+ const mapping = (this.matchMappings[key] = { defaultToken: 'text' });
251
+ let flag = 'g';
252
+
253
+ const splitterRurles = [];
254
+ for (let i = 0; i < state.length; i++) {
255
+ const rule = state[i];
256
+ if (rule.defaultToken) mapping.defaultToken = rule.defaultToken;
257
+ if (rule.caseInsensitive) flag = 'gi';
258
+ if (rule.regex == null) continue;
259
+
260
+ if (rule.regex instanceof RegExp) rule.regex = rule.regex.toString().slice(1, -1);
261
+
262
+ // Count number of matching groups. 2 extra groups from the full match
263
+ // And the catch-all on the end (used to force a match);
264
+ let adjustedregex = rule.regex;
265
+ let matchcount = new RegExp('(?:(' + adjustedregex + ')|(.))').exec('a').length - 2;
266
+ if (Array.isArray(rule.token)) {
267
+ if (rule.token.length === 1 || matchcount === 1) {
268
+ rule.token = rule.token[0];
269
+ } else if (matchcount - 1 !== rule.token.length) {
270
+ throw new Error(
271
+ "number of classes and regexp groups in '" +
272
+ rule.token +
273
+ "'\n'" +
274
+ rule.regex +
275
+ "' doesn't match\n" +
276
+ (matchcount - 1) +
277
+ '!=' +
278
+ rule.token.length,
279
+ );
280
+ } else {
281
+ rule.tokenArray = rule.token;
282
+ rule.token = null;
283
+ rule.onMatch = this.$arrayTokens;
284
+ }
285
+ } else if (typeof rule.token === 'function' && !rule.onMatch) {
286
+ if (matchcount > 1) rule.onMatch = this.$applyToken;
287
+ else rule.onMatch = rule.token;
288
+ }
289
+
290
+ if (matchcount > 1) {
291
+ if (/\\\d/.test(rule.regex)) {
292
+ // Replace any backreferences and offset appropriately.
293
+ adjustedregex = rule.regex.replace(/\\([0-9]+)/g, function (match, digit) {
294
+ return '\\' + (parseInt(digit, 10) + matchTotal + 1);
295
+ });
296
+ } else {
297
+ matchcount = 1;
298
+ adjustedregex = this.removeCapturingGroups(rule.regex);
299
+ }
300
+ if (!rule.splitRegex && typeof rule.token !== 'string')
301
+ // flag will be known only at the very end
302
+ splitterRurles.push(rule);
303
+ }
304
+
305
+ mapping[matchTotal] = i;
306
+ matchTotal += matchcount;
307
+
308
+ ruleRegExps.push(adjustedregex);
309
+
310
+ // makes property access faster
311
+ if (!rule.onMatch) rule.onMatch = null;
312
+ }
313
+
314
+ splitterRurles.forEach(function (rule) {
315
+ rule.splitRegex = this.createSplitterRegexp(rule.regex, flag);
316
+ }, this);
317
+
318
+ this.regExps[key] = new RegExp('(' + ruleRegExps.join(')|(') + ')|($)', flag);
319
+ }
320
+ };
321
+
322
+ (function () {
323
+ this.$setMaxTokenCount = function (m) {
324
+ MAX_TOKEN_COUNT = m | 0;
325
+ };
326
+
327
+ this.$applyToken = function (str) {
328
+ const values = this.splitRegex.exec(str).slice(1);
329
+ const types = this.token.apply(this, values);
330
+
331
+ // required for compatibility with old modes
332
+ if (typeof types === 'string') return [{ type: types, value: str }];
333
+
334
+ const tokens = [];
335
+ for (let i = 0, l = types.length; i < l; i++) {
336
+ if (values[i])
337
+ tokens[tokens.length] = {
338
+ type: types[i],
339
+ value: values[i],
340
+ };
341
+ }
342
+ return tokens;
343
+ };
344
+
345
+ this.$arrayTokens = function (str) {
346
+ if (!str) return [];
347
+ const values = this.splitRegex.exec(str);
348
+ if (!values) return 'text';
349
+ const tokens = [];
350
+ const types = this.tokenArray;
351
+ for (let i = 0, l = types.length; i < l; i++) {
352
+ if (values[i + 1])
353
+ tokens[tokens.length] = {
354
+ type: types[i],
355
+ value: values[i + 1],
356
+ };
357
+ }
358
+ return tokens;
359
+ };
360
+
361
+ this.removeCapturingGroups = function (src) {
362
+ const r = src.replace(/\[(?:\\.|[^\]])*?\]|\\.|\(\?[:=!]|(\()/g, function (x, y) {
363
+ return y ? '(?:' : x;
364
+ });
365
+ return r;
366
+ };
367
+
368
+ this.createSplitterRegexp = function (src, flag) {
369
+ if (src.indexOf('(?=') !== -1) {
370
+ let stack = 0;
371
+ let inChClass = false;
372
+ const lastCapture = {};
373
+ src.replace(/(\\.)|(\((?:\?[=!])?)|(\))|([\[\]])/g, function (m, esc, parenOpen, parenClose, square, index) {
374
+ if (inChClass) {
375
+ inChClass = square !== ']';
376
+ } else if (square) {
377
+ inChClass = true;
378
+ } else if (parenClose) {
379
+ if (stack === lastCapture.stack) {
380
+ lastCapture.end = index + 1;
381
+ lastCapture.stack = -1;
382
+ }
383
+ stack--;
384
+ } else if (parenOpen) {
385
+ stack++;
386
+ if (parenOpen.length !== 1) {
387
+ lastCapture.stack = stack;
388
+ lastCapture.start = index;
389
+ }
390
+ }
391
+ return m;
392
+ });
393
+
394
+ if (lastCapture.end != null && /^\)*$/.test(src.substr(lastCapture.end)))
395
+ src = src.substring(0, lastCapture.start) + src.substr(lastCapture.end);
396
+ }
397
+ return new RegExp(src, (flag || '').replace('g', ''));
398
+ };
399
+
400
+ /**
401
+ * Returns an object containing two properties: `tokens`, which contains all the tokens; and `state`, the current state.
402
+ * @returns {Object}
403
+ **/
404
+ this.getLineTokens = function (line, startState) {
405
+ let stack = [];
406
+ if (startState && typeof startState !== 'string') {
407
+ stack = startState.slice(0);
408
+ startState = stack[0];
409
+ }
410
+
411
+ let currentState = startState || 'start';
412
+ let state = this.states[currentState];
413
+ if (!state) {
414
+ currentState = 'start';
415
+ state = this.states[currentState];
416
+ }
417
+ let mapping = this.matchMappings[currentState];
418
+ let re = this.regExps[currentState];
419
+ re.lastIndex = 0;
420
+
421
+ let match;
422
+ const tokens = [];
423
+ let lastIndex = 0;
424
+
425
+ let token = { type: null, value: '' };
426
+
427
+ /* eslint no-cond-assign: "off" */
428
+ while ((match = re.exec(line))) {
429
+ let type = mapping.defaultToken;
430
+ let rule = null;
431
+ const value = match[0];
432
+ const index = re.lastIndex;
433
+
434
+ if (index - value.length > lastIndex) {
435
+ const skipped = line.substring(lastIndex, index - value.length);
436
+ if (token.type === type) {
437
+ token.value += skipped;
438
+ } else {
439
+ if (token.type) tokens.push(token);
440
+ token = { type: type, value: skipped };
441
+ }
442
+ }
443
+
444
+ for (let i = 0; i < match.length - 2; i++) {
445
+ if (match[i + 1] === undefined) continue;
446
+
447
+ rule = state[mapping[i]];
448
+
449
+ if (rule.onMatch) type = rule.onMatch(value, currentState, stack);
450
+ else type = rule.token;
451
+
452
+ if (rule.next) {
453
+ if (typeof rule.next === 'string') currentState = rule.next;
454
+ else currentState = rule.next(currentState, stack);
455
+
456
+ state = this.states[currentState];
457
+ if (!state) {
458
+ window.console && console.error && console.error(currentState, "doesn't exist");
459
+ currentState = 'start';
460
+ state = this.states[currentState];
461
+ }
462
+ mapping = this.matchMappings[currentState];
463
+ lastIndex = index;
464
+ re = this.regExps[currentState];
465
+ re.lastIndex = index;
466
+ }
467
+ break;
468
+ }
469
+
470
+ if (value) {
471
+ if (typeof type === 'string') {
472
+ if ((!rule || rule.merge !== false) && token.type === type) {
473
+ token.value += value;
474
+ } else {
475
+ if (token.type) tokens.push(token);
476
+ token = { type: type, value: value };
477
+ }
478
+ } else if (type) {
479
+ if (token.type) tokens.push(token);
480
+ token = { type: null, value: '' };
481
+ for (let i = 0; i < type.length; i++) tokens.push(type[i]);
482
+ }
483
+ }
484
+
485
+ if (lastIndex === line.length) break;
486
+
487
+ lastIndex = index;
488
+
489
+ if (tokens.length > MAX_TOKEN_COUNT) {
490
+ // chrome doens't show contents of text nodes with very long text
491
+ while (lastIndex < line.length) {
492
+ if (token.type) tokens.push(token);
493
+ token = {
494
+ value: line.substring(lastIndex, (lastIndex += 2000)),
495
+ type: 'overflow',
496
+ };
497
+ }
498
+ currentState = 'start';
499
+ stack = [];
500
+ break;
501
+ }
502
+ }
503
+
504
+ if (token.type) tokens.push(token);
505
+
506
+ if (stack.length > 1) {
507
+ if (stack[0] !== currentState) stack.unshift(currentState);
508
+ }
509
+ return {
510
+ tokens: tokens,
511
+ state: stack.length ? stack : currentState,
512
+ };
513
+ };
514
+ }.call(Tokenizer.prototype));
515
+
516
+ // Token conversion.
517
+ // See <https://github.com/ajaxorg/ace/wiki/Creating-or-Extending-an-Edit-Mode#common-tokens>
518
+ // This is not an exact match nor the best match that can be made.
519
+ const tokenFromAceToken = {
520
+ empty: null,
521
+ text: null,
522
+
523
+ // Keyword
524
+ keyword: 'keyword',
525
+ control: 'keyword',
526
+ operator: 'operator',
527
+
528
+ // Constants
529
+ constant: 'atom',
530
+ numeric: 'number',
531
+ character: 'atom',
532
+ escape: 'atom',
533
+
534
+ // Variables
535
+ variable: 'variable',
536
+ parameter: 'variable-3',
537
+ // Python's `self` uses that.
538
+ language: 'variable-2',
539
+
540
+ // Comments
541
+ comment: 'comment',
542
+ line: 'comment',
543
+ 'double-slash': 'comment',
544
+ 'double-dash': 'comment',
545
+ 'number-sign': 'comment',
546
+ percentage: 'comment',
547
+ block: 'comment',
548
+ doc: 'comment',
549
+
550
+ // String
551
+ string: 'string',
552
+ quoted: 'string',
553
+ single: 'string',
554
+ double: 'string',
555
+ triple: 'string',
556
+ unquoted: 'string',
557
+ interpolated: 'string',
558
+ regexp: 'string-2',
559
+
560
+ meta: 'keyword',
561
+ literal: 'qualifier',
562
+ support: 'builtin',
563
+
564
+ // Markup
565
+ markup: 'tag',
566
+ underline: 'link',
567
+ link: 'link',
568
+ strong: 'strong',
569
+ heading: 'header',
570
+ em: 'em',
571
+ list: 'variable-2',
572
+ numbered: 'variable-2',
573
+ unnumbered: 'variable-2',
574
+ quote: 'quote',
575
+ // Markdown's raw block uses that.
576
+ raw: 'variable-2',
577
+
578
+ // Invalid
579
+ invalid: 'error',
580
+ illegal: 'invalidchar',
581
+ deprecated: 'error',
582
+ };
583
+
584
+ // Takes a list of Ace tokens, returns a (string) CodeMirror token.
585
+ const cmTokenFromAceTokens = function (tokens) {
586
+ let token = null;
587
+ for (let i = 0; i < tokens.length; i++) {
588
+ // Find the most specific token.
589
+ if (tokenFromAceToken[tokens[i]] !== undefined) {
590
+ token = tokenFromAceToken[tokens[i]];
591
+ }
592
+ }
593
+ return token;
594
+ };
595
+
596
+ // Consume a token from plannedTokens.
597
+ const consumeToken = function (stream, state) {
598
+ const plannedToken = state.plannedTokens.shift();
599
+ if (plannedToken === undefined) {
600
+ return null;
601
+ }
602
+ stream.match(plannedToken.value);
603
+ const tokens = plannedToken.type.split('.');
604
+ return cmTokenFromAceTokens(tokens);
605
+ };
606
+
607
+ const matchToken = function (stream, state) {
608
+ // Anormal start: we already have planned tokens to consume.
609
+ if (state.plannedTokens.length > 0) {
610
+ return consumeToken(stream, state);
611
+ }
612
+
613
+ // Normal start.
614
+ const currentState = state.current;
615
+ const currentLine = stream.match(/.*$/, false)[0];
616
+ const tokenized = tokenizer.getLineTokens(currentLine, currentState);
617
+ // We got a {tokens, state} object.
618
+ // Each token is a {value, type} object.
619
+ state.plannedTokens = tokenized.tokens;
620
+ state.current = tokenized.state;
621
+
622
+ // Consume a token.
623
+ return consumeToken(stream, state);
624
+ };
625
+
626
+ // Initialize all state.
627
+ const aceHighlightRules = new HighlightRules();
628
+ const tokenizer = new Tokenizer(aceHighlightRules.$rules);
629
+
630
+ export const asciidoc = {
631
+ startState: function () {
632
+ return {
633
+ current: 'start',
634
+ // List of {value, type}, with type being an Ace token string.
635
+ plannedTokens: [],
636
+ };
637
+ },
638
+ blankLine: function (state) {
639
+ matchToken('', state);
640
+ },
641
+ token: matchToken,
642
+ };
@@ -52,13 +52,16 @@ export function InputElement(ParentClass) {
52
52
  :host([invalid]) :not(.clipboard) ::slotted(.input),
53
53
  :host([invalid]) :not(.clipboard) .box-icon-left,
54
54
  :host([invalid]) :not(.clipboard) textarea,
55
- :host([invalid]) :not(.clipboard) select {
55
+ :host([invalid]) :not(.clipboard) select,
56
+ :host([invalid]) :not(.clipboard) .input {
56
57
  box-shadow: inset 3px 0 0 var(--gv-input-invalid--bxshc, var(--gv-theme-color-error, #da1a1b));
57
58
  }
58
59
 
59
60
  :host([readonly]) :not(.clipboard) input,
60
61
  :host([readonly]) :not(.clipboard) ::slotted(.input),
61
- :host([readonly]) .textarea :host([readonly]) :not(.clipboard) select {
62
+ :host([readonly]) .textarea,
63
+ :host([readonly]) :not(.clipboard) select,
64
+ :host([readonly]) .input {
62
65
  border-left: 1px solid var(--gv-input--bdc, var(--gv-theme-neutral-color-dark, #d9d9d9));
63
66
  }
64
67
 
@@ -86,7 +89,7 @@ export function InputElement(ParentClass) {
86
89
 
87
90
  setValidity(isInvalid = false, violation = '') {
88
91
  const element = this.getInputElement();
89
- if (element) {
92
+ if (element && element.setCustomValidity) {
90
93
  if (isInvalid) {
91
94
  if (violation == null || violation.trim() === '') {
92
95
  violation = 'field is not valid';
@@ -95,6 +98,7 @@ export function InputElement(ParentClass) {
95
98
  } else {
96
99
  element.setCustomValidity('');
97
100
  }
101
+ element.reportValidity();
98
102
  }
99
103
  this.invalid = isInvalid;
100
104
  this.valid = !this.invalid;
@@ -13,12 +13,7 @@
13
13
  * See the License for the specific language governing permissions and
14
14
  * limitations under the License.
15
15
  */
16
- import { css, LitElement, html } from 'lit';
17
-
18
- import { shapeClipboard, shapeCopied } from '../styles/shapes';
19
- import { dispatchCustomEvent } from '../lib/events';
20
- import { uuid } from '../lib/utils';
21
- import { classMap } from 'lit-html/directives/class-map';
16
+ import { css, html } from 'lit';
22
17
 
23
18
  import { EditorView, basicSetup } from '@codemirror/basic-setup';
24
19
  import { EditorState, Compartment } from '@codemirror/state';
@@ -26,16 +21,16 @@ import { autocompletion } from '@codemirror/autocomplete';
26
21
  import { json } from '@codemirror/lang-json';
27
22
  import { languages } from '@codemirror/language-data';
28
23
  import { placeholder } from '@codemirror/view';
29
- import { InputElement } from '../mixins/input-element';
30
- import { i18n } from '../lib/i18n';
24
+
25
+ import { shapeClipboard } from '../styles/shapes';
26
+ import { dispatchCustomEvent } from '../lib/events';
27
+ import { uuid } from '../lib/utils';
28
+ import { classMap } from 'lit-html/directives/class-map';
29
+ import { GvInput } from '../atoms/gv-input';
31
30
  import { skeleton } from '../styles/skeleton';
32
31
  import { empty } from '../styles/empty';
33
32
  import { input } from '../styles/input';
34
33
 
35
- const languageCompartment = new Compartment();
36
- const readonlyCompartment = new Compartment();
37
- const placeholderCompartment = new Compartment();
38
-
39
34
  /**
40
35
  * Code component
41
36
  *
@@ -59,16 +54,11 @@ const placeholderCompartment = new Compartment();
59
54
  * @attr {Boolean} [autofocus=false] - true to put the focus on the input
60
55
  * @attr {Boolean} [readonly=false] - true if field is readonly mode
61
56
  */
62
- export class GvCode extends InputElement(LitElement) {
57
+ export class GvCode extends GvInput {
63
58
  static get properties() {
64
59
  return {
65
60
  ...super.properties,
66
61
  options: { type: Object },
67
- large: { type: Boolean },
68
- medium: { type: Boolean },
69
- small: { type: Boolean },
70
- clipboard: { type: Boolean },
71
- _clipboardIcon: { type: String },
72
62
  rows: { type: Number },
73
63
  _error: { type: String, attribute: false },
74
64
  };
@@ -82,6 +72,9 @@ export class GvCode extends InputElement(LitElement) {
82
72
  this.autofocus = false;
83
73
  this.clipboard = false;
84
74
  this._clipboardIcon = shapeClipboard;
75
+ this.languageCompartment = new Compartment();
76
+ this.readonlyCompartment = new Compartment();
77
+ this.placeholderCompartment = new Compartment();
85
78
  }
86
79
 
87
80
  render() {
@@ -91,37 +84,32 @@ export class GvCode extends InputElement(LitElement) {
91
84
  large: this.large,
92
85
  medium: this.medium || (!this.large && !this.small),
93
86
  small: this.small,
87
+ copied: this.hasClipboard && this._copied,
94
88
  };
95
89
  const inputClasses = {
96
90
  content: true,
97
- input: this.singleLine,
91
+ code: !this.hasInputStyle,
92
+ input: this.hasInputStyle,
98
93
  };
99
94
 
100
95
  return html`
101
96
  <div class="${classMap(classes)}">
102
97
  ${this.label ? html`<label for="code">${this.label}</label>` : ''}
103
- <div id="${this._id}" class="${classMap(inputClasses)}">
104
- ${this.clipboard
105
- ? html`<gv-button
106
- class="btn-clipboard"
107
- title="${i18n('gv-code.copy')}"
108
- ?outlined="${!this._copied}"
109
- ?primary="${this._copied}"
110
- small
111
- icon="${this._clipboardIcon}"
112
- ></gv-button>`
113
- : ''}
114
- </div>
98
+ <div id="${this._id}" class="${classMap(inputClasses)}">${this.renderIcon()}</div>
115
99
  </div>
116
100
  ${this.description != null ? html`<div class="description" .innerHTML="${this.description}"></div>` : ''}
117
101
  `;
118
102
  }
119
103
 
104
+ bindInputEvents() {
105
+ dispatchCustomEvent(this, 'ready', { currentTarget: this });
106
+ }
107
+
120
108
  _onChange() {
121
109
  dispatchCustomEvent(this, 'input', this.value);
122
110
  }
123
111
 
124
- get singleLine() {
112
+ get hasInputStyle() {
125
113
  return this.rows === 1;
126
114
  }
127
115
 
@@ -131,34 +119,32 @@ export class GvCode extends InputElement(LitElement) {
131
119
  }
132
120
 
133
121
  findBestAutocompleteHandler(completionContext) {
134
- return this.defaultCompletionHandler;
122
+ return { handler: this.defaultCompletionHandler, match: true };
135
123
  }
136
124
 
137
125
  get defaultCompletionHandler() {
138
126
  return {
139
- handler: {
140
- run(completionContext) {
141
- const language = completionContext.state.languageDataAt('autocomplete', completionContext.pos);
142
- if (language.length > 0) {
143
- return language[0](completionContext);
144
- }
145
- return { from: completionContext.pos, options: [] };
146
- },
127
+ run(completionContext) {
128
+ const language = completionContext.state.languageDataAt('autocomplete', completionContext.pos);
129
+ if (language.length > 0) {
130
+ return language[0](completionContext);
131
+ }
132
+ return { from: completionContext.pos, options: [] };
147
133
  },
148
- match: true,
149
134
  };
150
135
  }
151
136
 
152
137
  _getExtensions() {
153
138
  return [
154
139
  basicSetup,
155
- languageCompartment.of(json()),
156
- placeholderCompartment.of(placeholder(this.placeholder || '')),
157
- EditorState.transactionFilter.of((tr) => (this.singleLine && tr.newDoc.lines > 1 ? [] : tr)),
158
- readonlyCompartment.of(EditorView.editable.of(!this.readonly)),
159
- EditorView.updateListener.of((update) => {
160
- if (update.view.contentDOM.innerText) {
161
- this.value = update.view.contentDOM.innerText;
140
+ GvCode.codemirrorTheme,
141
+ this.languageCompartment.of(json()),
142
+ this.placeholderCompartment.of(placeholder(this.placeholder || '')),
143
+ EditorState.transactionFilter.of((tr) => (this.hasInputStyle && tr.newDoc.lines > 1 ? [] : tr)),
144
+ this.readonlyCompartment.of(EditorView.editable.of(!this.readonly && !this.disabled)),
145
+ EditorView.updateListener.of((viewUpdate) => {
146
+ if (viewUpdate.docChanged) {
147
+ this.value = this._editorView.state.doc.toString();
162
148
  }
163
149
  }),
164
150
  autocompletion({
@@ -173,9 +159,15 @@ export class GvCode extends InputElement(LitElement) {
173
159
  return [];
174
160
  }
175
161
 
162
+ getInputElement() {
163
+ return this.shadowRoot.querySelector(`[id=${this._id}]`);
164
+ }
165
+
176
166
  firstUpdated() {
177
167
  super.firstUpdated();
178
- const parent = this.shadowRoot.querySelector(`[id=${this._id}]`);
168
+
169
+ const parent = this.getInputElement();
170
+
179
171
  this._editorState = EditorState.create({
180
172
  doc: this.value,
181
173
  extensions: this._getExtensions(),
@@ -185,35 +177,20 @@ export class GvCode extends InputElement(LitElement) {
185
177
  parent,
186
178
  state: this._editorState,
187
179
  });
188
- parent.appendChild(this._editorView.dom);
189
180
 
190
- if (this.clipboard) {
191
- import('clipboard-copy').then((mod) => {
192
- const copy = mod.default;
193
- this.shadowRoot.querySelector('.btn-clipboard').addEventListener('gv-button:click', () => {
194
- copy(this.value);
195
- this._copied = true;
196
- this._clipboardIcon = shapeCopied;
197
- dispatchCustomEvent(this, 'clipboard-copy');
198
- setTimeout(() => {
199
- this._copied = false;
200
- this._clipboardIcon = shapeClipboard;
201
- }, 1000);
202
- });
203
- });
204
- }
205
- dispatchCustomEvent(this, 'ready');
181
+ parent.appendChild(this._editorView.dom);
206
182
  }
207
183
 
208
184
  async updated(properties) {
185
+ super.updated(properties);
209
186
  if (properties.has('placeholder')) {
210
187
  this._reflectPlaceholder();
211
188
  }
212
189
  if (properties.has('value')) {
213
190
  this._reflectValue();
214
191
  }
215
- if (properties.has('readonly')) {
216
- this._reflectReadonly();
192
+ if (properties.has('readonly') || properties.has('disabled')) {
193
+ this._reflectReadonlyDisabled();
217
194
  }
218
195
  if (properties.has('options') && this.options) {
219
196
  await this._reflectOptions();
@@ -222,7 +199,7 @@ export class GvCode extends InputElement(LitElement) {
222
199
 
223
200
  _reflectPlaceholder() {
224
201
  this._editorView.dispatch({
225
- effects: placeholderCompartment.reconfigure(placeholder(this.placeholder)),
202
+ effects: this.placeholderCompartment.reconfigure(placeholder(this.placeholder)),
226
203
  });
227
204
  }
228
205
 
@@ -237,38 +214,68 @@ export class GvCode extends InputElement(LitElement) {
237
214
  this._editorState = transaction.state;
238
215
  }
239
216
 
240
- _reflectReadonly() {
217
+ _reflectReadonlyDisabled() {
241
218
  this._editorView.dispatch({
242
- effects: readonlyCompartment.reconfigure(EditorView.editable.of(!this.readonly)),
219
+ effects: this.readonlyCompartment.reconfigure(EditorView.editable.of(!this.readonly && !this.disabled)),
243
220
  });
244
221
  }
245
222
 
246
- async _reflectOptions() {
247
- if (this.options.mode) {
248
- const language = languages.find((languageDescription) => {
249
- return (
250
- languageDescription.name.toUpperCase() === this.options.mode.toUpperCase() ||
251
- languageDescription.alias.includes(this.options.mode)
252
- );
253
- });
254
- if (language != null) {
255
- if (language.support == null) {
256
- await language.load();
257
- }
258
- this._editorView.dispatch({
259
- effects: languageCompartment.reconfigure(language.support.extension),
260
- });
223
+ static async findLanguage(mode) {
224
+ if (mode) {
225
+ const modeOnly = mode.split('/').pop();
226
+ if (modeOnly === 'asciidoc') {
227
+ const [{ asciidoc }, { StreamLanguage }] = await Promise.all([import('../lib/asciidoc-lang'), import('@codemirror/stream-parser')]);
228
+ return {
229
+ name: 'asciidoc',
230
+ support: {
231
+ extension: StreamLanguage.define(asciidoc),
232
+ },
233
+ };
261
234
  } else {
262
- console.warn(
263
- `Cannot find language ${this.options.mode}, please use language supported by CodeMirror 6`,
264
- languages.map((l) => l.name),
265
- );
235
+ const language = languages.find((languageDescription) => {
236
+ return languageDescription.name.toUpperCase() === modeOnly.toUpperCase() || languageDescription.alias.includes(modeOnly);
237
+ });
238
+ if (language == null) {
239
+ console.warn(
240
+ `Cannot find language ${mode}, please use language supported by CodeMirror 6`,
241
+ languages.map((l) => l.name),
242
+ );
243
+ }
244
+ return language;
266
245
  }
267
246
  }
247
+ return null;
248
+ }
249
+
250
+ async _reflectOptions() {
251
+ const language = await GvCode.findLanguage(this.options.mode);
252
+ if (language != null) {
253
+ if (language.support == null) {
254
+ await language.load();
255
+ }
256
+ this._editorView.dispatch({
257
+ effects: this.languageCompartment.reconfigure(language.support.extension),
258
+ });
259
+ }
260
+ }
261
+
262
+ static get codemirrorTheme() {
263
+ return EditorView.theme({
264
+ '&.cm-editor.cm-focused': {
265
+ outline: 'none',
266
+ },
267
+ '.cm-gutters': {
268
+ backgroundColor: 'var(--gv-input-icon--bgc, var(--gv-theme-neutral-color, #f5f5f5))',
269
+ color: 'var(--gv-theme-font-color-dark, #262626)',
270
+ borderLeft: '5px solid',
271
+ borderColor: 'var(--gv-input--bdc, var(--gv-theme-neutral-color-dark, #d9d9d9))',
272
+ },
273
+ });
268
274
  }
269
275
 
270
276
  static get styles() {
271
277
  return [
278
+ ...super.styles,
272
279
  skeleton,
273
280
  empty,
274
281
  input,
@@ -282,16 +289,25 @@ export class GvCode extends InputElement(LitElement) {
282
289
 
283
290
  .content {
284
291
  position: relative;
292
+ border: var(--gv-input--bdw, 1px) var(--gv-input--bds, solid) var(--gv-input--bdc, var(--gv-theme-neutral-color-dark, #d9d9d9));
293
+ box-sizing: border-box;
294
+ border-radius: 4px;
295
+ }
296
+
297
+ .btn_copy {
298
+ }
299
+
300
+ .box-icon {
301
+ bottom: -1px;
302
+ right: -1px;
303
+ z-index: 1;
285
304
  }
286
305
 
287
- .btn-clipboard {
288
- position: absolute;
289
- right: 0;
290
- top: 0;
291
- z-index: 10;
306
+ .code .box-icon {
307
+ border-radius: 3px;
292
308
  }
293
309
 
294
- /** Override Codemirror style */
310
+ /** Override Codemirror theme */
295
311
  .input .cm-gutters {
296
312
  display: none;
297
313
  }
@@ -300,7 +316,8 @@ export class GvCode extends InputElement(LitElement) {
300
316
  overflow: hidden;
301
317
  }
302
318
 
303
- .input .cm-activeLine {
319
+ .input .cm-activeLine,
320
+ :host([readonly]) .cm-activeLine {
304
321
  background-color: transparent;
305
322
  }
306
323
 
@@ -308,8 +325,8 @@ export class GvCode extends InputElement(LitElement) {
308
325
  padding: 0;
309
326
  }
310
327
 
311
- .ͼ1.cm-editor.cm-focused {
312
- outline: none;
328
+ :host([invalid]) .cm-gutters {
329
+ border-color: var(--gv-theme-color-error, #da1a1b);
313
330
  }
314
331
  `,
315
332
  ];
@@ -51,7 +51,7 @@ export class GvExpressionLanguage extends GvCode {
51
51
 
52
52
  firstUpdated() {
53
53
  super.firstUpdated();
54
- dispatchCustomEvent(this, 'ready');
54
+ dispatchCustomEvent(this, 'ready', { currentTarget: this });
55
55
  }
56
56
 
57
57
  getExtensions() {
@@ -78,7 +78,7 @@ export class GvExpressionLanguage extends GvCode {
78
78
  }
79
79
 
80
80
  buildMethods(type) {
81
- const modelType = this._getModelType(type);
81
+ const modelType = this.getModelType(type);
82
82
  return modelType.methods.map(({ name, params = [], returnType }) => {
83
83
  const command = `${name}()`;
84
84
  const displayParams = params.map((p) => `${p.type} ${p.name}`);
@@ -134,7 +134,6 @@ export class GvExpressionLanguage extends GvCode {
134
134
  if (type) {
135
135
  const lowerType = type.toLowerCase();
136
136
  if (lowerType === 'string') {
137
- // class, constant, enum, function, interface, keyword, method, namespace, property, text, type, and variable.
138
137
  return 'text';
139
138
  } else if (lowerType === 'httpheaders' || lowerType === 'multivaluemap') {
140
139
  return 'type';
@@ -159,7 +158,6 @@ export class GvExpressionLanguage extends GvCode {
159
158
  .filter((command) => !command.startsWith('_') && command.startsWith(prefix))
160
159
  .map((command) => {
161
160
  return {
162
- // class, constant, enum, function, interface, keyword, method, namespace, property, text, type, and variable.
163
161
  type: 'variable',
164
162
  command,
165
163
  apply: command,
@@ -176,11 +174,10 @@ export class GvExpressionLanguage extends GvCode {
176
174
  const tokens = match.text.split('.');
177
175
  const key = tokens[0].replaceAll('{#', '');
178
176
  const prefix = tokens[1];
179
- const candidate = this.grammar[key][prefix];
177
+ let candidate = this.grammar[key][prefix];
180
178
  let options = [];
181
179
  let from = completionContext.pos;
182
180
  if (candidate) {
183
- // const modelType = this._getModelType(candidate._type);
184
181
  if (this.isMap(candidate._type)) {
185
182
  options = this.getEnum(candidate._type).map((value) => {
186
183
  const type = this.convertType(candidate._type);
@@ -195,7 +192,7 @@ export class GvExpressionLanguage extends GvCode {
195
192
  }
196
193
  } else {
197
194
  from -= prefix.length;
198
- const candidate = this.grammar[key];
195
+ candidate = this.grammar[key];
199
196
  if (candidate._type) {
200
197
  options = this.buildMethods(candidate._type);
201
198
  } else {
@@ -224,16 +221,16 @@ export class GvExpressionLanguage extends GvCode {
224
221
  let options = [];
225
222
  let from = completionContext.pos;
226
223
  if (candidate) {
227
- if (this._isMap(candidate._type)) {
228
- options = this._getEnum(candidate._type)
224
+ if (this.isMap(candidate._type)) {
225
+ options = this.getEnum(candidate._type)
229
226
  .filter((command) => !command.startsWith('_') && command.startsWith(prefix))
230
227
  .map((label) => {
231
- const type = this._convertType(candidate._type);
228
+ const type = this.convertType(candidate._type);
232
229
  return {
233
230
  type,
234
231
  command: `['${label}'][0]`,
235
232
  apply(view, completion, _from, to) {
236
- const from = _from - prefix.length - 1;
233
+ from = _from - prefix.length - 1;
237
234
  view.dispatch({
238
235
  changes: { from, to, insert: completion.command },
239
236
  selection: { anchor: from + completion.command.length },
@@ -246,14 +243,14 @@ export class GvExpressionLanguage extends GvCode {
246
243
  });
247
244
  } else {
248
245
  if (candidate._type) {
249
- options = this._buildMethods(candidate._type);
246
+ options = this.buildMethods(candidate._type);
250
247
  } else {
251
248
  from -= prefix.length;
252
249
  options = Object.keys(candidate)
253
250
  .filter((command) => command.startsWith(prefix))
254
251
  .map((command) => {
255
252
  return {
256
- type: this._convertType(candidate[command]._type),
253
+ type: this.convertType(candidate[command]._type),
257
254
  command,
258
255
  apply: command,
259
256
  label: command,
@@ -122,6 +122,7 @@ export const input = css`
122
122
  ::slotted(.input),
123
123
  .input {
124
124
  border: var(--gv-input--bdw, 1px) var(--gv-input--bds, solid) var(--gv-input--bdc, var(--gv-theme-neutral-color-dark, #d9d9d9));
125
+ transition: border 10ms ease-in-out;
125
126
  box-sizing: border-box;
126
127
  border-radius: 4px;
127
128
  font-style: normal;
@@ -232,6 +233,7 @@ export const input = css`
232
233
  }
233
234
 
234
235
  :host([disabled]) input,
236
+ :host([disabled]) .input,
235
237
  :host([disabled]) ::slotted(input) {
236
238
  cursor: default;
237
239
  opacity: 0.5;