@aquera/nile-elements 0.1.1 → 0.1.3
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/README.md +8 -0
- package/demo/variables.css +0 -556
- package/dist/nile-code-editor/extensionSetup.cjs.js +6 -6
- package/dist/nile-code-editor/extensionSetup.cjs.js.map +1 -1
- package/dist/nile-code-editor/extensionSetup.esm.js +1 -1
- package/dist/nile-code-editor/nile-code-editor.cjs.js +2 -2
- package/dist/nile-code-editor/nile-code-editor.cjs.js.map +1 -1
- package/dist/nile-code-editor/nile-code-editor.esm.js +3 -3
- package/dist/nile-drawer/nile-drawer.css.cjs.js +1 -1
- package/dist/nile-drawer/nile-drawer.css.cjs.js.map +1 -1
- package/dist/nile-drawer/nile-drawer.css.esm.js +1 -1
- package/dist/nile-form-help-text/nile-form-help-text.cjs.js +1 -1
- package/dist/nile-form-help-text/nile-form-help-text.cjs.js.map +1 -1
- package/dist/nile-form-help-text/nile-form-help-text.esm.js +2 -2
- package/dist/src/nile-code-editor/extensionSetup.d.ts +8 -9
- package/dist/src/nile-code-editor/extensionSetup.js +0 -13
- package/dist/src/nile-code-editor/extensionSetup.js.map +1 -1
- package/dist/src/nile-code-editor/nile-code-editor.d.ts +49 -15
- package/dist/src/nile-code-editor/nile-code-editor.js +195 -115
- package/dist/src/nile-code-editor/nile-code-editor.js.map +1 -1
- package/dist/src/nile-drawer/nile-drawer.css.js +1 -1
- package/dist/src/nile-drawer/nile-drawer.css.js.map +1 -1
- package/dist/src/nile-form-help-text/nile-form-help-text.js +32 -2
- package/dist/src/nile-form-help-text/nile-form-help-text.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +2 -1
- package/plop-templates/lit/lit.ts.hbs +2 -2
- package/src/nile-code-editor/extensionSetup.ts +8 -23
- package/src/nile-code-editor/nile-code-editor.ts +209 -124
- package/src/nile-drawer/nile-drawer.css.ts +1 -1
- package/src/nile-form-help-text/nile-form-help-text.ts +37 -3
- package/vscode-html-custom-data.json +13 -2
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.
|
6
|
+
"version": "0.1.3",
|
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,
|
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
|
|
@@ -30,6 +30,14 @@ import {
|
|
30
30
|
|
31
31
|
import { lintKeymap } from '@codemirror/lint';
|
32
32
|
|
33
|
+
export interface MinimalSetupOptions {
|
34
|
+
highlightSpecialChars?: boolean;
|
35
|
+
history?: boolean;
|
36
|
+
drawSelection?: boolean;
|
37
|
+
syntaxHighlighting?: boolean;
|
38
|
+
defaultKeymap?: boolean;
|
39
|
+
historyKeymap?: boolean;
|
40
|
+
}
|
33
41
|
export interface BasicSetupOptions extends MinimalSetupOptions {
|
34
42
|
lineNumbers?: boolean;
|
35
43
|
highlightActiveLineGutter?: boolean;
|
@@ -91,27 +99,4 @@ export const basicSetup = (options: BasicSetupOptions = {}): Extension[] => {
|
|
91
99
|
return extensions.concat([keymap.of(keymaps.flat())]).filter(Boolean);
|
92
100
|
};
|
93
101
|
|
94
|
-
export interface MinimalSetupOptions {
|
95
|
-
highlightSpecialChars?: boolean;
|
96
|
-
history?: boolean;
|
97
|
-
drawSelection?: boolean;
|
98
|
-
syntaxHighlighting?: boolean;
|
99
|
-
defaultKeymap?: boolean;
|
100
|
-
historyKeymap?: boolean;
|
101
|
-
}
|
102
102
|
|
103
|
-
export const minimalSetup = (options: MinimalSetupOptions = {}) => {
|
104
|
-
let keymaps: KeyBinding[] = [];
|
105
|
-
isValidSetup(options.defaultKeymap) && keymaps.push(...defaultKeymap);
|
106
|
-
isValidSetup(options.historyKeymap) && keymaps.push(...historyKeymap);
|
107
|
-
const extensions: Extension[] = [];
|
108
|
-
isValidSetup(options.highlightSpecialChars) &&
|
109
|
-
extensions.push(highlightSpecialChars());
|
110
|
-
isValidSetup(options.history) && extensions.push(history());
|
111
|
-
isValidSetup(options.drawSelection) && extensions.push(drawSelection());
|
112
|
-
isValidSetup(options.syntaxHighlighting) &&
|
113
|
-
extensions.push(
|
114
|
-
syntaxHighlighting(defaultHighlightStyle, { fallback: true })
|
115
|
-
);
|
116
|
-
return extensions.concat([keymap.of(keymaps.flat())]).filter(Boolean);
|
117
|
-
};
|
@@ -6,7 +6,6 @@
|
|
6
6
|
*/
|
7
7
|
|
8
8
|
import {
|
9
|
-
LitElement,
|
10
9
|
html,
|
11
10
|
CSSResultArray,
|
12
11
|
TemplateResult,
|
@@ -20,23 +19,23 @@ 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';
|
36
36
|
import { classMap } from 'lit/directives/class-map.js';
|
37
37
|
import { Theme } from './theme';
|
38
38
|
|
39
|
-
const TIME_OUT_DURATION=200;
|
40
39
|
// Choose the appropriate mode for your use case
|
41
40
|
|
42
41
|
/**
|
@@ -58,7 +57,9 @@ export class NileCodeEditor extends NileElement {
|
|
58
57
|
|
59
58
|
@property({ type: Object, reflect: true , attribute: true }) customAutoCompletions: object | any = {};
|
60
59
|
|
61
|
-
@property({ type:
|
60
|
+
@property({ type: Array, reflect: true , attribute: true }) customCompletionsPaths: string[] = [];
|
61
|
+
|
62
|
+
@property({ type: String, reflect: true , attribute: true}) language: 'javascript' | 'sql' | 'json' | 'html' = 'javascript';
|
62
63
|
|
63
64
|
@property({ type: String, reflect: true , attribute: 'error-message' }) errorMessage: string = '';
|
64
65
|
|
@@ -82,6 +83,8 @@ export class NileCodeEditor extends NileElement {
|
|
82
83
|
|
83
84
|
@property({ type: Boolean, reflect: true , attribute: true}) debounce: boolean = false;
|
84
85
|
|
86
|
+
@property({ type: Number, reflect: true , attribute: true}) debounceTimeout: number = 200;
|
87
|
+
|
85
88
|
public view: EditorView;
|
86
89
|
public viewState:EditorState;
|
87
90
|
private timeOut: any = null;
|
@@ -157,7 +160,7 @@ export class NileCodeEditor extends NileElement {
|
|
157
160
|
]
|
158
161
|
})
|
159
162
|
}
|
160
|
-
if(changedProperties.has('customAutoCompletions') || changedProperties.has('
|
163
|
+
if(changedProperties.has('customAutoCompletions') || changedProperties.has('customCompletionsPaths')){
|
161
164
|
this.view.dispatch({
|
162
165
|
effects: [
|
163
166
|
this.customCompletionComp.reconfigure(javascriptLanguage.data.of({
|
@@ -225,7 +228,7 @@ export class NileCodeEditor extends NileElement {
|
|
225
228
|
}));
|
226
229
|
|
227
230
|
this.viewState = EditorState.create({
|
228
|
-
doc: !this.multiline ?
|
231
|
+
doc: !this.multiline ? convertToSingleLine(this.value) : this.value,
|
229
232
|
extensions: [
|
230
233
|
basicSetup({
|
231
234
|
highlightActiveLine: false,
|
@@ -252,28 +255,112 @@ export class NileCodeEditor extends NileElement {
|
|
252
255
|
});
|
253
256
|
return this.viewState
|
254
257
|
}
|
258
|
+
/**
|
259
|
+
* Custom autocomplete handler for code editor suggestions
|
260
|
+
* @param context CompletionContext from CodeMirror
|
261
|
+
* @returns CompletionResult with suggestions or null if no suggestions
|
262
|
+
*/
|
263
|
+
customAutocomplete = (context: CompletionContext): CompletionResult | null => {
|
264
|
+
// Getting the valid last line, last text from the code editor
|
265
|
+
const text = context.state.doc.sliceString(0, context.pos);
|
266
|
+
const lastWord = text.split('\n').at(-1)?.split(' ').at(-1) || '';
|
267
|
+
const [textBeforeCursor, baseTextAfterSeperation] = splitStringAtLastSeparator(lastWord);
|
268
|
+
|
269
|
+
return this.getNestedSuggestions(context, textBeforeCursor, baseTextAfterSeperation)
|
270
|
+
|| this.getTopLevelSuggestions(context, textBeforeCursor);
|
271
|
+
};
|
255
272
|
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
273
|
+
/**
|
274
|
+
* Gets nested property suggestions based on the current path
|
275
|
+
* @param context CompletionContext from CodeMirror
|
276
|
+
* @param textBeforeCursor Text before cursor position
|
277
|
+
* @param baseTextAfterSeperation Text after the last separator (. or [)
|
278
|
+
* @returns CompletionResult with nested suggestions or null
|
279
|
+
*/
|
280
|
+
getNestedSuggestions(context: CompletionContext, textBeforeCursor: string, baseTextAfterSeperation: string) {
|
281
|
+
// Return early if not a valid path or not ending with . or [
|
282
|
+
if (!isValidPath(textBeforeCursor) || !['.', '['].includes(textBeforeCursor.at(-1)!)) {
|
283
|
+
return null;
|
284
|
+
}
|
285
|
+
|
286
|
+
const path = parsePath(textBeforeCursor);
|
287
|
+
if (!path) return null;
|
288
|
+
|
289
|
+
const textAfterSeperation = baseTextAfterSeperation.replace(/["'\[]/g, '');
|
290
|
+
const isInString = textAfterSeperation !== baseTextAfterSeperation;
|
291
|
+
const isBracket = textBeforeCursor.at(-1) === '[';
|
292
|
+
|
293
|
+
// Return null if we're in a string after a dot
|
294
|
+
if (textBeforeCursor.at(-1) === '.' && isInString) return null;
|
295
|
+
|
296
|
+
// Get nested properties and filter by text after separation if it exists
|
297
|
+
let resolved = resolveNestedProperties(this.customAutoCompletions, path);
|
298
|
+
if (!resolved || typeof resolved !== 'object') return null;
|
299
|
+
|
300
|
+
if (textAfterSeperation) {
|
301
|
+
resolved = Object.fromEntries(
|
302
|
+
Object.entries(resolved).filter(([key]) =>
|
303
|
+
key.toLowerCase().startsWith(textAfterSeperation.toLowerCase())
|
304
|
+
)
|
305
|
+
);
|
306
|
+
}
|
307
|
+
|
308
|
+
return {
|
309
|
+
from: context.pos - textAfterSeperation.length,
|
310
|
+
options: Object.keys(resolved).map(key => ({
|
311
|
+
label: key,
|
312
|
+
type: 'property',
|
313
|
+
info: `Key of ${path[path.length - 1]}`,
|
314
|
+
apply: !this.allowVariableInCustomSuggestion && (isBracket && !isInString)
|
315
|
+
? `'${key}'`
|
316
|
+
: key,
|
317
|
+
boost: 999
|
318
|
+
}))
|
319
|
+
};
|
266
320
|
}
|
267
321
|
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
322
|
+
/**
|
323
|
+
* Gets top level suggestions based on custom completions and paths
|
324
|
+
* @param context CompletionContext from CodeMirror
|
325
|
+
* @param textBeforeCursor Text before cursor position
|
326
|
+
* @returns CompletionResult with top level suggestions or null
|
327
|
+
*/
|
328
|
+
getTopLevelSuggestions(context: CompletionContext,textBeforeCursor:string){
|
329
|
+
const baseMatch: any = textBeforeCursor.match(/([a-zA-Z_$][\w$]*)$/);
|
330
|
+
if (!baseMatch) return null;
|
331
|
+
|
332
|
+
const optionsList = Object.keys(this.customAutoCompletions).filter(key =>
|
333
|
+
Object.keys(this.customAutoCompletions[key]).length &&
|
334
|
+
key.toLowerCase().startsWith(textBeforeCursor.toLowerCase())
|
335
|
+
);
|
336
|
+
|
337
|
+
const options=optionsList.map((key) => ({
|
338
|
+
label: key,
|
339
|
+
type: 'property',
|
340
|
+
apply: key,
|
341
|
+
boost: 999
|
342
|
+
}))
|
343
|
+
if(this.customCompletionsPaths.length){
|
344
|
+
this.customCompletionsPaths
|
345
|
+
.filter(path=>path.toLocaleLowerCase().includes(textBeforeCursor.toLocaleLowerCase()))
|
346
|
+
.map(path=>{
|
347
|
+
options.push({
|
348
|
+
label: ''+path,
|
349
|
+
type: 'property',
|
350
|
+
apply: ''+path,
|
351
|
+
boost: 998
|
352
|
+
})
|
353
|
+
})
|
354
|
+
}
|
355
|
+
return {
|
356
|
+
from: context.pos - baseMatch[1].length,
|
357
|
+
options: options
|
358
|
+
}
|
272
359
|
}
|
273
360
|
|
274
361
|
emitAfterTimeout(value:any){
|
275
362
|
if(this.timeOut) clearTimeout(this.timeOut);
|
276
|
-
this.timeOut=setTimeout(()=> this.emit('nile-change', value, false),
|
363
|
+
this.timeOut=setTimeout(()=> this.emit('nile-change', value, false), this.debounceTimeout)
|
277
364
|
}
|
278
365
|
|
279
366
|
public insertBetweenCode=(text: string) => {
|
@@ -283,18 +370,32 @@ export class NileCodeEditor extends NileElement {
|
|
283
370
|
});
|
284
371
|
this.view.dispatch(transaction);
|
285
372
|
}
|
286
|
-
|
373
|
+
|
374
|
+
singleLineMultiLineToggle() {
|
375
|
+
this.view.dispatch({
|
376
|
+
changes: {
|
377
|
+
from: 0,
|
378
|
+
to: this.view.state.doc.length,
|
379
|
+
insert: !this.multiline
|
380
|
+
? convertToSingleLine(this.value)
|
381
|
+
: this.value,
|
382
|
+
},
|
383
|
+
});
|
384
|
+
}
|
385
|
+
|
287
386
|
//EXTENSION CONFIGURATIONS
|
288
387
|
getLineNumbersExension() {
|
289
388
|
return (!this.multiline && this.lineNumbers) || (this.multiline && this.lineNumbersMultiline) ? lineNumbers() : [];
|
290
389
|
}
|
291
390
|
|
292
|
-
getLanguageExtension(){
|
391
|
+
getLanguageExtension():Extension{
|
293
392
|
switch(this.language){
|
294
393
|
case 'sql':
|
295
394
|
return sql();
|
296
395
|
case 'json':
|
297
396
|
return json();
|
397
|
+
case 'html':
|
398
|
+
return htmlLang();
|
298
399
|
default:
|
299
400
|
return javascript();
|
300
401
|
}
|
@@ -319,115 +420,99 @@ export class NileCodeEditor extends NileElement {
|
|
319
420
|
tr.newDoc.lines > 1 ? [] : tr
|
320
421
|
);
|
321
422
|
}
|
423
|
+
/* #endregion */
|
424
|
+
}
|
322
425
|
|
323
|
-
|
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
|
-
};
|
426
|
+
export default NileCodeEditor;
|
382
427
|
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
return null;
|
389
|
-
}, obj);
|
390
|
-
};
|
428
|
+
declare global {
|
429
|
+
interface HTMLElementTagNameMap {
|
430
|
+
'nile-code-editor': NileCodeEditor;
|
431
|
+
}
|
432
|
+
}
|
391
433
|
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
434
|
+
/**
|
435
|
+
* Parses a string path into an array of keys representing nested object access
|
436
|
+
* @param text The path string to parse (e.g. "foo.bar[0].baz")
|
437
|
+
* @returns Array of keys if valid path, null otherwise
|
438
|
+
* @example
|
439
|
+
* parsePath("foo.bar[0]") // returns ["foo", "bar", "0"]
|
440
|
+
* parsePath("invalid") // returns null
|
441
|
+
*/
|
442
|
+
function parsePath(text: string) {
|
443
|
+
const regex = /([a-zA-Z_$][\w$]*)(\[(?:[^\]]+)\]|\.[a-zA-Z_$][\w$]*)*/g;
|
444
|
+
const matches = [...text.matchAll(regex)];
|
445
|
+
if (matches.length > 0) {
|
446
|
+
const base = matches[0][1]; // The base object name
|
447
|
+
const keys = [base];
|
448
|
+
// Extract keys from dot or bracket notation
|
449
|
+
const pathMatches = text.match(/\[(.*?)\]|\.(\w+)/g) || [];
|
450
|
+
for (const match of pathMatches) {
|
451
|
+
if (match.startsWith('[')) {
|
452
|
+
keys.push(match.slice(1, -1).replace(/['"]/g, '')); // Remove brackets and quotes
|
453
|
+
} else if (match.startsWith('.')) {
|
454
|
+
keys.push(match.slice(1));
|
406
455
|
}
|
407
|
-
return keys;
|
408
456
|
}
|
409
|
-
return
|
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);
|
457
|
+
return keys;
|
417
458
|
}
|
459
|
+
return null;
|
460
|
+
};
|
418
461
|
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
462
|
+
/**
|
463
|
+
* Splits a path string at the last separator (. or [)
|
464
|
+
* @param input The path string to split
|
465
|
+
* @returns Array containing [path up to last separator, remainder after separator]
|
466
|
+
* @example
|
467
|
+
* splitStringAtLastSeparator("foo.bar[0]") // returns ["foo.bar[", "0"]
|
468
|
+
*/
|
469
|
+
function splitStringAtLastSeparator(input:string) {
|
470
|
+
const lastSeparatorIndex = Math.max(input.lastIndexOf('.'), input.lastIndexOf('['));
|
471
|
+
if (lastSeparatorIndex === -1) return [input, ''];
|
472
|
+
return [input.slice(0, lastSeparatorIndex + 1), input.slice(lastSeparatorIndex + 1)];
|
425
473
|
}
|
426
474
|
|
427
|
-
|
475
|
+
/**
|
476
|
+
* Traverses an object using an array of keys to access nested properties
|
477
|
+
* @param obj The object to traverse
|
478
|
+
* @param keys Array of keys defining the path to the desired property
|
479
|
+
* @returns The value at the specified path, or null if path is invalid
|
480
|
+
* @example
|
481
|
+
* resolveNestedProperties({foo: {bar: 123}}, ["foo", "bar"]) // returns 123
|
482
|
+
*/
|
483
|
+
function resolveNestedProperties (obj:any, keys:any[]){
|
484
|
+
return keys.reduce((acc, key) => {
|
485
|
+
if (acc && typeof acc === 'object') {
|
486
|
+
return acc[key];
|
487
|
+
}
|
488
|
+
return null;
|
489
|
+
}, obj);
|
490
|
+
};
|
428
491
|
|
429
|
-
|
430
|
-
|
431
|
-
|
432
|
-
|
492
|
+
/**
|
493
|
+
* Validates if a string represents a valid object path format
|
494
|
+
* @param path The path string to validate
|
495
|
+
* @returns Boolean indicating if path format is valid
|
496
|
+
* @example
|
497
|
+
* isValidPath("foo.bar[0]") // returns true
|
498
|
+
* isValidPath("foo..bar") // returns false
|
499
|
+
*/
|
500
|
+
function isValidPath(path: string) {
|
501
|
+
// Regex to validate the format of the string
|
502
|
+
const regex = /^([a-zA-Z_$][\w$]*)(\.[a-zA-Z_$][\w$]*|\[\s*(['"]?[a-zA-Z0-9_$]*['"]?)\s*\])*([\.\[])?$/;
|
503
|
+
// Test the string against the regex
|
504
|
+
return regex.test(path);
|
433
505
|
}
|
506
|
+
|
507
|
+
/**
|
508
|
+
* Converts multi-line code into a single line by removing line breaks and extra whitespace
|
509
|
+
* @param code The code string to convert
|
510
|
+
* @returns Single line version of the code
|
511
|
+
* @example
|
512
|
+
* convertToSingleLine("foo\n bar") // returns "foo bar"
|
513
|
+
*/
|
514
|
+
function convertToSingleLine(code: string) {
|
515
|
+
if (!code) return '';
|
516
|
+
// Remove line breaks and unnecessary whitespace
|
517
|
+
return code.replace(/\s+/g, ' ').trim();
|
518
|
+
}
|
@@ -58,8 +58,15 @@ export class NileFormHelpText extends LitElement {
|
|
58
58
|
this.updateDisplayedText()
|
59
59
|
}
|
60
60
|
|
61
|
-
updateDisplayedText(){
|
62
|
-
|
61
|
+
updateDisplayedText() {
|
62
|
+
if (this.isExpanded) {
|
63
|
+
this.displayedText = this.fullText;
|
64
|
+
} else {
|
65
|
+
const validConcatNumber=concatSentence(this.fullText, this.textLimit)
|
66
|
+
const truncatedText = this.fullText.slice(0, validConcatNumber);
|
67
|
+
const ellipsis = this.fullText.length > validConcatNumber ? '...' : '';
|
68
|
+
this.displayedText = `${truncatedText}${ellipsis}`;
|
69
|
+
}
|
63
70
|
}
|
64
71
|
|
65
72
|
/* #endregion */
|
@@ -71,7 +78,7 @@ export class NileFormHelpText extends LitElement {
|
|
71
78
|
* @slot This is a slot test
|
72
79
|
*/
|
73
80
|
public render(): TemplateResult {
|
74
|
-
const showMoreButton = this.fullText.length > this.textLimit
|
81
|
+
const showMoreButton = this.fullText.length > this.textLimit;
|
75
82
|
const iconName = this.isExpanded ? 'arrowup' : 'arrowdown';
|
76
83
|
|
77
84
|
return html`
|
@@ -101,3 +108,30 @@ declare global {
|
|
101
108
|
'nile-form-help-text': NileFormHelpText;
|
102
109
|
}
|
103
110
|
}
|
111
|
+
|
112
|
+
function concatSentence(sentence:string, n:number) {
|
113
|
+
if (n < 0 || n > sentence.length) {
|
114
|
+
throw new Error("Invalid value of n. It must be between 0 and the sentence length.");
|
115
|
+
}
|
116
|
+
|
117
|
+
// Adjust n if it falls in the middle of a word
|
118
|
+
if (sentence[n] !== " " && n !== 0 && n !== sentence.length) {
|
119
|
+
// Move left until the start of the word or the beginning of the sentence
|
120
|
+
let left = n;
|
121
|
+
while (left > 0 && sentence[left - 1] !== " ") {
|
122
|
+
left--;
|
123
|
+
}
|
124
|
+
|
125
|
+
// Move right until the end of the word or the end of the sentence
|
126
|
+
let right = n;
|
127
|
+
while (right < sentence.length && sentence[right] !== " ") {
|
128
|
+
right++;
|
129
|
+
}
|
130
|
+
|
131
|
+
// Adjust n to the closer boundary
|
132
|
+
n = (n - left <= right - n) ? left : right;
|
133
|
+
}
|
134
|
+
|
135
|
+
// Return the substring from the start to the adjusted n
|
136
|
+
return n;
|
137
|
+
}
|
@@ -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 * `
|
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\n * `debounceTimeout` {`number`} - \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 * `debounceTimeout` {`number`} - \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` - Custom autocomplete handler for code editor suggestions\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
|
},
|
@@ -813,6 +820,10 @@
|
|
813
820
|
"description": "`debounce` {`boolean`} - \n\nProperty: debounce\n\nDefault: false",
|
814
821
|
"valueSet": "v"
|
815
822
|
},
|
823
|
+
{
|
824
|
+
"name": "debounceTimeout",
|
825
|
+
"description": "`debounceTimeout` {`number`} - \n\nProperty: debounceTimeout\n\nDefault: 200"
|
826
|
+
},
|
816
827
|
{
|
817
828
|
"name": "onnile-focus",
|
818
829
|
"description": "`nile-focus` {`Event`} - "
|