@aquera/nile-elements 0.1.1 → 0.1.2

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/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "description": "Webcomponent nile-elements following open-wc recommendations",
4
4
  "license": "MIT",
5
5
  "author": "nile-elements",
6
- "version": "0.1.1",
6
+ "version": "0.1.2",
7
7
  "main": "dist/src/index.js",
8
8
  "type": "module",
9
9
  "module": "dist/src/index.js",
@@ -117,6 +117,7 @@
117
117
  "@codemirror/lang-javascript": "6.2.1",
118
118
  "@codemirror/lang-sql": "6.7.0",
119
119
  "@codemirror/lang-json": "^6.0.1",
120
+ "@codemirror/lang-html":"6.4.9",
120
121
  "codemirror": "6.0.1",
121
122
  "chalk": "5.3.0",
122
123
  "figlet": "1.7.0",
@@ -5,8 +5,8 @@
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  */
7
7
 
8
- import {LitElement, html, property, CSSResultArray, TemplateResult} from 'lit';
9
- import { customElement } from 'lit/decorators.js';
8
+ import {LitElement, html, CSSResultArray, TemplateResult} from 'lit';
9
+ import { customElement, property} from 'lit/decorators.js';
10
10
  import {styles} from './nile-{{name}}.css';
11
11
  import NileElement from '../internal/nile-element';
12
12
 
@@ -6,7 +6,6 @@
6
6
  */
7
7
 
8
8
  import {
9
- LitElement,
10
9
  html,
11
10
  CSSResultArray,
12
11
  TemplateResult,
@@ -20,16 +19,17 @@ import { ViewUpdate, placeholder } from '@codemirror/view';
20
19
  import {
21
20
  Compartment,
22
21
  EditorState,
22
+ Extension
23
23
  } from '@codemirror/state';
24
24
 
25
25
  import { lineNumbers } from '@codemirror/view';
26
26
  import {
27
27
  javascript,
28
28
  javascriptLanguage,
29
- scopeCompletionSource,
30
29
  } from '@codemirror/lang-javascript';
31
30
  import { sql } from '@codemirror/lang-sql';
32
31
  import { json } from '@codemirror/lang-json';
32
+ import { html as htmlLang } from '@codemirror/lang-html';
33
33
  import { autocompletion,CompletionContext,CompletionResult } from '@codemirror/autocomplete';
34
34
  import NileElement from '../internal/nile-element';
35
35
  import { basicSetup } from './extensionSetup';
@@ -58,7 +58,9 @@ export class NileCodeEditor extends NileElement {
58
58
 
59
59
  @property({ type: Object, reflect: true , attribute: true }) customAutoCompletions: object | any = {};
60
60
 
61
- @property({ type: String, reflect: true , attribute: true}) language: 'javascript' | 'sql' | 'json' = 'javascript';
61
+ @property({ type: Array, reflect: true , attribute: true }) customCompletionsPaths: string[] = [];
62
+
63
+ @property({ type: String, reflect: true , attribute: true}) language: 'javascript' | 'sql' | 'json' | 'html' = 'javascript';
62
64
 
63
65
  @property({ type: String, reflect: true , attribute: 'error-message' }) errorMessage: string = '';
64
66
 
@@ -157,7 +159,7 @@ export class NileCodeEditor extends NileElement {
157
159
  ]
158
160
  })
159
161
  }
