@esfaenza/flow-builder 20.3.28 → 20.3.30
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 +10 -1
- package/fesm2022/esfaenza-flow-builder.mjs +143 -2
- package/fesm2022/esfaenza-flow-builder.mjs.map +1 -1
- package/index.d.ts +108 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -144,6 +144,7 @@ sono opzionali e rifiutano con `MissingService` se non sovrascritti.
|
|
|
144
144
|
| `listEnumTypes`, `listEvents`, `listSubflowCandidates` | astratti |
|
|
145
145
|
| `describeObject` | opzionale |
|
|
146
146
|
| `listFieldValues(object, field)` | opzionale — i valori ammessi di un campo a **scelta chiusa** (`hasClosedValueSet`, §6.4), cioe' l'altra meta' degli insiemi chiusi: quelli di un `Enum` sono del **tipo** (`listEnumValues`), questi della **colonna** — `Ordine.Stato` e `Attivita.Stato` possono ammettere valori diversi pur essendo due `String`, ed e' perche' serve la coppia. Lista vuota = "non lo so": il valore si scrive a mano |
|
|
147
|
+
| `listFormulaFunctions(usage?)` | opzionale — le funzioni (e gli operatori, se il motore li dichiara) scrivibili in un'espressione: e' la **palette** di `<fb-formula-editor>`, la terza gamba accanto ai nomi (`getReferences`) e al giudizio (`validateFormula`). `usage` e' lo stesso di `validateFormula` e un motore che non filtra risponde comunque tutto, che e' legittimo. Due regole: lista vuota = «il motore non le dichiara» e la palette non compare (§4.6), e l'elenco **non e' autoritativo** — accusare una funzione fuori catalogo sarebbe un rilievo falso su una formula valida |
|
|
147
148
|
| `listEnumValues(enumType)` | opzionale — i **valori** di un tipo di enumerazione, cioe' i nomi scrivibili in `enumValue` (§4.2, §4.6). `listEnumTypes` e' l'altra meta' e non basta: quella dice quali tipi esistono, questa quali valori ha un tipo. `enumType` e' esattamente l'`objectType` della risorsa, del parametro o del **membro** di una classe (§4.7.1): la risposta e' del tipo, non del punto di uso, e la cache e' per nome del tipo. Lista vuota = "non lo so" — il valore si scrive a mano, e un tipo sconosciuto risponde vuoto, non 404 |
|
|
148
149
|
| `listStructures`, `describeStructure(className)` | opzionali — le classi e i loro membri per le risorse `Structure` (§4.7). `listStructures` e' l'**elenco delle classi** senza membri; `describeStructure` restituisce la **descrizione** di una classe (`className`, `label`, `members`), non un array nudo (§4.7.1). Senza, le classi non sono verificabili e il nome si scrive a mano: "non lo so", non "non esiste". I tre esiti sono distinti: `members` popolato = elenco autorevole, `members: []` = membri non dichiarati (si digita, nessuna accusa), rifiuto `StructureNotFound` = classe non registrata (si segnala la **classe**) |
|
|
149
150
|
|
|
@@ -463,7 +464,15 @@ salto, `position` resterebbe un numero da contare a mano. Lo stesso componente o
|
|
|
463
464
|
citabili come **autocompletamento** mentre si scrive un identificatore: la fonte e'
|
|
464
465
|
`POST /flows/references`, la stessa del reference picker, output automatici compresi; frecce per
|
|
465
466
|
scorrere, Invio o clic per inserire. Elenco non disponibile = nessun suggerimento e nessuna
|
|
466
|
-
accusa — la formula si scrive lo stesso.
|
|
467
|
+
accusa — la formula si scrive lo stesso. La terza gamba e' la **palette**: `listFormulaFunctions`
|
|
468
|
+
(`GET /catalog/formula-functions?usage=`, §6.3) dice cosa si puo' scrivere in mezzo ai nomi, e il
|
|
469
|
+
componente la apre da un bottone, raggruppata per categoria e filtrabile; scegliere una voce
|
|
470
|
+
inserisce il suo `snippet` — assente, il nome — e porta il cursore **dentro** la prima parentesi.
|
|
471
|
+
Due cose che non si devono confondere: elenco vuoto significa «il motore non le dichiara», quindi
|
|
472
|
+
il bottone non compare affatto invece di aprire un pannello vuoto; e l'elenco **non e'
|
|
473
|
+
autoritativo** — a giudicare resta `validateFormula`, e accusare una funzione fuori catalogo
|
|
474
|
+
sarebbe un rilievo falso su una formula valida, perche' un motore puo' supportare piu' di quanto
|
|
475
|
+
dichiara. `signature` e `description` si mostrano e non si parsano: la grammatica resta del motore. Lo usano tutti i punti in cui si scrive
|
|
467
476
|
un'espressione: la risorsa `Formula`, la modalita' Formula di una condizione, la `filterFormula`
|
|
468
477
|
di un filtro, la regola di validazione di un campo di screen dinamico e il `formulaExpression`
|
|
469
478
|
dentro un valore. A ogni punto corrispondono un `usage` e un `expectedDataType` — `Boolean` per
|
|
@@ -218,6 +218,30 @@ class FlowBuilderApi {
|
|
|
218
218
|
void field;
|
|
219
219
|
return missing('listFieldValues');
|
|
220
220
|
}
|
|
221
|
+
/**
|
|
222
|
+
* `GET /catalog/formula-functions?usage=` — le funzioni (e gli operatori, se il motore li
|
|
223
|
+
* dichiara) scrivibili in un'espressione: la **palette** dell'editor di formule (§6.3, §6.4).
|
|
224
|
+
*
|
|
225
|
+
* È la terza gamba dell'editor di formule, e le altre due non la sostituiscono: i **nomi**
|
|
226
|
+
* citabili li da' {@link getReferences}, il **giudizio** sull'espressione
|
|
227
|
+
* {@link validateFormula}, e questa dice cosa si puo' scrivere in mezzo.
|
|
228
|
+
*
|
|
229
|
+
* `usage` chiede le sole funzioni che hanno senso in quel punto — lo stesso valore che va in
|
|
230
|
+
* {@link validateFormula}. Un motore che non filtra risponde comunque l'elenco intero, che e'
|
|
231
|
+
* legittimo: chi mostra non deve dedurre niente dal fatto che una voce ci sia.
|
|
232
|
+
*
|
|
233
|
+
* Due regole, e non sono dettagli. La lista **vuota** significa «il motore non le dichiara»,
|
|
234
|
+
* non «non ce ne sono» (§4.6): si mostra il campo di testo libero, non una palette vuota. E
|
|
235
|
+
* l'elenco **non e' autoritativo**: accusare una funzione che non c'e' produrrebbe un rilievo
|
|
236
|
+
* falso su una formula valida, perche' un motore puo' supportare piu' di quanto dichiara.
|
|
237
|
+
*
|
|
238
|
+
* Opzionale come ogni catalogo che dipende da un servizio dell'host: assente, l'editor di
|
|
239
|
+
* formule resta quello di prima — nomi e verifica, senza palette.
|
|
240
|
+
*/
|
|
241
|
+
listFormulaFunctions(usage) {
|
|
242
|
+
void usage;
|
|
243
|
+
return missing('listFormulaFunctions');
|
|
244
|
+
}
|
|
221
245
|
/**
|
|
222
246
|
* `GET /catalog/enum-types/{enumType}/values` — i valori di **un** tipo di enumerazione, cioe'
|
|
223
247
|
* i nomi che si possono scrivere in `enumValue` (§4.2, §4.6). `enumType` e' esattamente
|
|
@@ -567,6 +591,13 @@ class HttpFlowBuilderApi extends FlowBuilderApi {
|
|
|
567
591
|
listFormParameters(formName) {
|
|
568
592
|
return this.get(`/flows/editor/forms/${HttpFlowBuilderApi.segment(formName)}/parameters`);
|
|
569
593
|
}
|
|
594
|
+
/**
|
|
595
|
+
* §6.3 — la palette dell'editor di formule. `usage` e' un filtro, non un obbligo: chi non lo
|
|
596
|
+
* manda ottiene l'elenco intero, ed e' legittimo anche che un motore lo ignori.
|
|
597
|
+
*/
|
|
598
|
+
listFormulaFunctions(usage) {
|
|
599
|
+
return this.get('/flows/editor/formula-functions', HttpFlowBuilderApi.params({ usage }));
|
|
600
|
+
}
|
|
570
601
|
listEnumTypes() {
|
|
571
602
|
return this.get('/flows/editor/enum-types');
|
|
572
603
|
}
|
|
@@ -3461,6 +3492,7 @@ class FlowCatalogStore {
|
|
|
3461
3492
|
entriesCache = new AsyncCache();
|
|
3462
3493
|
parametersCache = new AsyncCache();
|
|
3463
3494
|
membersCache = new AsyncCache();
|
|
3495
|
+
formulaFunctionsCache = new AsyncCache();
|
|
3464
3496
|
/**
|
|
3465
3497
|
* Una lista vuota significa "non lo so", non "nessuno": con il catalogo non popolato la
|
|
3466
3498
|
* validazione salta i controlli invece di produrre falsi allarmi (§7). L'editor fa lo
|
|
@@ -3516,6 +3548,17 @@ class FlowCatalogStore {
|
|
|
3516
3548
|
}
|
|
3517
3549
|
return this.parametersCache.get(`form|${formName}`, () => this.api.listFormParameters(formName).catch(() => []));
|
|
3518
3550
|
}
|
|
3551
|
+
/**
|
|
3552
|
+
* §6.3 — la palette dell'editor di formule. La cache e' per **usage**, perche' e' cio' che
|
|
3553
|
+
* cambia la risposta: un motore che filtra risponde due elenchi diversi a `Condition` e a
|
|
3554
|
+
* `Resource`, e una chiave sola li farebbe sovrascrivere a vicenda.
|
|
3555
|
+
*
|
|
3556
|
+
* La primitiva e' opzionale e l'errore diventa lista vuota — che qui significa «il motore non
|
|
3557
|
+
* le dichiara»: nessuna palette e nessuna accusa a una funzione fuori elenco (§4.6, §6.3).
|
|
3558
|
+
*/
|
|
3559
|
+
listFormulaFunctions(usage) {
|
|
3560
|
+
return this.formulaFunctionsCache.get(usage ?? '', () => this.api.listFormulaFunctions(usage).then((list) => list ?? []).catch(() => []));
|
|
3561
|
+
}
|
|
3519
3562
|
listEnumTypes() {
|
|
3520
3563
|
return this.entriesCache.get('enum-types', () => this.api.listEnumTypes().then((list) => list ?? []));
|
|
3521
3564
|
}
|
|
@@ -3587,6 +3630,7 @@ class FlowCatalogStore {
|
|
|
3587
3630
|
this.entriesCache.clear();
|
|
3588
3631
|
this.parametersCache.clear();
|
|
3589
3632
|
this.membersCache.clear();
|
|
3633
|
+
this.formulaFunctionsCache.clear();
|
|
3590
3634
|
}
|
|
3591
3635
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.28", ngImport: i0, type: FlowCatalogStore, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
3592
3636
|
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.28", ngImport: i0, type: FlowCatalogStore });
|
|
@@ -6838,6 +6882,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.28", ngImpo
|
|
|
6838
6882
|
* la primitiva non esiste proprio: silenzio, mai un esito positivo inventato.
|
|
6839
6883
|
* - il codice del rilievo e' **del motore**, non della §7: si mostra e non si interpreta.
|
|
6840
6884
|
*
|
|
6885
|
+
* La terza gamba e' la **palette**: `listFormulaFunctions` (§6.3) dice cosa si puo' scrivere in
|
|
6886
|
+
* mezzo ai nomi. Non e' un elenco autoritativo — a giudicare resta `validateFormula`, quindi una
|
|
6887
|
+
* funzione fuori catalogo non si segnala — e vuoto significa «il motore non le dichiara»: in quel
|
|
6888
|
+
* caso il bottone non compare affatto, invece di aprire un pannello vuoto.
|
|
6889
|
+
*
|
|
6841
6890
|
* Il debounce e lo stato dell'esito stanno qui, uno per campo; nel servizio sta solo la memoria
|
|
6842
6891
|
* di «la primitiva non c'e'», che e' l'unica cosa condivisa fra i campi.
|
|
6843
6892
|
*/
|
|
@@ -6847,6 +6896,7 @@ class FormulaEditorComponent {
|
|
|
6847
6896
|
store = inject(FlowDocumentStore);
|
|
6848
6897
|
api = inject(FlowBuilderApi);
|
|
6849
6898
|
service = inject(FormulaValidationService);
|
|
6899
|
+
catalog = inject(FlowCatalogStore);
|
|
6850
6900
|
destroyRef = inject(DestroyRef);
|
|
6851
6901
|
expression = input('', ...(ngDevMode ? [{ debugName: "expression" }] : []));
|
|
6852
6902
|
/** Dove comparira': e' cio' che dice al motore cosa pretendere (§6.3). */
|
|
@@ -6907,6 +6957,91 @@ class FormulaEditorComponent {
|
|
|
6907
6957
|
}
|
|
6908
6958
|
return matches.slice(0, 8);
|
|
6909
6959
|
}, ...(ngDevMode ? [{ debugName: "suggestions" }] : []));
|
|
6960
|
+
// -------------------------------------------------------------------------
|
|
6961
|
+
// La palette delle funzioni (§6.3)
|
|
6962
|
+
// -------------------------------------------------------------------------
|
|
6963
|
+
/**
|
|
6964
|
+
* Le funzioni dichiarate dal motore. L'elenco lo tiene in cache lo store, per `usage`: piu'
|
|
6965
|
+
* editor montati insieme fanno una richiesta sola. Vuoto = non dichiarate, e allora la palette
|
|
6966
|
+
* non esiste — mostrarla vuota farebbe credere che il motore non abbia funzioni.
|
|
6967
|
+
*/
|
|
6968
|
+
functions = signal([], ...(ngDevMode ? [{ debugName: "functions" }] : []));
|
|
6969
|
+
isPaletteOpen = signal(false, ...(ngDevMode ? [{ debugName: "isPaletteOpen" }] : []));
|
|
6970
|
+
paletteFilter = signal('', ...(ngDevMode ? [{ debugName: "paletteFilter" }] : []));
|
|
6971
|
+
hasPalette = computed(() => this.functions().length > 0, ...(ngDevMode ? [{ debugName: "hasPalette" }] : []));
|
|
6972
|
+
/**
|
|
6973
|
+
* Le voci raggruppate per `category`. La categoria puo' mancare: quelle senza finiscono in un
|
|
6974
|
+
* gruppo senza titolo, in coda, invece di sparire.
|
|
6975
|
+
*/
|
|
6976
|
+
paletteGroups = computed(() => {
|
|
6977
|
+
const needle = this.paletteFilter().trim().toLowerCase();
|
|
6978
|
+
const groups = new Map();
|
|
6979
|
+
for (const entry of this.functions()) {
|
|
6980
|
+
if (needle && !this.matchesFilter(entry, needle)) {
|
|
6981
|
+
continue;
|
|
6982
|
+
}
|
|
6983
|
+
const category = entry.category?.trim() || '';
|
|
6984
|
+
const bucket = groups.get(category);
|
|
6985
|
+
if (bucket) {
|
|
6986
|
+
bucket.push(entry);
|
|
6987
|
+
}
|
|
6988
|
+
else {
|
|
6989
|
+
groups.set(category, [entry]);
|
|
6990
|
+
}
|
|
6991
|
+
}
|
|
6992
|
+
return Array.from(groups, ([category, items]) => ({ category, items })).sort(
|
|
6993
|
+
// Il gruppo senza titolo va in coda: e' il ripiego, non la prima cosa da leggere.
|
|
6994
|
+
(a, b) => (a.category ? 0 : 1) - (b.category ? 0 : 1) || a.category.localeCompare(b.category));
|
|
6995
|
+
}, ...(ngDevMode ? [{ debugName: "paletteGroups" }] : []));
|
|
6996
|
+
matchesFilter(entry, needle) {
|
|
6997
|
+
return (entry.name.toLowerCase().includes(needle) ||
|
|
6998
|
+
(entry.signature ?? '').toLowerCase().includes(needle) ||
|
|
6999
|
+
(entry.description ?? '').toLowerCase().includes(needle));
|
|
7000
|
+
}
|
|
7001
|
+
togglePalette() {
|
|
7002
|
+
this.isPaletteOpen.update((open) => !open);
|
|
7003
|
+
}
|
|
7004
|
+
/** La forma d'uso da mostrare: `signature` se il motore la da', altrimenti il solo nome. */
|
|
7005
|
+
signatureOf(entry) {
|
|
7006
|
+
return entry.signature?.trim() || entry.name;
|
|
7007
|
+
}
|
|
7008
|
+
/**
|
|
7009
|
+
* Inserisce la voce scelta al punto in cui si stava scrivendo. Cosa inserire lo dice `snippet`
|
|
7010
|
+
* — assente, il nome — e il cursore va **dentro** la prima parentesi: la palette serve a non
|
|
7011
|
+
* ricordare la firma, e lasciare il cursore in fondo costringerebbe a tornare indietro a mano.
|
|
7012
|
+
*
|
|
7013
|
+
* Non si scrive niente nel documento oltre al testo: la firma resta del motore, e qui non c'e'
|
|
7014
|
+
* nessun parser che la interpreti.
|
|
7015
|
+
*/
|
|
7016
|
+
insertFunction(entry) {
|
|
7017
|
+
const element = this.area()?.nativeElement;
|
|
7018
|
+
if (!element || this.disabled()) {
|
|
7019
|
+
return;
|
|
7020
|
+
}
|
|
7021
|
+
const snippet = entry.snippet?.trim() || entry.name;
|
|
7022
|
+
// Se si stava digitando un nome, la voce lo **sostituisce**: chi scrive `RO` e sceglie
|
|
7023
|
+
// `ROUND(` non vuole `ROROUND(`.
|
|
7024
|
+
const token = this.token();
|
|
7025
|
+
const start = token ? token.start : (element.selectionStart ?? element.value.length);
|
|
7026
|
+
const end = token ? token.end : (element.selectionEnd ?? start);
|
|
7027
|
+
const next = element.value.slice(0, start) + snippet + element.value.slice(end);
|
|
7028
|
+
const opening = snippet.indexOf('(');
|
|
7029
|
+
const caret = start + (opening >= 0 ? opening + 1 : snippet.length);
|
|
7030
|
+
element.value = next;
|
|
7031
|
+
element.setSelectionRange(caret, caret);
|
|
7032
|
+
element.focus();
|
|
7033
|
+
this.token.set(null);
|
|
7034
|
+
this.onInput(next);
|
|
7035
|
+
// Con `commitOn="change"` il `change` del DOM non scatta su una scrittura da codice.
|
|
7036
|
+
this.onCommit(next);
|
|
7037
|
+
}
|
|
7038
|
+
async loadFunctions(usage) {
|
|
7039
|
+
// La primitiva e' opzionale: in errore lo store risponde lista vuota, cioe' «non dichiarate».
|
|
7040
|
+
const list = await this.catalog.listFormulaFunctions(usage);
|
|
7041
|
+
if (this.usage() === usage) {
|
|
7042
|
+
this.functions.set(list);
|
|
7043
|
+
}
|
|
7044
|
+
}
|
|
6910
7045
|
issues = computed(() => this._result()?.issues ?? [], ...(ngDevMode ? [{ debugName: "issues" }] : []));
|
|
6911
7046
|
hasErrors = computed(() => this.issues().some((issue) => severityBucket(issue.severity) === 'Error'), ...(ngDevMode ? [{ debugName: "hasErrors" }] : []));
|
|
6912
7047
|
/**
|
|
@@ -6942,6 +7077,12 @@ class FormulaEditorComponent {
|
|
|
6942
7077
|
// La verifica riparte quando cambia l'espressione **arrivata da fuori** o cio' che ci si
|
|
6943
7078
|
// aspetta che produca. Il documento no: si legge al momento della richiesta, perche'
|
|
6944
7079
|
// tracciarlo rivaliderebbe ogni formula aperta a ogni tasto premuto altrove nell'editor.
|
|
7080
|
+
// La palette dipende solo da `usage`, e la richiesta la condivide lo store: piu' editor
|
|
7081
|
+
// montati insieme non fanno piu' di una chiamata per uso.
|
|
7082
|
+
effect(() => {
|
|
7083
|
+
const usage = this.usage();
|
|
7084
|
+
untracked(() => void this.loadFunctions(usage));
|
|
7085
|
+
});
|
|
6945
7086
|
effect(() => {
|
|
6946
7087
|
const expression = this.expression();
|
|
6947
7088
|
this.usage();
|
|
@@ -7129,11 +7270,11 @@ class FormulaEditorComponent {
|
|
|
7129
7270
|
}
|
|
7130
7271
|
}
|
|
7131
7272
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.28", ngImport: i0, type: FormulaEditorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
7132
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.28", type: FormulaEditorComponent, isStandalone: true, selector: "fb-formula-editor", inputs: { expression: { classPropertyName: "expression", publicName: "expression", isSignal: true, isRequired: false, transformFunction: null }, usage: { classPropertyName: "usage", publicName: "usage", isSignal: true, isRequired: false, transformFunction: null }, expectedDataType: { classPropertyName: "expectedDataType", publicName: "expectedDataType", isSignal: true, isRequired: false, transformFunction: null }, scale: { classPropertyName: "scale", publicName: "scale", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, rows: { classPropertyName: "rows", publicName: "rows", isSignal: true, isRequired: false, transformFunction: null }, commitOn: { classPropertyName: "commitOn", publicName: "commitOn", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { expressionChange: "expressionChange" }, viewQueries: [{ propertyName: "area", first: true, predicate: ["area"], descendants: true, isSignal: true }], ngImport: i0, template: "<textarea\r\n #area\r\n class=\"fb-textarea fb-input--mono\"\r\n [class.fb-input--invalid]=\"hasErrors()\"\r\n [value]=\"expression()\"\r\n [rows]=\"rows()\"\r\n [disabled]=\"disabled()\"\r\n [placeholder]=\"placeholder()\"\r\n [attr.aria-label]=\"ariaLabel()\"\r\n (input)=\"onInput($any($event.target).value)\"\r\n (change)=\"onCommit($any($event.target).value)\"\r\n (focus)=\"onFocus()\"\r\n (blur)=\"onBlur()\"\r\n (keydown)=\"onKeyDown($event)\"\r\n (keyup)=\"onCaretMove()\"\r\n (click)=\"onCaretMove()\"\r\n></textarea>\r\n\r\n@if (suggestions().length) {\r\n <!--\r\n L'elenco dei riferimenti disponibili come autocompletamento (\u00A76.3): stessa fonte del\r\n reference picker, `POST /flows/references`, output automatici compresi. `mousedown` va\r\n fermato \u2014 il blur della casella arriverebbe prima del click e chiuderebbe l'elenco.\r\n -->\r\n <ul class=\"fb-formula__hints\" role=\"listbox\" aria-label=\"Riferimenti disponibili\">\r\n @for (reference of suggestions(); track reference.name) {\r\n <li>\r\n <button\r\n type=\"button\"\r\n class=\"fb-formula__hint\"\r\n [class.fb-formula__hint--on]=\"$index === highlighted()\"\r\n role=\"option\"\r\n [attr.aria-selected]=\"$index === highlighted()\"\r\n (mousedown)=\"$event.preventDefault()\"\r\n (click)=\"insert(reference.name)\"\r\n >\r\n <code>{{ reference.name }}</code>\r\n @if (reference.dataType) {\r\n <span class=\"fb-formula__hint-type\">\r\n {{ reference.dataType }}{{ reference.isCollection ? '[]' : '' }}\r\n </span>\r\n }\r\n </button>\r\n </li>\r\n }\r\n </ul>\r\n}\r\n\r\n@if (isChecking()) {\r\n <p class=\"fb-field__hint\">Verifica in corso\u2026</p>\r\n} @else if (issues().length) {\r\n <ul class=\"fb-formula__issues\">\r\n @for (issue of issues(); track $index) {\r\n <li class=\"fb-formula__issue\" [class]=\"'fb-formula__issue--' + severityOf(issue)\">\r\n @if (hasPosition(issue)) {\r\n <!--\r\n Il salto e' il senso di `position`: un indice di carattere che l'utente dovrebbe\r\n contare a mano non porta da nessuna parte.\r\n -->\r\n <button\r\n type=\"button\"\r\n class=\"fb-formula__jump\"\r\n [disabled]=\"disabled()\"\r\n title=\"Seleziona il tratto segnalato\"\r\n (click)=\"goToIssue(issue)\"\r\n >\r\n @if (excerptOf(issue)) {\r\n <code>{{ excerptOf(issue) }}</code>\r\n } @else {\r\n car. {{ issue.position! + 1 }}\r\n }\r\n </button>\r\n }\r\n <span class=\"fb-formula__message\">{{ issue.message }}</span>\r\n <!-- Codice del motore, non della \u00A77: si mostra e non si interpreta. -->\r\n <code class=\"fb-formula__code\">{{ issue.code }}</code>\r\n </li>\r\n }\r\n </ul>\r\n} @else if (isConfirmed()) {\r\n <p class=\"fb-formula__ok\">\u2713 Espressione verificata dal motore.</p>\r\n} @else if (isUnverified()) {\r\n <!--\r\n Primitiva s\u00EC, motore no: nessun rilievo **e** nessuna conferma. Dirlo e' l'unico modo di\r\n non far leggere il silenzio come un via libera (\u00A76.3).\r\n -->\r\n <p class=\"fb-field__hint fb-field__hint--warn\">\r\n Nessun motore di validazione delle formule e\u2019 configurato: l\u2019espressione non e\u2019 stata\r\n controllata.\r\n </p>\r\n}\r\n\r\n@if (typeMismatch(); as mismatch) {\r\n <p class=\"fb-field__hint fb-field__hint--warn\">\r\n L\u2019espressione produce {{ mismatch.produced }}, ma qui serve {{ mismatch.expected }}.\r\n </p>\r\n}\r\n\r\n<ng-content />\r\n", styles: [":host{display:flex;flex-direction:column;gap:4px}.fb-formula__issues{display:flex;flex-direction:column;gap:3px;margin:0;padding:0;list-style:none}.fb-formula__issue{display:flex;flex-wrap:wrap;gap:5px;align-items:baseline;padding:3px 6px;border-left:3px solid var(--fb-border, #d6dae1);border-radius:3px;background:var(--fb-surface-alt, #f8f9fb);font-size:10px;line-height:1.45}.fb-formula__issue--Error{border-left-color:var(--fb-error, #c9372c);color:var(--fb-error, #c9372c)}.fb-formula__issue--Warning{border-left-color:var(--fb-warning, #b7791f);color:var(--fb-warning, #b7791f)}.fb-formula__issue--Info{border-left-color:var(--fb-accent, #2f6feb);color:var(--fb-text-muted, #667085)}.fb-formula__message{flex:1 1 auto;min-width:0}.fb-formula__jump{padding:0 4px;border:1px solid currentcolor;border-radius:3px;background:transparent;color:inherit;font:inherit;font-size:10px;cursor:pointer}.fb-formula__jump:disabled{opacity:.5;cursor:not-allowed}.fb-formula__jump code{font-family:ui-monospace,SFMono-Regular,Menlo,monospace}.fb-formula__code{color:var(--fb-text-subtle, #98a2b3);font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:9px}.fb-formula__ok{margin:0;font-size:10px;color:var(--fb-success, #22a06b)}.fb-formula__hints{display:flex;flex-direction:column;gap:1px;max-height:160px;margin:0;padding:2px;overflow-y:auto;border:1px solid var(--fb-border, #d6dae1);border-radius:4px;background:var(--fb-surface, #fff);list-style:none}.fb-formula__hint{display:flex;gap:6px;align-items:baseline;width:100%;padding:2px 5px;border:0;border-radius:3px;background:transparent;color:var(--fb-text, #1d2939);font:inherit;font-size:10px;text-align:left;cursor:pointer}.fb-formula__hint:hover,.fb-formula__hint--on{background:color-mix(in srgb,var(--fb-accent, #2f6feb) 10%,transparent)}.fb-formula__hint code{font-family:ui-monospace,SFMono-Regular,Menlo,monospace}.fb-formula__hint-type{margin-left:auto;color:var(--fb-text-subtle, #98a2b3)}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
7273
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.28", type: FormulaEditorComponent, isStandalone: true, selector: "fb-formula-editor", inputs: { expression: { classPropertyName: "expression", publicName: "expression", isSignal: true, isRequired: false, transformFunction: null }, usage: { classPropertyName: "usage", publicName: "usage", isSignal: true, isRequired: false, transformFunction: null }, expectedDataType: { classPropertyName: "expectedDataType", publicName: "expectedDataType", isSignal: true, isRequired: false, transformFunction: null }, scale: { classPropertyName: "scale", publicName: "scale", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, rows: { classPropertyName: "rows", publicName: "rows", isSignal: true, isRequired: false, transformFunction: null }, commitOn: { classPropertyName: "commitOn", publicName: "commitOn", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { expressionChange: "expressionChange" }, viewQueries: [{ propertyName: "area", first: true, predicate: ["area"], descendants: true, isSignal: true }], ngImport: i0, template: "@if (hasPalette()) {\r\n <!--\r\n La palette compare **solo** se il motore dichiara delle funzioni (\u00A76.3): elenco vuoto\r\n significa \u00ABnon le dichiara\u00BB, e un pannello vuoto farebbe credere che non ce ne siano.\r\n -->\r\n <div class=\"fb-formula__bar\">\r\n <button\r\n type=\"button\"\r\n class=\"fb-formula__toggle\"\r\n [class.fb-formula__toggle--on]=\"isPaletteOpen()\"\r\n [disabled]=\"disabled()\"\r\n [attr.aria-expanded]=\"isPaletteOpen()\"\r\n title=\"Funzioni disponibili nel motore\"\r\n (click)=\"togglePalette()\"\r\n >\r\n <em>f</em>(x) Funzioni\r\n </button>\r\n </div>\r\n}\r\n\r\n<textarea\r\n #area\r\n class=\"fb-textarea fb-input--mono\"\r\n [class.fb-input--invalid]=\"hasErrors()\"\r\n [value]=\"expression()\"\r\n [rows]=\"rows()\"\r\n [disabled]=\"disabled()\"\r\n [placeholder]=\"placeholder()\"\r\n [attr.aria-label]=\"ariaLabel()\"\r\n (input)=\"onInput($any($event.target).value)\"\r\n (change)=\"onCommit($any($event.target).value)\"\r\n (focus)=\"onFocus()\"\r\n (blur)=\"onBlur()\"\r\n (keydown)=\"onKeyDown($event)\"\r\n (keyup)=\"onCaretMove()\"\r\n (click)=\"onCaretMove()\"\r\n></textarea>\r\n\r\n@if (suggestions().length) {\r\n <!--\r\n L'elenco dei riferimenti disponibili come autocompletamento (\u00A76.3): stessa fonte del\r\n reference picker, `POST /flows/references`, output automatici compresi. `mousedown` va\r\n fermato \u2014 il blur della casella arriverebbe prima del click e chiuderebbe l'elenco.\r\n -->\r\n <ul class=\"fb-formula__hints\" role=\"listbox\" aria-label=\"Riferimenti disponibili\">\r\n @for (reference of suggestions(); track reference.name) {\r\n <li>\r\n <button\r\n type=\"button\"\r\n class=\"fb-formula__hint\"\r\n [class.fb-formula__hint--on]=\"$index === highlighted()\"\r\n role=\"option\"\r\n [attr.aria-selected]=\"$index === highlighted()\"\r\n (mousedown)=\"$event.preventDefault()\"\r\n (click)=\"insert(reference.name)\"\r\n >\r\n <code>{{ reference.name }}</code>\r\n @if (reference.dataType) {\r\n <span class=\"fb-formula__hint-type\">\r\n {{ reference.dataType }}{{ reference.isCollection ? '[]' : '' }}\r\n </span>\r\n }\r\n </button>\r\n </li>\r\n }\r\n </ul>\r\n}\r\n\r\n@if (hasPalette() && isPaletteOpen()) {\r\n <div class=\"fb-formula__palette\">\r\n <input\r\n type=\"search\"\r\n class=\"fb-input fb-formula__search\"\r\n placeholder=\"Cerca una funzione\u2026\"\r\n aria-label=\"Cerca una funzione\"\r\n [value]=\"paletteFilter()\"\r\n (input)=\"paletteFilter.set($any($event.target).value)\"\r\n />\r\n @if (paletteGroups().length) {\r\n @for (group of paletteGroups(); track $index) {\r\n <div class=\"fb-formula__group\">\r\n @if (group.category) {\r\n <h5 class=\"fb-formula__group-title\">{{ group.category }}</h5>\r\n }\r\n @for (entry of group.items; track entry.name) {\r\n <!--\r\n `mousedown` fermato come nei suggerimenti: il blur della casella arriverebbe prima\r\n del click. `signature` e `description` si mostrano e non si parsano \u2014 la grammatica\r\n resta del motore (\u00A76.3).\r\n -->\r\n <button\r\n type=\"button\"\r\n class=\"fb-formula__fn\"\r\n [disabled]=\"disabled()\"\r\n (mousedown)=\"$event.preventDefault()\"\r\n (click)=\"insertFunction(entry)\"\r\n >\r\n <code class=\"fb-formula__fn-sig\">{{ signatureOf(entry) }}</code>\r\n @if (entry.resultDataType) {\r\n <span class=\"fb-formula__fn-type\">\r\n {{ entry.resultDataType }}{{ entry.isCollection ? '[]' : '' }}\r\n </span>\r\n }\r\n @if (entry.description) {\r\n <span class=\"fb-formula__fn-desc\">{{ entry.description }}</span>\r\n }\r\n @if (entry.example) {\r\n <code class=\"fb-formula__fn-example\">{{ entry.example }}</code>\r\n }\r\n </button>\r\n }\r\n </div>\r\n }\r\n } @else {\r\n <p class=\"fb-field__hint\">Nessuna funzione corrisponde alla ricerca.</p>\r\n }\r\n <!--\r\n L'elenco non e\u2019 autoritativo: un motore puo\u2019 supportare piu\u2019 di quanto dichiara, quindi una\r\n funzione che non c\u2019e\u2019 non e\u2019 un errore (\u00A76.3).\r\n -->\r\n <p class=\"fb-field__hint\">\r\n Elenco dichiarato dal motore: puo\u2019 non essere completo. A verificare l\u2019espressione resta il\r\n motore stesso.\r\n </p>\r\n </div>\r\n}\r\n\r\n@if (isChecking()) {\r\n <p class=\"fb-field__hint\">Verifica in corso\u2026</p>\r\n} @else if (issues().length) {\r\n <ul class=\"fb-formula__issues\">\r\n @for (issue of issues(); track $index) {\r\n <li class=\"fb-formula__issue\" [class]=\"'fb-formula__issue--' + severityOf(issue)\">\r\n @if (hasPosition(issue)) {\r\n <!--\r\n Il salto e' il senso di `position`: un indice di carattere che l'utente dovrebbe\r\n contare a mano non porta da nessuna parte.\r\n -->\r\n <button\r\n type=\"button\"\r\n class=\"fb-formula__jump\"\r\n [disabled]=\"disabled()\"\r\n title=\"Seleziona il tratto segnalato\"\r\n (click)=\"goToIssue(issue)\"\r\n >\r\n @if (excerptOf(issue)) {\r\n <code>{{ excerptOf(issue) }}</code>\r\n } @else {\r\n car. {{ issue.position! + 1 }}\r\n }\r\n </button>\r\n }\r\n <span class=\"fb-formula__message\">{{ issue.message }}</span>\r\n <!-- Codice del motore, non della \u00A77: si mostra e non si interpreta. -->\r\n <code class=\"fb-formula__code\">{{ issue.code }}</code>\r\n </li>\r\n }\r\n </ul>\r\n} @else if (isConfirmed()) {\r\n <p class=\"fb-formula__ok\">\u2713 Espressione verificata dal motore.</p>\r\n} @else if (isUnverified()) {\r\n <!--\r\n Primitiva s\u00EC, motore no: nessun rilievo **e** nessuna conferma. Dirlo e' l'unico modo di\r\n non far leggere il silenzio come un via libera (\u00A76.3).\r\n -->\r\n <p class=\"fb-field__hint fb-field__hint--warn\">\r\n Nessun motore di validazione delle formule e\u2019 configurato: l\u2019espressione non e\u2019 stata\r\n controllata.\r\n </p>\r\n}\r\n\r\n@if (typeMismatch(); as mismatch) {\r\n <p class=\"fb-field__hint fb-field__hint--warn\">\r\n L\u2019espressione produce {{ mismatch.produced }}, ma qui serve {{ mismatch.expected }}.\r\n </p>\r\n}\r\n\r\n<ng-content />\r\n", styles: [":host{display:flex;flex-direction:column;gap:4px}.fb-formula__issues{display:flex;flex-direction:column;gap:3px;margin:0;padding:0;list-style:none}.fb-formula__issue{display:flex;flex-wrap:wrap;gap:5px;align-items:baseline;padding:3px 6px;border-left:3px solid var(--fb-border, #d6dae1);border-radius:3px;background:var(--fb-surface-alt, #f8f9fb);font-size:10px;line-height:1.45}.fb-formula__issue--Error{border-left-color:var(--fb-error, #c9372c);color:var(--fb-error, #c9372c)}.fb-formula__issue--Warning{border-left-color:var(--fb-warning, #b7791f);color:var(--fb-warning, #b7791f)}.fb-formula__issue--Info{border-left-color:var(--fb-accent, #2f6feb);color:var(--fb-text-muted, #667085)}.fb-formula__message{flex:1 1 auto;min-width:0}.fb-formula__jump{padding:0 4px;border:1px solid currentcolor;border-radius:3px;background:transparent;color:inherit;font:inherit;font-size:10px;cursor:pointer}.fb-formula__jump:disabled{opacity:.5;cursor:not-allowed}.fb-formula__jump code{font-family:ui-monospace,SFMono-Regular,Menlo,monospace}.fb-formula__code{color:var(--fb-text-subtle, #98a2b3);font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:9px}.fb-formula__ok{margin:0;font-size:10px;color:var(--fb-success, #22a06b)}.fb-formula__hints{display:flex;flex-direction:column;gap:1px;max-height:160px;margin:0;padding:2px;overflow-y:auto;border:1px solid var(--fb-border, #d6dae1);border-radius:4px;background:var(--fb-surface, #fff);list-style:none}.fb-formula__hint{display:flex;gap:6px;align-items:baseline;width:100%;padding:2px 5px;border:0;border-radius:3px;background:transparent;color:var(--fb-text, #1d2939);font:inherit;font-size:10px;text-align:left;cursor:pointer}.fb-formula__hint:hover,.fb-formula__hint--on{background:color-mix(in srgb,var(--fb-accent, #2f6feb) 10%,transparent)}.fb-formula__hint code{font-family:ui-monospace,SFMono-Regular,Menlo,monospace}.fb-formula__hint-type{margin-left:auto;color:var(--fb-text-subtle, #98a2b3)}.fb-formula__bar{display:flex;justify-content:flex-end}.fb-formula__toggle{padding:1px 6px;border:1px solid var(--fb-border, #d6dae1);border-radius:3px;background:var(--fb-surface, #fff);color:var(--fb-text-muted, #667085);font:inherit;font-size:10px;cursor:pointer}.fb-formula__toggle em{font-family:ui-serif,Georgia,serif}.fb-formula__toggle--on{border-color:var(--fb-accent, #2f6feb);color:var(--fb-accent, #2f6feb)}.fb-formula__toggle:disabled{opacity:.5;cursor:not-allowed}.fb-formula__palette{display:flex;flex-direction:column;gap:4px;max-height:220px;padding:4px;overflow-y:auto;border:1px solid var(--fb-border, #d6dae1);border-radius:4px;background:var(--fb-surface-alt, #f8f9fb)}.fb-formula__search{font-size:10px}.fb-formula__group{display:flex;flex-direction:column;gap:2px}.fb-formula__group-title{margin:2px 0 0;color:var(--fb-text-subtle, #98a2b3);font-size:9px;font-weight:600;text-transform:uppercase;letter-spacing:.04em}.fb-formula__fn{display:grid;grid-template-columns:1fr auto;gap:0 6px;padding:3px 5px;border:0;border-radius:3px;background:var(--fb-surface, #fff);color:var(--fb-text, #1d2939);font:inherit;font-size:10px;text-align:left;cursor:pointer}.fb-formula__fn:hover{background:color-mix(in srgb,var(--fb-accent, #2f6feb) 10%,transparent)}.fb-formula__fn:disabled{opacity:.5;cursor:not-allowed}.fb-formula__fn-sig{font-family:ui-monospace,SFMono-Regular,Menlo,monospace}.fb-formula__fn-type{color:var(--fb-text-subtle, #98a2b3)}.fb-formula__fn-desc,.fb-formula__fn-example{grid-column:1 / -1;color:var(--fb-text-muted, #667085);font-size:9px;line-height:1.4}.fb-formula__fn-example{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;color:var(--fb-text-subtle, #98a2b3)}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
7133
7274
|
}
|
|
7134
7275
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.28", ngImport: i0, type: FormulaEditorComponent, decorators: [{
|
|
7135
7276
|
type: Component,
|
|
7136
|
-
args: [{ selector: 'fb-formula-editor', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: "<textarea\r\n #area\r\n class=\"fb-textarea fb-input--mono\"\r\n [class.fb-input--invalid]=\"hasErrors()\"\r\n [value]=\"expression()\"\r\n [rows]=\"rows()\"\r\n [disabled]=\"disabled()\"\r\n [placeholder]=\"placeholder()\"\r\n [attr.aria-label]=\"ariaLabel()\"\r\n (input)=\"onInput($any($event.target).value)\"\r\n (change)=\"onCommit($any($event.target).value)\"\r\n (focus)=\"onFocus()\"\r\n (blur)=\"onBlur()\"\r\n (keydown)=\"onKeyDown($event)\"\r\n (keyup)=\"onCaretMove()\"\r\n (click)=\"onCaretMove()\"\r\n></textarea>\r\n\r\n@if (suggestions().length) {\r\n <!--\r\n L'elenco dei riferimenti disponibili come autocompletamento (\u00A76.3): stessa fonte del\r\n reference picker, `POST /flows/references`, output automatici compresi. `mousedown` va\r\n fermato \u2014 il blur della casella arriverebbe prima del click e chiuderebbe l'elenco.\r\n -->\r\n <ul class=\"fb-formula__hints\" role=\"listbox\" aria-label=\"Riferimenti disponibili\">\r\n @for (reference of suggestions(); track reference.name) {\r\n <li>\r\n <button\r\n type=\"button\"\r\n class=\"fb-formula__hint\"\r\n [class.fb-formula__hint--on]=\"$index === highlighted()\"\r\n role=\"option\"\r\n [attr.aria-selected]=\"$index === highlighted()\"\r\n (mousedown)=\"$event.preventDefault()\"\r\n (click)=\"insert(reference.name)\"\r\n >\r\n <code>{{ reference.name }}</code>\r\n @if (reference.dataType) {\r\n <span class=\"fb-formula__hint-type\">\r\n {{ reference.dataType }}{{ reference.isCollection ? '[]' : '' }}\r\n </span>\r\n }\r\n </button>\r\n </li>\r\n }\r\n </ul>\r\n}\r\n\r\n@if (isChecking()) {\r\n <p class=\"fb-field__hint\">Verifica in corso\u2026</p>\r\n} @else if (issues().length) {\r\n <ul class=\"fb-formula__issues\">\r\n @for (issue of issues(); track $index) {\r\n <li class=\"fb-formula__issue\" [class]=\"'fb-formula__issue--' + severityOf(issue)\">\r\n @if (hasPosition(issue)) {\r\n <!--\r\n Il salto e' il senso di `position`: un indice di carattere che l'utente dovrebbe\r\n contare a mano non porta da nessuna parte.\r\n -->\r\n <button\r\n type=\"button\"\r\n class=\"fb-formula__jump\"\r\n [disabled]=\"disabled()\"\r\n title=\"Seleziona il tratto segnalato\"\r\n (click)=\"goToIssue(issue)\"\r\n >\r\n @if (excerptOf(issue)) {\r\n <code>{{ excerptOf(issue) }}</code>\r\n } @else {\r\n car. {{ issue.position! + 1 }}\r\n }\r\n </button>\r\n }\r\n <span class=\"fb-formula__message\">{{ issue.message }}</span>\r\n <!-- Codice del motore, non della \u00A77: si mostra e non si interpreta. -->\r\n <code class=\"fb-formula__code\">{{ issue.code }}</code>\r\n </li>\r\n }\r\n </ul>\r\n} @else if (isConfirmed()) {\r\n <p class=\"fb-formula__ok\">\u2713 Espressione verificata dal motore.</p>\r\n} @else if (isUnverified()) {\r\n <!--\r\n Primitiva s\u00EC, motore no: nessun rilievo **e** nessuna conferma. Dirlo e' l'unico modo di\r\n non far leggere il silenzio come un via libera (\u00A76.3).\r\n -->\r\n <p class=\"fb-field__hint fb-field__hint--warn\">\r\n Nessun motore di validazione delle formule e\u2019 configurato: l\u2019espressione non e\u2019 stata\r\n controllata.\r\n </p>\r\n}\r\n\r\n@if (typeMismatch(); as mismatch) {\r\n <p class=\"fb-field__hint fb-field__hint--warn\">\r\n L\u2019espressione produce {{ mismatch.produced }}, ma qui serve {{ mismatch.expected }}.\r\n </p>\r\n}\r\n\r\n<ng-content />\r\n", styles: [":host{display:flex;flex-direction:column;gap:4px}.fb-formula__issues{display:flex;flex-direction:column;gap:3px;margin:0;padding:0;list-style:none}.fb-formula__issue{display:flex;flex-wrap:wrap;gap:5px;align-items:baseline;padding:3px 6px;border-left:3px solid var(--fb-border, #d6dae1);border-radius:3px;background:var(--fb-surface-alt, #f8f9fb);font-size:10px;line-height:1.45}.fb-formula__issue--Error{border-left-color:var(--fb-error, #c9372c);color:var(--fb-error, #c9372c)}.fb-formula__issue--Warning{border-left-color:var(--fb-warning, #b7791f);color:var(--fb-warning, #b7791f)}.fb-formula__issue--Info{border-left-color:var(--fb-accent, #2f6feb);color:var(--fb-text-muted, #667085)}.fb-formula__message{flex:1 1 auto;min-width:0}.fb-formula__jump{padding:0 4px;border:1px solid currentcolor;border-radius:3px;background:transparent;color:inherit;font:inherit;font-size:10px;cursor:pointer}.fb-formula__jump:disabled{opacity:.5;cursor:not-allowed}.fb-formula__jump code{font-family:ui-monospace,SFMono-Regular,Menlo,monospace}.fb-formula__code{color:var(--fb-text-subtle, #98a2b3);font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:9px}.fb-formula__ok{margin:0;font-size:10px;color:var(--fb-success, #22a06b)}.fb-formula__hints{display:flex;flex-direction:column;gap:1px;max-height:160px;margin:0;padding:2px;overflow-y:auto;border:1px solid var(--fb-border, #d6dae1);border-radius:4px;background:var(--fb-surface, #fff);list-style:none}.fb-formula__hint{display:flex;gap:6px;align-items:baseline;width:100%;padding:2px 5px;border:0;border-radius:3px;background:transparent;color:var(--fb-text, #1d2939);font:inherit;font-size:10px;text-align:left;cursor:pointer}.fb-formula__hint:hover,.fb-formula__hint--on{background:color-mix(in srgb,var(--fb-accent, #2f6feb) 10%,transparent)}.fb-formula__hint code{font-family:ui-monospace,SFMono-Regular,Menlo,monospace}.fb-formula__hint-type{margin-left:auto;color:var(--fb-text-subtle, #98a2b3)}\n"] }]
|
|
7277
|
+
args: [{ selector: 'fb-formula-editor', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: "@if (hasPalette()) {\r\n <!--\r\n La palette compare **solo** se il motore dichiara delle funzioni (\u00A76.3): elenco vuoto\r\n significa \u00ABnon le dichiara\u00BB, e un pannello vuoto farebbe credere che non ce ne siano.\r\n -->\r\n <div class=\"fb-formula__bar\">\r\n <button\r\n type=\"button\"\r\n class=\"fb-formula__toggle\"\r\n [class.fb-formula__toggle--on]=\"isPaletteOpen()\"\r\n [disabled]=\"disabled()\"\r\n [attr.aria-expanded]=\"isPaletteOpen()\"\r\n title=\"Funzioni disponibili nel motore\"\r\n (click)=\"togglePalette()\"\r\n >\r\n <em>f</em>(x) Funzioni\r\n </button>\r\n </div>\r\n}\r\n\r\n<textarea\r\n #area\r\n class=\"fb-textarea fb-input--mono\"\r\n [class.fb-input--invalid]=\"hasErrors()\"\r\n [value]=\"expression()\"\r\n [rows]=\"rows()\"\r\n [disabled]=\"disabled()\"\r\n [placeholder]=\"placeholder()\"\r\n [attr.aria-label]=\"ariaLabel()\"\r\n (input)=\"onInput($any($event.target).value)\"\r\n (change)=\"onCommit($any($event.target).value)\"\r\n (focus)=\"onFocus()\"\r\n (blur)=\"onBlur()\"\r\n (keydown)=\"onKeyDown($event)\"\r\n (keyup)=\"onCaretMove()\"\r\n (click)=\"onCaretMove()\"\r\n></textarea>\r\n\r\n@if (suggestions().length) {\r\n <!--\r\n L'elenco dei riferimenti disponibili come autocompletamento (\u00A76.3): stessa fonte del\r\n reference picker, `POST /flows/references`, output automatici compresi. `mousedown` va\r\n fermato \u2014 il blur della casella arriverebbe prima del click e chiuderebbe l'elenco.\r\n -->\r\n <ul class=\"fb-formula__hints\" role=\"listbox\" aria-label=\"Riferimenti disponibili\">\r\n @for (reference of suggestions(); track reference.name) {\r\n <li>\r\n <button\r\n type=\"button\"\r\n class=\"fb-formula__hint\"\r\n [class.fb-formula__hint--on]=\"$index === highlighted()\"\r\n role=\"option\"\r\n [attr.aria-selected]=\"$index === highlighted()\"\r\n (mousedown)=\"$event.preventDefault()\"\r\n (click)=\"insert(reference.name)\"\r\n >\r\n <code>{{ reference.name }}</code>\r\n @if (reference.dataType) {\r\n <span class=\"fb-formula__hint-type\">\r\n {{ reference.dataType }}{{ reference.isCollection ? '[]' : '' }}\r\n </span>\r\n }\r\n </button>\r\n </li>\r\n }\r\n </ul>\r\n}\r\n\r\n@if (hasPalette() && isPaletteOpen()) {\r\n <div class=\"fb-formula__palette\">\r\n <input\r\n type=\"search\"\r\n class=\"fb-input fb-formula__search\"\r\n placeholder=\"Cerca una funzione\u2026\"\r\n aria-label=\"Cerca una funzione\"\r\n [value]=\"paletteFilter()\"\r\n (input)=\"paletteFilter.set($any($event.target).value)\"\r\n />\r\n @if (paletteGroups().length) {\r\n @for (group of paletteGroups(); track $index) {\r\n <div class=\"fb-formula__group\">\r\n @if (group.category) {\r\n <h5 class=\"fb-formula__group-title\">{{ group.category }}</h5>\r\n }\r\n @for (entry of group.items; track entry.name) {\r\n <!--\r\n `mousedown` fermato come nei suggerimenti: il blur della casella arriverebbe prima\r\n del click. `signature` e `description` si mostrano e non si parsano \u2014 la grammatica\r\n resta del motore (\u00A76.3).\r\n -->\r\n <button\r\n type=\"button\"\r\n class=\"fb-formula__fn\"\r\n [disabled]=\"disabled()\"\r\n (mousedown)=\"$event.preventDefault()\"\r\n (click)=\"insertFunction(entry)\"\r\n >\r\n <code class=\"fb-formula__fn-sig\">{{ signatureOf(entry) }}</code>\r\n @if (entry.resultDataType) {\r\n <span class=\"fb-formula__fn-type\">\r\n {{ entry.resultDataType }}{{ entry.isCollection ? '[]' : '' }}\r\n </span>\r\n }\r\n @if (entry.description) {\r\n <span class=\"fb-formula__fn-desc\">{{ entry.description }}</span>\r\n }\r\n @if (entry.example) {\r\n <code class=\"fb-formula__fn-example\">{{ entry.example }}</code>\r\n }\r\n </button>\r\n }\r\n </div>\r\n }\r\n } @else {\r\n <p class=\"fb-field__hint\">Nessuna funzione corrisponde alla ricerca.</p>\r\n }\r\n <!--\r\n L'elenco non e\u2019 autoritativo: un motore puo\u2019 supportare piu\u2019 di quanto dichiara, quindi una\r\n funzione che non c\u2019e\u2019 non e\u2019 un errore (\u00A76.3).\r\n -->\r\n <p class=\"fb-field__hint\">\r\n Elenco dichiarato dal motore: puo\u2019 non essere completo. A verificare l\u2019espressione resta il\r\n motore stesso.\r\n </p>\r\n </div>\r\n}\r\n\r\n@if (isChecking()) {\r\n <p class=\"fb-field__hint\">Verifica in corso\u2026</p>\r\n} @else if (issues().length) {\r\n <ul class=\"fb-formula__issues\">\r\n @for (issue of issues(); track $index) {\r\n <li class=\"fb-formula__issue\" [class]=\"'fb-formula__issue--' + severityOf(issue)\">\r\n @if (hasPosition(issue)) {\r\n <!--\r\n Il salto e' il senso di `position`: un indice di carattere che l'utente dovrebbe\r\n contare a mano non porta da nessuna parte.\r\n -->\r\n <button\r\n type=\"button\"\r\n class=\"fb-formula__jump\"\r\n [disabled]=\"disabled()\"\r\n title=\"Seleziona il tratto segnalato\"\r\n (click)=\"goToIssue(issue)\"\r\n >\r\n @if (excerptOf(issue)) {\r\n <code>{{ excerptOf(issue) }}</code>\r\n } @else {\r\n car. {{ issue.position! + 1 }}\r\n }\r\n </button>\r\n }\r\n <span class=\"fb-formula__message\">{{ issue.message }}</span>\r\n <!-- Codice del motore, non della \u00A77: si mostra e non si interpreta. -->\r\n <code class=\"fb-formula__code\">{{ issue.code }}</code>\r\n </li>\r\n }\r\n </ul>\r\n} @else if (isConfirmed()) {\r\n <p class=\"fb-formula__ok\">\u2713 Espressione verificata dal motore.</p>\r\n} @else if (isUnverified()) {\r\n <!--\r\n Primitiva s\u00EC, motore no: nessun rilievo **e** nessuna conferma. Dirlo e' l'unico modo di\r\n non far leggere il silenzio come un via libera (\u00A76.3).\r\n -->\r\n <p class=\"fb-field__hint fb-field__hint--warn\">\r\n Nessun motore di validazione delle formule e\u2019 configurato: l\u2019espressione non e\u2019 stata\r\n controllata.\r\n </p>\r\n}\r\n\r\n@if (typeMismatch(); as mismatch) {\r\n <p class=\"fb-field__hint fb-field__hint--warn\">\r\n L\u2019espressione produce {{ mismatch.produced }}, ma qui serve {{ mismatch.expected }}.\r\n </p>\r\n}\r\n\r\n<ng-content />\r\n", styles: [":host{display:flex;flex-direction:column;gap:4px}.fb-formula__issues{display:flex;flex-direction:column;gap:3px;margin:0;padding:0;list-style:none}.fb-formula__issue{display:flex;flex-wrap:wrap;gap:5px;align-items:baseline;padding:3px 6px;border-left:3px solid var(--fb-border, #d6dae1);border-radius:3px;background:var(--fb-surface-alt, #f8f9fb);font-size:10px;line-height:1.45}.fb-formula__issue--Error{border-left-color:var(--fb-error, #c9372c);color:var(--fb-error, #c9372c)}.fb-formula__issue--Warning{border-left-color:var(--fb-warning, #b7791f);color:var(--fb-warning, #b7791f)}.fb-formula__issue--Info{border-left-color:var(--fb-accent, #2f6feb);color:var(--fb-text-muted, #667085)}.fb-formula__message{flex:1 1 auto;min-width:0}.fb-formula__jump{padding:0 4px;border:1px solid currentcolor;border-radius:3px;background:transparent;color:inherit;font:inherit;font-size:10px;cursor:pointer}.fb-formula__jump:disabled{opacity:.5;cursor:not-allowed}.fb-formula__jump code{font-family:ui-monospace,SFMono-Regular,Menlo,monospace}.fb-formula__code{color:var(--fb-text-subtle, #98a2b3);font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:9px}.fb-formula__ok{margin:0;font-size:10px;color:var(--fb-success, #22a06b)}.fb-formula__hints{display:flex;flex-direction:column;gap:1px;max-height:160px;margin:0;padding:2px;overflow-y:auto;border:1px solid var(--fb-border, #d6dae1);border-radius:4px;background:var(--fb-surface, #fff);list-style:none}.fb-formula__hint{display:flex;gap:6px;align-items:baseline;width:100%;padding:2px 5px;border:0;border-radius:3px;background:transparent;color:var(--fb-text, #1d2939);font:inherit;font-size:10px;text-align:left;cursor:pointer}.fb-formula__hint:hover,.fb-formula__hint--on{background:color-mix(in srgb,var(--fb-accent, #2f6feb) 10%,transparent)}.fb-formula__hint code{font-family:ui-monospace,SFMono-Regular,Menlo,monospace}.fb-formula__hint-type{margin-left:auto;color:var(--fb-text-subtle, #98a2b3)}.fb-formula__bar{display:flex;justify-content:flex-end}.fb-formula__toggle{padding:1px 6px;border:1px solid var(--fb-border, #d6dae1);border-radius:3px;background:var(--fb-surface, #fff);color:var(--fb-text-muted, #667085);font:inherit;font-size:10px;cursor:pointer}.fb-formula__toggle em{font-family:ui-serif,Georgia,serif}.fb-formula__toggle--on{border-color:var(--fb-accent, #2f6feb);color:var(--fb-accent, #2f6feb)}.fb-formula__toggle:disabled{opacity:.5;cursor:not-allowed}.fb-formula__palette{display:flex;flex-direction:column;gap:4px;max-height:220px;padding:4px;overflow-y:auto;border:1px solid var(--fb-border, #d6dae1);border-radius:4px;background:var(--fb-surface-alt, #f8f9fb)}.fb-formula__search{font-size:10px}.fb-formula__group{display:flex;flex-direction:column;gap:2px}.fb-formula__group-title{margin:2px 0 0;color:var(--fb-text-subtle, #98a2b3);font-size:9px;font-weight:600;text-transform:uppercase;letter-spacing:.04em}.fb-formula__fn{display:grid;grid-template-columns:1fr auto;gap:0 6px;padding:3px 5px;border:0;border-radius:3px;background:var(--fb-surface, #fff);color:var(--fb-text, #1d2939);font:inherit;font-size:10px;text-align:left;cursor:pointer}.fb-formula__fn:hover{background:color-mix(in srgb,var(--fb-accent, #2f6feb) 10%,transparent)}.fb-formula__fn:disabled{opacity:.5;cursor:not-allowed}.fb-formula__fn-sig{font-family:ui-monospace,SFMono-Regular,Menlo,monospace}.fb-formula__fn-type{color:var(--fb-text-subtle, #98a2b3)}.fb-formula__fn-desc,.fb-formula__fn-example{grid-column:1 / -1;color:var(--fb-text-muted, #667085);font-size:9px;line-height:1.4}.fb-formula__fn-example{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;color:var(--fb-text-subtle, #98a2b3)}\n"] }]
|
|
7137
7278
|
}], ctorParameters: () => [], propDecorators: { expression: [{ type: i0.Input, args: [{ isSignal: true, alias: "expression", required: false }] }], usage: [{ type: i0.Input, args: [{ isSignal: true, alias: "usage", required: false }] }], expectedDataType: [{ type: i0.Input, args: [{ isSignal: true, alias: "expectedDataType", required: false }] }], scale: [{ type: i0.Input, args: [{ isSignal: true, alias: "scale", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], rows: [{ type: i0.Input, args: [{ isSignal: true, alias: "rows", required: false }] }], commitOn: [{ type: i0.Input, args: [{ isSignal: true, alias: "commitOn", required: false }] }], expressionChange: [{ type: i0.Output, args: ["expressionChange"] }], area: [{ type: i0.ViewChild, args: ['area', { isSignal: true }] }] } });
|
|
7138
7279
|
|
|
7139
7280
|
/**
|