@arsedizioni/ars-utils
v22.6.83
Published
Common tools and standalone components shared among ARS Edizioni Angular based web applications.
Downloads
22,722
Readme
ARS Utils
Common tools and standalone components shared among ARS Edizioni Angular based web applications.
Rispetto alla versione monolitica precedente adotta la struttura a entry point
introdotta con @fabio.buscaroli/scm-utils: code splitting e tree shaking sono il criterio di
ripartizione dei simboli, non un effetto collaterale.
Platform
Angular 22 + Material
Entry points
La libreria non espone un barrel unico: l'entry point secondario e' l'unica unita' di code splitting riconosciuta da ng-packagr, quindi ogni gruppo di simboli che ha un ciclo di vita proprio vive nel suo entry point. Importare sempre dal path specifico.
Nucleo condiviso
| Livello | Entry point | Contenuto | Note |
|---|---|---|---|
| L0 | core | SystemUtils, models, definitions, pipe, direttive validator, servizi (broadcast, screen, theme, splash, environment), LoginOAuthType | nessuna dipendenza da Angular Material |
| L0 | core.date | provideArsDateFns, provideArsLocalDates, MAT_DATE_FNS_FORMATS, arsLocalDateInterceptor, ARS_TIME_ZONE | isola @angular/material/core + datepicker |
| L0 | core.markdown | MarkdownUtils, FormatMarkdownPipe | parser markdown, fuori dal percorso comune |
| L0 | core.validators | direttive validator per i form template-driven (ValidatorDirective, ValidIfDirective, EqualsValidatorDirective, PasswordValidatorDirective, EmailsValidatorDirective, ...) | isola @angular/forms (53 KB): core sta sul percorso di boot e non deve trascinarselo |
| L0.5 | ui.shell | ShellService (info, error, busy*, wait, BusyTimer), ShellMessageComponent, ShellBusyComponent | zero Material e zero CDK: e' quello che shell, interceptor, guard e app initializer possono permettersi sul percorso di boot |
| L1 | ui | FlexLayoutModule, MediaObserver, UIService, tipi dei dialog | kernel: deve restare magro, e non importa nulla da Material |
| L1 | ui.paginator | PaginatorIntl | isola @angular/material/paginator, che si porta dietro mat-select e mat-option |
| L1.5 | ui.dialogs | DialogService (estende ShellService) + confirm, delete, toast, open, e le aperture pigre dei dialog pesanti | tutto cio' che chiede qualcosa all'utente, piu' il toast |
| L2 | ui.dialogs.auth | credentials, reset-password, recover-password, prompt-otp, OtpInputComponent, PasswordStrengthComponent | solo route di login/account |
| L2 | ui.dialogs.prompt | prompt, prompt-date, prompt-time | porta @angular/material/datepicker |
| L2 | ui.dialogs.select | select, select-tree, send-to | porta mat-tree, mat-list, mat-chips |
| L2 | ui.files | file-input, file-preview, select-file, select-picture | |
| L2 | ui.controls | button-selector, button-toggle, chips-selector | base Material comune: button, icon, form-field |
| L2 | ui.controls.date | MatDatepickerParseErrorFixDirective, CalendarEmptyHeader | isola @angular/material/datepicker: ui.dialogs.prompt aggancia solo questo |
| L2 | ui.controls.tree | TreePickerComponent | isola mat-tree, mat-tabs, mat-input, mat-checkbox, che nessun altro controllo usa |
| L2 | ui.filters | FilterBarComponent + modello Filters | |
| L2 | ui.navigation | NavigationBarComponent + definizioni | shell applicativa |
Specifici ARS
| Livello | Entry point | Contenuto | Dipendenze pesanti |
|---|---|---|---|
| L0.5 | support.common | SupportService, notifiche, definitions, messages | - |
| L0.5 | evolution.common | EvolutionService, account, compliance, login, interceptor auth | - |
| L2 | ui.oauth | LoginOAuthComponent, LoginOAuthOkMSComponent | @azure/msal-angular, @azure/msal-browser |
| L2 | ui.help | HelpService, HelpViewerComponent, modello dei capitoli | - |
| L2 | ui.tinymce | TinymceEditorDirective, TinymceLoaderService, TinymceUtils, TinyMceEditorComponent, langs/it.js | tinymce (caricato a runtime) |
| L2 | ui.notifications | NotificationsBrowserComponent (ex support.ui) | - |
| L2 | clipper.common | ClipperService, documents, login, canali e contatori non letti, interceptor auth | solo il necessario a consultare i documenti |
| L4 | clipper.ui | browser, document, references, search-* e ClipperDocumentUtilsService | clipper.scss |
I peer dependency opzionali (@azure/msal-*, tinymce) servono
solo a chi importa rispettivamente ui.oauth e ui.tinymce: sono dichiarati in
peerDependenciesMeta.optional proprio perche' nessun altro entry point li aggancia.
Grafo delle dipendenze statiche
core core.date core.markdown core.validators ui.paginator ui.controls.date
| \
| ui.shell
| |
ui ------|-----------------------------------------------------------
| | | | | | | |
| | ui.controls ui.controls.tree ui.filters ui.navigation ui.dialogs.select clipper.common
| |
ui.dialogs <-- DialogService extends ShellService: dipende da `ui` E da `ui.shell`
| | | | | |
| ui.dialogs.auth ui.dialogs.prompt ui.files ui.help ui.oauth
| ui.notifications (+ support.common)
clipper.ui (+ clipper.common, ui.controls, ui.controls.date, ui.files, ui.dialogs.select)
`ui.dialogs` --- import() ---> ui.dialogs.{auth,prompt,select}, ui.files
Gli archi dinamici puntano all'insu' e sono l'unica ragione per cui quei quattro entry point
restano fuori dal bundle iniziale. Regge finche' NESSUNO di loro importa `DialogService`: per
`error()` e `busy()` iniettano `ShellService`.
`ui.controls.date` non dipende da nulla della libreria (solo `@angular/core` e
`@angular/material/datepicker`): e' cio' che permette al chunk di `ui.dialogs.prompt` di
agganciare la direttiva senza linkare il file di `ui.controls`.evolution.common e support.common dipendono solo da core.
Regole da rispettare
- Il grafo statico tra entry point deve restare un DAG:
ui.dialogsraggiunge i dialog pesanti solo conimport(), e quei quattro entry point non devono importareDialogServicein nessun modo — ng-packagr rifiuta la build concircular dependencyal primo che lo fa. Per messaggi e attesa iniettanoShellService, che sta sotto di loro nel grafo. - I tipi condivisi fra il facade e i dialog pesanti stanno in
ui(dialog.definitions.ts). Se un tipo servisse a entrambi e vivesse nel dialog, l'import()del facade tornerebbe statico. - Il facade usa
import typeper i tipi dei componenti eimport()per i valori: e' quello che tiene i dialog fuori dal bundle iniziale. - Dopo una modifica, verificare che gli
import()sopravvivano alla build:grep -o "import('@arsedizioni[^']*')" dist/ars-utils/fesm2022/*ui.dialogs.mjsdeve stampare i nove. ui.shellnon importa nulla da@angular/materialne' da@angular/cdk, e nemmeno daui. E' l'unica ragione per cui esiste: se ci finisce dentro un solo simbolo di Material, la shell torna a pagare l'intero stack sul percorso di boot. Da verificare dopo ogni build:grep -oE "@angular/(material|cdk)[^'\"]*" dist/ars-utils/fesm2022/*ui.shell.mjsnon deve stampare nulla.- Le sovrapposizioni di
ui.shellstanno nel top layer del browser, non nello stack del CDK. Da Angular CDK 22 ogni overlay viene aperto comepopover="manual", quindi un dialog Material non sta piu' a z-index 1000: sta nel top layer, che viene disegnato sopra tutta la pagina qualunque cosa dica lo z-index della pagina. Un numero, per quanto alto, non ci arriva sopra: per questoShellServicepromuove anche i suoi due overlay conshowPopover(). Nel top layer l'ordine e' quello di promozione, l'ultimo promosso sta sopra. Da qui le tre regole esplicite:setBusy()ripromuove il messaggio dopo aver alzato il busy,DialogService.open()chiamaraiseMessage()dopo aver aperto un dialog, e chiamaclearBusy(true)senza periodo di grazia. La coppia--ars-shell-dialog-z-index/--ars-shell-busy-z-index(1100/1090) resta valida e serve ancora: e' quello che ordina gli overlay sui browser senza Popover API, dove nemmeno il CDK la usa. Se un'applicazione avesse bisogno del vecchio comportamento puo' spegnere la Popover API del CDK con{ provide: OVERLAY_DEFAULT_CONFIG, useValue: { usePopover: false } }. uinon importa valori da Material.PaginatorIntle' uscito da li' proprio per questo: era l'unico simbolo che ne dipendeva, e faceva pagaremat-paginator+mat-select+mat-optiona chiunque toccasseui.dialogs. Restano due eccezioni, entrambe volute:MatFormFieldAppearanceindialog.definitions.ts, che e' unimport typee quindi sparisce in compilazione, e@angular/cdk/layout(1 KB) di cuiMediaObserverha bisogno.
Da dove parte un'applicazione
core + ui.shell. Sono i due entry point che una applicazione ARS carica comunque prima di
avere una rotta, e gli unici due che non costano Material. core porta SystemUtils, i modelli,
BroadcastService, SplashService, EnvironmentService, ThemeService; ui.shell porta il modo
di dire all'utente che la sessione e' scaduta o che l'API non risponde.
Non sono un entry point solo, e non devono diventarlo: core e' L0 e ci dipendono anche
clipper.common, evolution.common e support.common, che di interfaccia non ne hanno. Fonderli
significherebbe far dipendere tre entry point headless da uno di UI, cioe' rompere la regola 1.
La conseguenza pratica per chi scrive l'applicazione:
- shell, interceptor, guard,
provideAppInitializer->ShellServicediui.shell - componenti di rotta ->
DialogServicediui.dialogs, che apre anche i dialog pesanti
I tre servizi sono una catena, non tre servizi diversi:
ShellService info, error, busy*, wait, busyTimer ui.shell
└ DialogService + open, confirm, delete, toast, ui.dialogs
select, prompt, sendTo, ... (pigri)Quindi chi inietta DialogService ha tutto quello che aveva prima: info, error e busy non
sono spariti, sono ereditati. E non esistono in due copie — c'e' una implementazione sola, quella
senza Material.
ShellService.info() e ShellService.error() hanno gli stessi parametri, nello stesso ordine,
delle omonime di DialogService: spostare una chiamata dall'una all'altra e' un cambio di servizio
iniettato e nient'altro.
Differenze rispetto alla versione precedente (22.1.x monolitica)
- Nessun barrel radice:
@arsedizioni/ars-utilsesporta soloARS_UTILS_VERSION. uinon contiene piu' i dialog:DialogServicesta inui.dialogs.ui.applicationnon esiste piu': i nove metodi che apriva stanno inDialogService. I controlli sono inui.controls, i file inui.files, i filtri inui.filters, la navigazione inui.navigation.SystemUtils.markdownToHtmlnon esiste piu': usareMarkdownUtils.toHtmldacore.markdown.SelectableModelesponefirsteselectedAnyal posto diselectedFirsteselectedAll.support.uisi chiamaui.notifications,helpsi chiamaui.help,tinymcesi chiamaui.tinymce.PaginatorIntlnon sta piu' inui: sta inui.paginator.ui.tinymcenon dipende piu' da@tinymce/tinymce-angular: l'editor e' la direttiva[tinymceEditor]su una<textarea>, e TinyMCE viene caricato a runtime daTinymceLoaderService. Il componente<editor>non esiste piu'.- Le direttive validator non stanno piu' in
core: stanno incore.validators, che e' l'unico entry point del nucleo a dipendere da@angular/forms. - I token CSS della shell stanno tutti sotto
--ars-shell-dialog-*e--ars-shell-busy-*: prima erano--ars-dialog-*,--ars-scrim-color,--ars-busy-*e--ars-progress-track-color, che si confondevano con--ars-dialog-item-*, cioe' i dialog Material veri. Un'applicazione che ne sovrascriveva qualcuno deve rinominarlo. - La shell non deve piu' iniettare
DialogServiceper mostrare un errore: c'e'ShellServiceinui.shell. info,error,busy,busySpinner,busyHourglass,wait,busyTimereclearBusysono passati aShellService.DialogServiceli eredita, quindi nessuna chiamata cambia.info()eerror()restituisconoShellMessageRefinvece diMatDialogRef<InfoDialogComponent>. In myARS nessun chiamante usava quel valore; controllare nelle altre applicazioni.clearBusy()accettaimmediate:clearBusy(true)non aspetta i 500 ms di grazia.BusyTimersi importa daui.shell, non piu' daui.dialogs.InfoDialogComponenteBusyDialogComponentnon esistono piu': li sostituisconoShellMessageComponenteShellBusyComponent, senza Material.
Authors
Fabio Buscaroli, Alberto Doria