160
- if(changedProperties.has('customAutoCompletions') || changedProperties.has('suggestionBracketSupport') ){
162
+ if(changedProperties.has('customAutoCompletions') || changedProperties.has('customCompletionsPaths')){
161
163
  this.view.dispatch({
162
164
  effects: [
163
165
  this.customCompletionComp.reconfigure(javascriptLanguage.data.of({
@@ -225,7 +227,7 @@ export class NileCodeEditor extends NileElement {
225
227
  }));
226
228
 
227
229
  this.viewState = EditorState.create({
228
- doc: !this.multiline ? this.convertToSingleLine(this.value) : this.value,
230
+ doc: !this.multiline ? convertToSingleLine(this.value) : this.value,
229
231
  extensions: [
230
232
  basicSetup({
231
233
  highlightActiveLine: false,
@@ -253,22 +255,89 @@ export class NileCodeEditor extends NileElement {
253
255
  return this.viewState
254
256
  }
255
257
 
256
- singleLineMultiLineToggle() {
257
- this.view.dispatch({
258
- changes: {
259
- from: 0,
260
- to: this.view.state.doc.length,
261
- insert: !this.multiline
262
- ? this.convertToSingleLine(this.value)
263
- : this.value,
264
- },
265
- });
258
+ customAutocomplete = (context: CompletionContext): CompletionResult | null => {
259
+ // Getting the valid last line, last text from the code editor
260
+ const text = context.state.doc.sliceString(0, context.pos);
261
+ const lastWord = text.split('\n').at(-1)?.split(' ').at(-1) || '';
262
+ const [textBeforeCursor, baseTextAfterSeperation] = splitStringAtLastSeparator(lastWord);
263
+
264
+ return this.getNestedSuggestions(context, textBeforeCursor, baseTextAfterSeperation)
265
+ || this.getTopLevelSuggestions(context, textBeforeCursor);
266
+ };
267
+
268
+ getNestedSuggestions(context: CompletionContext, textBeforeCursor: string, baseTextAfterSeperation: string) {
269
+ // Return early if not a valid path or not ending with . or [
270
+ if (!isValidPath(textBeforeCursor) || !['.', '['].includes(textBeforeCursor.at(-1)!)) {
271
+ return null;
272
+ }
273
+
274
+ const path = parsePath(textBeforeCursor);
275
+ if (!path) return null;
276
+
277
+ const textAfterSeperation = baseTextAfterSeperation.replace(/["'\[]/g, '');
278
+ const isInString = textAfterSeperation !== baseTextAfterSeperation;
279
+ const isBracket = textBeforeCursor.at(-1) === '[';
280
+
281
+ // Return null if we're in a string after a dot
282
+ if (textBeforeCursor.at(-1) === '.' && isInString) return null;
283
+
284
+ // Get nested properties and filter by text after separation if it exists
285
+ let resolved = resolveNestedProperties(this.customAutoCompletions, path);
286
+ if (!resolved || typeof resolved !== 'object') return null;
287
+
288
+ if (textAfterSeperation) {
289
+ resolved = Object.fromEntries(
290
+ Object.entries(resolved).filter(([key]) =>
291
+ key.toLowerCase().startsWith(textAfterSeperation.toLowerCase())
292
+ )
293
+ );
294
+ }
295
+
296
+ return {
297
+ from: context.pos - textAfterSeperation.length,
298
+ options: Object.keys(resolved).map(key => ({
299
+ label: key,
300
+ type: 'property',
301
+ info: `Key of ${path[path.length - 1]}`,
302
+ apply: !this.allowVariableInCustomSuggestion && (isBracket && !isInString)
303
+ ? `'${key}'`
304
+ : key,
305
+ boost: 999
306
+ }))
307
+ };
266
308
  }
267
309
 
268
- convertToSingleLine(code: any) {
269
- if (!code) return '';
270
- // Remove line breaks and unnecessary whitespace
271
- return code.replace(/\s+/g, ' ').trim();
310
+ getTopLevelSuggestions(context: CompletionContext,textBeforeCursor:string){
311
+ const baseMatch: any = textBeforeCursor.match(/([a-zA-Z_$][\w$]*)$/);
312
+ if (!baseMatch) return null;
313
+
314
+ const optionsList = Object.keys(this.customAutoCompletions).filter(key =>
315
+ Object.keys(this.customAutoCompletions[key]).length &&
316
+ key.toLowerCase().startsWith(textBeforeCursor.toLowerCase())
317
+ );
318
+
319
+ const options=optionsList.map((key) => ({
320
+ label: key,
321
+ type: 'property',
322
+ apply: key,
323
+ boost: 999
324
+ }))
325
+ if(this.customCompletionsPaths.length){
326
+ this.customCompletionsPaths
327
+ .filter(path=>path.toLocaleLowerCase().includes(textBeforeCursor.toLocaleLowerCase()))
328
+ .map(path=>{
329
+ options.push({
330
+ label: ''+path,
331
+ type: 'property',
332
+ apply: ''+path,
333
+ boost: 998
334
+ })
335
+ })
336
+ }
337
+ return {
338
+ from: context.pos - baseMatch[1].length,
339
+ options: options
340
+ }
272
341
  }
273
342
 
274
343
  emitAfterTimeout(value:any){
@@ -283,18 +352,32 @@ export class NileCodeEditor extends NileElement {
283
352
  });
284
353
  this.view.dispatch(transaction);
285
354
  }
286
-
355
+
356
+ singleLineMultiLineToggle() {
357
+ this.view.dispatch({
358
+ changes: {
359
+ from: 0,
360
+ to: this.view.state.doc.length,
361
+ insert: !this.multiline
362
+ ? convertToSingleLine(this.value)
363
+ : this.value,
364
+ },
365
+ });
366
+ }
367
+
287
368
  //EXTENSION CONFIGURATIONS
288
369
  getLineNumbersExension() {
289
370
  return (!this.multiline && this.lineNumbers) || (this.multiline && this.lineNumbersMultiline) ? lineNumbers() : [];
290
371
  }
291
372
 
292
- getLanguageExtension(){
373
+ getLanguageExtension():Extension{
293
374
  switch(this.language){
294
375
  case 'sql':
295
376
  return sql();
296
377
  case 'json':
297
378
  return json();
379
+ case 'html':
380
+ return htmlLang();
298
381
  default:
299
382
  return javascript();
300
383
  }
@@ -319,108 +402,6 @@ export class NileCodeEditor extends NileElement {
319
402
  tr.newDoc.lines > 1 ? [] : tr
320
403
  );
321
404
  }
322
-
323
- customAutocomplete = (context: CompletionContext): CompletionResult | null => {
324
- // Getting the valid last line, last text from the code editor
325
- let text = context.state.doc.sliceString(0, context.pos);
326
- const [textBeforeCursor, baseTextAfterSeperation] = this.splitStringAtLastSeparator(text.split('\n').at(-1)?.split(' ').at(-1) + '')
327
- const textAfterSeperation = baseTextAfterSeperation.replace(/["'\[]/g, '')
328
-
329
- const isInString = textAfterSeperation != baseTextAfterSeperation;
330
- const isBracket = textBeforeCursor.at(-1) == '[';
331
- const isDot = textBeforeCursor.at(-1) == '.';
332
-
333
- if (!this.isValidPath(textBeforeCursor)) return { from: context.pos, options: [] };
334
- if (['.', '['].includes(textBeforeCursor[textBeforeCursor.length - 1])) {
335
- // Parse the path for dot or bracket notation
336
- const path = this.parsePath(textBeforeCursor);
337
- if (path) {
338
- if (isDot && isInString) return null;
339
- let resolved = this.resolveNestedProperties(this.customAutoCompletions, path);
340
- if (textAfterSeperation) {
341
- const obj: any = {}
342
- Object.keys(resolved).forEach((key) => {
343
- if (key.toLowerCase().startsWith(textAfterSeperation.toLowerCase())) {
344
- obj[key] = resolved[key]
345
- }
346
- })
347
- resolved = obj
348
- }
349
- // If resolved is an object, provide its keys as suggestions
350
- if (resolved && typeof resolved === 'object') {
351
- return {
352
- from: context.pos - textAfterSeperation.length,
353
- options: Object.keys(resolved).map((key) => ({
354
- label: key,
355
- type: 'property',
356
- info: `Key of ${path[path.length - 1]}`,
357
- apply: !this.allowVariableInCustomSuggestion && (isBracket && !isInString) ? "\'" + key + "\'" : key,
358
- boost: 999
359
- })),
360
- };
361
- }
362
- }
363
- }
364
-
365
- // Match for top-level object suggestions, e.g., "a"
366
- const baseMatch: any = textBeforeCursor.match(/([a-zA-Z_$][\w$]*)$/);
367
- if (baseMatch) {
368
- const optionsList=Object.keys(this.customAutoCompletions).filter(key=>key.toLowerCase().startsWith(textBeforeCursor.toLowerCase()));
369
- return {
370
- from: context.pos - baseMatch[1].length,
371
- options: optionsList.map((key) => ({
372
- label: key,
373
- type: 'property',
374
- apply: key,
375
- boost: 999
376
- }))
377
- }
378
- }
379
- // Default to an empty list if no match
380
- return null;
381
- };
382
-
383
- resolveNestedProperties = (obj:any, keys:any[]) => {
384
- return keys.reduce((acc, key) => {
385
- if (acc && typeof acc === 'object') {
386
- return acc[key];
387
- }
388
- return null;
389
- }, obj);
390
- };
391
-
392
- parsePath(text: string) {
393
- const regex = /([a-zA-Z_$][\w$]*)(\[(?:[^\]]+)\]|\.[a-zA-Z_$][\w$]*)*/g;
394
- const matches = [...text.matchAll(regex)];
395
- if (matches.length > 0) {
396
- const base = matches[0][1]; // The base object name
397
- const keys = [base];
398
- // Extract keys from dot or bracket notation
399
- const pathMatches = text.match(/\[(.*?)\]|\.(\w+)/g) || [];
400
- for (const match of pathMatches) {
401
- if (match.startsWith('[')) {
402
- keys.push(match.slice(1, -1).replace(/['"]/g, '')); // Remove brackets and quotes
403
- } else if (match.startsWith('.')) {
404
- keys.push(match.slice(1));
405
- }
406
- }
407
- return keys;
408
- }
409
- return null;
410
- };
411
-
412
- isValidPath(path: string) {
413
- // Regex to validate the format of the string
414
- const regex = /^([a-zA-Z_$][\w$]*)(\.[a-zA-Z_$][\w$]*|\[\s*(['"]?[a-zA-Z0-9_$]*['"]?)\s*\])*([\.\[])?$/;
415
- // Test the string against the regex
416
- return regex.test(path);
417
- }
418
-
419
- splitStringAtLastSeparator(input:string) {
420
- const lastSeparatorIndex = Math.max(input.lastIndexOf('.'), input.lastIndexOf('['));
421
- if (lastSeparatorIndex === -1) return [input, ''];
422
- return [input.slice(0, lastSeparatorIndex + 1), input.slice(lastSeparatorIndex + 1)];
423
- }
424
405
  /* #endregion */
425
406
  }
426
407
 
@@ -431,3 +412,51 @@ declare global {
431
412
  'nile-code-editor': NileCodeEditor;
432
413
  }
433
414
  }
415
+
416
+ function parsePath(text: string) {
417
+ const regex = /([a-zA-Z_$][\w$]*)(\[(?:[^\]]+)\]|\.[a-zA-Z_$][\w$]*)*/g;
418
+ const matches = [...text.matchAll(regex)];
419
+ if (matches.length > 0) {
420
+ const base = matches[0][1]; // The base object name
421
+ const keys = [base];
422
+ // Extract keys from dot or bracket notation
423
+ const pathMatches = text.match(/\[(.*?)\]|\.(\w+)/g) || [];
424
+ for (const match of pathMatches) {
425
+ if (match.startsWith('[')) {
426
+ keys.push(match.slice(1, -1).replace(/['"]/g, '')); // Remove brackets and quotes
427
+ } else if (match.startsWith('.')) {
428
+ keys.push(match.slice(1));
429
+ }
430
+ }
431
+ return keys;
432
+ }
433
+ return null;
434
+ };
435
+
436
+ function splitStringAtLastSeparator(input:string) {
437
+ const lastSeparatorIndex = Math.max(input.lastIndexOf('.'), input.lastIndexOf('['));
438
+ if (lastSeparatorIndex === -1) return [input, ''];
439
+ return [input.slice(0, lastSeparatorIndex + 1), input.slice(lastSeparatorIndex + 1)];
440
+ }
441
+
442
+ function resolveNestedProperties (obj:any, keys:any[]){
443
+ return keys.reduce((acc, key) => {
444
+ if (acc && typeof acc === 'object') {
445
+ return acc[key];
446
+ }
447
+ return null;
448
+ }, obj);
449
+ };
450
+
451
+ function isValidPath(path: string) {
452
+ // Regex to validate the format of the string
453
+ const regex = /^([a-zA-Z_$][\w$]*)(\.[a-zA-Z_$][\w$]*|\[\s*(['"]?[a-zA-Z0-9_$]*['"]?)\s*\])*([\.\[])?$/;
454
+ // Test the string against the regex
455
+ return regex.test(path);
456
+ }
457
+
458
+ function convertToSingleLine(code: string) {
459
+ if (!code) return '';
460
+ // Remove line breaks and unnecessary whitespace
461
+ return code.replace(/\s+/g, ' ').trim();
462
+ }
@@ -726,7 +726,7 @@
726
726
  },
727
727
  {
728
728
  "name": "nile-code-editor",
729
- "description": "Nile icon component.\n\nEvents:\n\n * `nile-focus` {`Event`} - \n\n * `nile-blur` {`Event`} - \n\nAttributes:\n\n * `value` {`string`} - \n\n * `expandIcon` {`string`} - \n\n * `placeholder` {`string`} - \n\n * `customAutoCompletions` - \n\n * `language` {`\"javascript\" | \"sql\" | \"json\"`} - \n\n * `error-message` {`string`} - \n\n * `error` {`boolean`} - \n\n * `noborder` {`boolean`} - \n\n * `multiline` {`boolean`} - \n\n * `allowVariableInCustomSuggestion` {`boolean`} - \n\n * `lineNumbers` {`boolean`} - \n\n * `lineNumbersMultiline` {`boolean`} - \n\n * `hasScroller` {`boolean`} - \n\n * `expandable` {`boolean`} - \n\n * `readonly` {`boolean`} - \n\n * `debounce` {`boolean`} - \n\nProperties:\n\n * `codeEditor` {`HTMLInputElement`} - \n\n * `value` {`string`} - \n\n * `expandIcon` {`string`} - \n\n * `placeholder` {`string`} - \n\n * `customAutoCompletions` - \n\n * `language` {`\"javascript\" | \"sql\" | \"json\"`} - \n\n * `errorMessage` {`string`} - \n\n * `error` {`boolean`} - \n\n * `noborder` {`boolean`} - \n\n * `multiline` {`boolean`} - \n\n * `allowVariableInCustomSuggestion` {`boolean`} - \n\n * `lineNumbers` {`boolean`} - \n\n * `lineNumbersMultiline` {`boolean`} - \n\n * `hasScroller` {`boolean`} - \n\n * `expandable` {`boolean`} - \n\n * `readonly` {`boolean`} - \n\n * `debounce` {`boolean`} - \n\n * `view` - \n\n * `viewState` - \n\n * `timeOut` - \n\n * `lineNumbersComp` - \n\n * `restrictSingleLineComp` - \n\n * `readOnlyComp` - \n\n * `customCompletionComp` - \n\n * `placeholderComp` - \n\n * `insertBetweenCode` - \n\n * `customAutocomplete` - \n\n * `resolveNestedProperties` - \n\n * `BUBBLES` {`boolean`} - \n\n * `COMPOSED` {`boolean`} - \n\n * `CANCELABLE` {`boolean`} - ",
729
+ "description": "Nile icon component.\n\nEvents:\n\n * `nile-focus` {`Event`} - \n\n * `nile-blur` {`Event`} - \n\nAttributes:\n\n * `value` {`string`} - \n\n * `expandIcon` {`string`} - \n\n * `placeholder` {`string`} - \n\n * `customAutoCompletions` - \n\n * `customCompletionsPaths` {`string[]`} - \n\n * `language` {`\"html\" | \"javascript\" | \"sql\" | \"json\"`} - \n\n * `error-message` {`string`} - \n\n * `error` {`boolean`} - \n\n * `noborder` {`boolean`} - \n\n * `multiline` {`boolean`} - \n\n * `allowVariableInCustomSuggestion` {`boolean`} - \n\n * `lineNumbers` {`boolean`} - \n\n * `lineNumbersMultiline` {`boolean`} - \n\n * `hasScroller` {`boolean`} - \n\n * `expandable` {`boolean`} - \n\n * `readonly` {`boolean`} - \n\n * `debounce` {`boolean`} - \n\nProperties:\n\n * `codeEditor` {`HTMLInputElement`} - \n\n * `value` {`string`} - \n\n * `expandIcon` {`string`} - \n\n * `placeholder` {`string`} - \n\n * `customAutoCompletions` - \n\n * `customCompletionsPaths` {`string[]`} - \n\n * `language` {`\"html\" | \"javascript\" | \"sql\" | \"json\"`} - \n\n * `errorMessage` {`string`} - \n\n * `error` {`boolean`} - \n\n * `noborder` {`boolean`} - \n\n * `multiline` {`boolean`} - \n\n * `allowVariableInCustomSuggestion` {`boolean`} - \n\n * `lineNumbers` {`boolean`} - \n\n * `lineNumbersMultiline` {`boolean`} - \n\n * `hasScroller` {`boolean`} - \n\n * `expandable` {`boolean`} - \n\n * `readonly` {`boolean`} - \n\n * `debounce` {`boolean`} - \n\n * `view` - \n\n * `viewState` - \n\n * `timeOut` - \n\n * `lineNumbersComp` - \n\n * `restrictSingleLineComp` - \n\n * `readOnlyComp` - \n\n * `customCompletionComp` - \n\n * `placeholderComp` - \n\n * `customAutocomplete` - \n\n * `insertBetweenCode` - \n\n * `BUBBLES` {`boolean`} - \n\n * `COMPOSED` {`boolean`} - \n\n * `CANCELABLE` {`boolean`} - ",
730
730
  "attributes": [
731
731
  {
732
732
  "name": "value",
@@ -744,10 +744,17 @@
744
744
  "name": "customAutoCompletions",
745
745
  "description": "`customAutoCompletions` - \n\nProperty: customAutoCompletions\n\nDefault: [object Object]"
746
746
  },
747
+ {
748
+ "name": "customCompletionsPaths",
749
+ "description": "`customCompletionsPaths` {`string[]`} - \n\nProperty: customCompletionsPaths\n\nDefault: "
750
+ },
747
751
  {
748
752
  "name": "language",
749
- "description": "`language` {`\"javascript\" | \"sql\" | \"json\"`} - \n\nProperty: language\n\nDefault: javascript",
753
+ "description": "`language` {`\"html\" | \"javascript\" | \"sql\" | \"json\"`} - \n\nProperty: language\n\nDefault: javascript",
750
754
  "values": [
755
+ {
756
+ "name": "html"
757
+ },
751
758
  {
752
759
  "name": "javascript"
753
760
  },