cic-kit 0.0.8 → 0.0.9

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 CHANGED
@@ -2,29 +2,9 @@
2
2
 
3
3
  `cic-kit` è un piccolo kit di componenti e stili per **Vue 3**, pensato per essere riutilizzato tra più progetti.
4
4
 
5
- Attualmente esporta:
6
- - ✅ un componente Vue (`BtnCmp`)
7
- - ✅ uno stylesheet (`style.css`) con utility, font e override
8
- - ❌ **non** include Bootstrap o Vue Router internamente (usa quelli del progetto consumer)
9
-
10
- ---
11
-
12
- ## Installazione
13
-
14
- ```bash
15
- npm install cic-kit
16
- ```
17
-
18
- > Il progetto che usa `cic-kit` deve avere già installati:
19
- > - `vue`
20
- > - `vue-router`
21
- > - `bootstrap`
22
-
23
- ---
24
-
25
5
  ## Peer Dependencies
26
6
 
27
- Questo pacchetto **non porta con sé** queste dipendenze, ma usa quelle del progetto consumer:
7
+ Il progetto che usa `cic-kit` deve avere già installati:
28
8
 
29
9
  ```json
30
10
  {
@@ -34,29 +14,53 @@ Questo pacchetto **non porta con sé** queste dipendenze, ma usa quelle del prog
34
14
  }
35
15
  ```
36
16
 
37
- Questa è una scelta intenzionale per evitare duplicazioni e conflitti di stile.
38
-
39
17
  ---
40
18
 
41
- ## Utilizzo
19
+ ## Installazione
42
20
 
43
- ### Import dello stile
21
+ dopo aver installato le peer Dependencies
44
22
 
45
- Nel file di bootstrap dell’app (es. `main.ts`):
23
+ ```bash
24
+ npm install cic-kit
25
+ ```
46
26
 
47
- ```ts
48
- import "bootstrap/dist/css/bootstrap.css";
49
- import "cic-kit/style.css";
27
+ poi importa lo style su un scss con
28
+
29
+ ```scss
30
+ @use "cic-kit/style";
50
31
  ```
51
32
 
52
- > `style.css` include:
33
+ **non** include Bootstrap internamente bisogna importarlo prima con `@use "bootstrap/scss/bootstrap"`;
34
+
35
+ ## Style
36
+
37
+ > `_style.scss` include:
38
+ >
39
+ > - regolre di reset
53
40
  > - font custom (Material Symbols, emoji, ecc.)
54
- > - utility CSS
55
41
  > - override delle classi Bootstrap
42
+ > - utility CSS
56
43
 
57
- ---
44
+ ## Componenti
45
+
46
+ Tra i componenti ci sono file di utility .ts e componenti .vue che possono utilizzare store globali basati su reactive() per controllarli
47
+
48
+ #### BtnCmp
49
+
50
+ Button Bootstrap con varianti, icona, loading e navigazione router.
58
51
 
59
- ### Uso del componente
52
+ | prop | default | type | utilizzo |
53
+ | ---------- | -------- | ----------------------------------------------------------------------------------------------- | --------------------------- |
54
+ | `variant` | `solid` | `"solid" \| "outline" \| "ghost" \| "link"` | stile del bottone |
55
+ | `color` | `dark` | `"primary" \| "secondary" \| "success" \| "danger" \| "warning" \| "info" \| "light" \| "dark"` | cambia colore Bootstrap |
56
+ | `size` | — | `"sm" \| "lg"` | dimensione Bootstrap |
57
+ | `block` | `false` | `boolean` | full width (`w-100`) |
58
+ | `disabled` | `false` | `boolean` | disabilita click |
59
+ | `type` | `button` | `"button" \| "submit" \| "reset"` | tipo HTML button |
60
+ | `to` | — | `RouteLocationRaw` | naviga con `router.push` |
61
+ | `loading` | `false` | `boolean` | mostra spinner e disabilita |
62
+ | `icon` | — | `string` | icona Material Symbols |
63
+ | `share` | — | `ShareLink` | condivide link al click |
60
64
 
61
65
  ```vue
62
66
  <script setup lang="ts">
@@ -64,50 +68,6 @@ import { BtnCmp } from "cic-kit";
64
68
  </script>
65
69
 
66
70
  <template>
67
- <BtnCmp />
71
+ <BtnCmp color="primary">Salva</BtnCmp>
68
72
  </template>
69
73
  ```
70
-
71
- Il componente utilizza `vue-router`, quindi l’app deve avere un router configurato.
72
-
73
- ---
74
-
75
- ## Font e asset
76
-
77
- I font sono inclusi nello stylesheet del pacchetto.
78
- Durante la build possono essere:
79
- - **inlined** (base64 nel CSS), oppure
80
- - **copiati come asset** (a seconda della configurazione di build)
81
-
82
- In entrambi i casi **non è richiesta alcuna configurazione aggiuntiva** nel progetto consumer.
83
-
84
- ---
85
-
86
- ## Filosofia del pacchetto
87
-
88
- - 🧩 Componenti piccoli e riutilizzabili
89
- - 🎨 Stili centralizzati e condivisi
90
- - 📦 Nessuna dipendenza “hardcoded”
91
- - 🔌 Massima integrazione con il progetto consumer
92
-
93
- ---
94
-
95
- ## Sviluppo
96
-
97
- Il pacchetto è pensato per essere usato insieme a un progetto di test/sandbox separato.
98
-
99
- Build della libreria:
100
-
101
- ```bash
102
- npm run build
103
- ```
104
-
105
- Prima della pubblicazione è consigliato testare il pacchetto con:
106
-
107
- ```bash
108
- npm pack
109
- ```
110
-
111
- e installare il `.tgz` in un progetto Vue reale.
112
-
113
- ---
package/dist/cic-kit.css CHANGED
@@ -1 +1 @@
1
- .spinner-border[data-v-1fbd412d]{vertical-align:middle}.btn-ms-link[data-v-1fbd412d]{background-color:transparent!important;border:none;color:var(--bs-btn-color)!important}.btn-ms-link[data-v-1fbd412d]:hover{text-decoration:underline}.hideAfter[data-v-1fbd412d]:after{display:none}
1
+ .spinner-border[data-v-2280ac85]{vertical-align:middle}.btn-ms-link[data-v-2280ac85]{background-color:transparent!important;border:none;color:var(--bs-btn-color)!important}.btn-ms-link[data-v-2280ac85]:hover{text-decoration:underline}.hideAfter[data-v-2280ac85]:after{display:none}.toast-wrapper[data-v-821bd999]{position:fixed;bottom:20px;right:20px;display:flex;flex-direction:column;gap:6px;z-index:999999}.toast-card[data-v-821bd999]{width:330px;min-height:80px;border-radius:8px;padding:10px 12px;background-color:#fff;box-shadow:0 8px 24px #00000026;display:flex;align-items:center;justify-content:center;gap:12px;cursor:default;transition:all .3s ease,transform .3s ease;overflow:hidden;opacity:1}.toast-card .icon-container[data-v-821bd999]{width:35px;height:35px;display:flex;justify-content:center;align-items:center;border-radius:50%;flex-shrink:0;transition:all .3s ease}.toast-card .message-text[data-v-821bd999]{font-size:17px;font-weight:700}.toast-card .sub-text[data-v-821bd999]{color:#555;font-size:14px}.toast-card .cross-icon[data-v-821bd999]{width:18px;height:18px;color:#555;cursor:pointer;flex-shrink:0}.toast-card[data-v-821bd999]:not(.expanded){min-height:40px;max-height:40px;padding-top:6px;padding-bottom:6px;opacity:.7}.toast-card:not(.expanded) .icon-container[data-v-821bd999]{width:18px;height:18px}.toast-card:not(.expanded) .message-text[data-v-821bd999]{font-size:14px}.toast-card:not(.expanded) .sub-content[data-v-821bd999]{display:none}.toast-card:not(.expanded) .cross-icon[data-v-821bd999]{width:14px;height:14px}.toast-fade-enter-from[data-v-821bd999],.toast-fade-leave-to[data-v-821bd999]{opacity:0;transform:translateY(20px)}.toast-fade-enter-active[data-v-821bd999],.toast-fade-leave-active[data-v-821bd999]{transition:all .3s ease}.message-text-container[data-v-821bd999]{flex-grow:1}.toast-card.info[data-v-821bd999]{border-right:5px solid var(--bs-info)}.toast-card.info .icon-container[data-v-821bd999]{color:var(--bs-info)}.toast-card.success[data-v-821bd999]{border-right:5px solid var(--bs-success)}.toast-card.success .icon-container[data-v-821bd999]{color:var(--bs-success)}.toast-card.warning[data-v-821bd999]{border-right:5px solid var(--bs-warning)}.toast-card.warning .icon-container[data-v-821bd999]{color:var(--bs-warning)}.toast-card.error[data-v-821bd999]{border-right:5px solid var(--bs-danger)}.toast-card.error .icon-container[data-v-821bd999]{color:var(--bs-danger)}.toast-card.primary[data-v-821bd999]{border-right:5px solid var(--bs-primary)}.toast-card.primary .icon-container[data-v-821bd999]{color:var(--bs-primary)}.toast-card.secondary[data-v-821bd999]{border-right:5px solid var(--bs-secondary)}.toast-card.secondary .icon-container[data-v-821bd999]{color:var(--bs-secondary)}.prefix-width[data-v-d70bf135]{width:60px}
@@ -0,0 +1,6 @@
1
+ export interface ShareLink {
2
+ url: string;
3
+ text?: string;
4
+ title?: string;
5
+ }
6
+ export declare function shareLink({ url, text, title }: ShareLink): Promise<void>;
@@ -0,0 +1,3 @@
1
+ export type BtnVariant = "solid" | "outline" | "ghost" | "link";
2
+ export type BtnColor = "primary" | "secondary" | "success" | "danger" | "warning" | "info" | "light" | "dark";
3
+ export type IconGoogle = "search" | "home" | "menu" | "close" | "settings" | "send" | "add" | "remove" | "delete" | "star" | "star_half" | "arrow_forward_ios" | "arrow_back_ios" | "logout" | "more_vert" | "favorite" | "login" | "radio_button_unchecked" | "radio_button_checked" | "bolt" | "block" | "sync" | "share" | "ios_share" | "upload" | "alternate_email" | "account_circle" | "manage_accounts" | "visibility" | "visibility_off" | "language" | "support" | "mail" | "call" | "notifications" | "link" | "person_search" | "edit" | "photo_camera" | "image" | "circle" | "payments" | "credit_card" | "database" | "shopping_bag" | "account_balance" | "savings" | "qr_code" | "euro" | "wallet" | "payment_arrow_down" | "location_on" | "map" | "fastfood";
@@ -0,0 +1,5 @@
1
+ export declare const cicKitStore: {
2
+ isDev: boolean;
3
+ debugMod: boolean;
4
+ debugFirestore: boolean | string | string[];
5
+ };
@@ -0,0 +1 @@
1
+ export declare function clone<U>(o: U): U;
@@ -0,0 +1,81 @@
1
+ import { DocumentReference, Timestamp } from 'firebase/firestore';
2
+ type FirestoreStore_delete = {
3
+ delete: (id: string, opts?: Omit<OptionFireModel, 'touchUpdate'>) => Promise<void>;
4
+ };
5
+ export declare function fireDebugLog(collectionPath: string, icons: string, type: string, ...args: unknown[]): void;
6
+ export type Timestampble = {
7
+ createdAt: Timestamp;
8
+ updatedAt: Timestamp;
9
+ deleteAt: Timestamp | null;
10
+ };
11
+ export type OptionFireModel = {
12
+ offlineAllow?: boolean;
13
+ touchUpdate?: boolean;
14
+ localSet?: boolean;
15
+ };
16
+ export declare const optionFireModelDefault: OptionFireModel;
17
+ export declare abstract class FirestoreModel<T extends {
18
+ id: string;
19
+ }> {
20
+ id: string;
21
+ createdAt: Timestamp;
22
+ updatedAt: Timestamp;
23
+ deleteAt: Timestamp | null;
24
+ protected constructor(data: T & Partial<Timestampble>);
25
+ static collectionName?: string;
26
+ private debugLog;
27
+ /**
28
+ * Facoltativo: i model figli possono override-are questo metodo
29
+ * per fornire la path dinamica di collezione (es. subcollection).
30
+ * Esempio: "debits/{parentId}/transitions"
31
+ */
32
+ protected getCollectionPath?(): string;
33
+ protected localStorageKey?(): string;
34
+ /**
35
+ * Ritorna la DocumentReference calcolando:
36
+ * - se il model ha getCollectionPath(): la usa
37
+ * - altrimenti usa la static collectionName.
38
+ */
39
+ get ref(): DocumentReference;
40
+ abstract toData(): T;
41
+ /**
42
+ * GET singolo documento.
43
+ */
44
+ static get<U extends FirestoreModel<T>, T extends {
45
+ id: string;
46
+ }>(this: {
47
+ new (data: T): U;
48
+ collectionName?: string;
49
+ }, id: string, opts?: {
50
+ collectionPath?: string;
51
+ localSet?: boolean;
52
+ }): Promise<U | undefined>;
53
+ static cleanDataAAA(data: any): {
54
+ [k: string]: any;
55
+ };
56
+ private static isPlainObject;
57
+ /**
58
+ * Rimuove ricorsivamente gli `undefined` annidati (Firestore non li supporta).
59
+ * NON trasforma null in deleteField: quello lo fai a top-level.
60
+ */
61
+ static stripUndefinedDeep(value: any): any;
62
+ static cleanData(data: any): {
63
+ [k: string]: any;
64
+ };
65
+ onGetBeforeStoreSet<U extends FirestoreModel<T>>(instance: U): Promise<U>;
66
+ save({ offlineAllow, touchUpdate, localSet }?: OptionFireModel): Promise<void>;
67
+ update(data: Partial<Omit<T, 'id'>>, { offlineAllow, touchUpdate, localSet }?: OptionFireModel): Promise<void>;
68
+ delete(store: FirestoreStore_delete, opts?: Omit<OptionFireModel, 'touchUpdate'>): Promise<void>;
69
+ deleteJustOnline_NotLocalStore({ offlineAllow, localSet }?: Omit<OptionFireModel, 'touchUpdate'>): Promise<void>;
70
+ get isDeleted(): boolean;
71
+ timestampbleProps(): Timestampble;
72
+ touchUpdated(): Timestamp;
73
+ softDelete(optionFireModel?: OptionFireModel): Promise<void>;
74
+ /** 🔄 Ripristina dal cestino (se supportato) */
75
+ restore(optionFireModel?: OptionFireModel): Promise<void>;
76
+ /** Ritorna true se il model espone una chiave valido per il salvataggio su LocalStorage */
77
+ canLocalSave(localSet?: boolean): boolean;
78
+ /** Salva/aggiorna questo documento nel LocalStorage, sotto l’oggetto indicizzato per id */
79
+ localSet(_delete?: boolean): void;
80
+ }
81
+ export {};
@@ -0,0 +1,116 @@
1
+ import { type QueryConstraint, type FieldPath, type OrderByDirection, type DocumentChange, type DocumentData } from 'firebase/firestore';
2
+ import { FirestoreModel } from './FirestoreModel';
3
+ import { type OptionFireModel } from './FirestoreModel';
4
+ import type { Reactive } from 'vue';
5
+ export interface GetProps {
6
+ ids?: string[];
7
+ lastByCreate?: number;
8
+ lastByUpdate?: number;
9
+ query?: QueryConstraint | QueryConstraint[];
10
+ limit?: number;
11
+ orderBy?: {
12
+ fieldPath: string | FieldPath;
13
+ directionStr?: OrderByDirection;
14
+ };
15
+ forceLocalSet?: boolean;
16
+ localSet?: boolean;
17
+ }
18
+ type Ctor<M, D> = {
19
+ new (data: D): M;
20
+ collectionName?: string;
21
+ };
22
+ export type FirestoreStoreReactive<M extends FirestoreModel<D>, D extends {
23
+ id: string;
24
+ }> = Reactive<FirestoreStore<M, D>>;
25
+ export type AnyFirestoreStoreReactive = FirestoreStoreReactive<FirestoreModel<{
26
+ id: string;
27
+ }>, {
28
+ id: string;
29
+ }>;
30
+ export declare class FirestoreStore<M extends FirestoreModel<D>, D extends {
31
+ id: string;
32
+ }> {
33
+ protected readonly ModelInstnce: Ctor<M, D>;
34
+ protected makeModel(id: string, data: Omit<D, 'id'>): M;
35
+ /** Se presente, verrà usata al posto di ModelInstnce.collectionName */
36
+ protected readonly _collectionPath?: string;
37
+ private debugLog;
38
+ items: Record<string, M>;
39
+ snapshotFnStop: (() => void) | null;
40
+ isFirstRun: boolean;
41
+ prevStartQuery: string | null;
42
+ get live(): boolean;
43
+ get ref(): import("@firebase/firestore").CollectionReference<DocumentData, DocumentData>;
44
+ constructor(ModelInstnce: Ctor<M, D>, opts?: {
45
+ collectionPath?: string;
46
+ });
47
+ /** Path effettiva della collezione di questo store */
48
+ protected get collectionPath(): string;
49
+ get name(): string;
50
+ get itemsActive(): Record<string, M>;
51
+ get itemsDeleted(): Record<string, M>;
52
+ get itemsArray(): M[];
53
+ /** 🔎 Solo elementi NON cancellati (m.deleteAt === null) */
54
+ get itemsActiveArray(): M[];
55
+ /** 🧺 Solo elementi cancellati (cestino) */
56
+ get itemsDeletedArray(): M[];
57
+ get isEmpty(): boolean;
58
+ /** 🔎 Versione array: NON cancellati */
59
+ get isActiveEmpty(): boolean;
60
+ /** 🧺 Versione array: cancellati */
61
+ get isDeletedEmpty(): boolean;
62
+ get localStorageKey(): any;
63
+ /**
64
+ * 📅 Restituisce un array ordinato per timestamp scelto.
65
+ * @param option 'createdAt' | 'updatedAt' | 'deleteAt'
66
+ * @returns Array ordinato in ordine discendente (più recente prima)
67
+ */
68
+ itemsArrayOrderedBy(option: 'createdAt' | 'updatedAt' | 'deleteAt', deleted?: boolean): M[];
69
+ findItemsById(id: string | false | null | undefined): M;
70
+ get(opts?: GetProps): Promise<Record<string, M>>;
71
+ /**
72
+ * Legge doc per ids usando `documentId() in (...)`
73
+ * Firestore: max 10 elementi per `in` ma gestito fa chiamate a grruppi da 10
74
+ */
75
+ getIds(ids: string[]): Promise<{
76
+ foundIds: string[] | false;
77
+ notFoundIds: string[] | false;
78
+ }>;
79
+ localGet(): void;
80
+ /**
81
+ * 🔴 Avvia il listening realtime (onSnapshot) sulla collection gestita dallo store.
82
+ *
83
+ * Questo metodo mette lo store in modalità "live", mantenendo sincronizzati
84
+ * gli `items` locali con Firestore in tempo reale.
85
+ *
86
+ * ⚠️ Non modifica la logica esistente di `get()`:
87
+ * - `start()` serve solo per l'ascolto realtime
88
+ * - `get()` resta una fetch one-shot
89
+ *
90
+ */
91
+ start(opts?: GetProps): Promise<void>;
92
+ onStartFirstRun(snapDocs: DocumentChange<DocumentData, DocumentData>[], forceLocalSet?: boolean): void;
93
+ stop(): void;
94
+ add(data: Omit<D, 'id'>, options?: Omit<OptionFireModel, 'touchUpdate'>): Promise<M>;
95
+ add(data: Omit<D, 'id'> & {
96
+ id?: string;
97
+ }, options?: Omit<OptionFireModel, 'touchUpdate'>): Promise<M>;
98
+ delete(id: string, opts?: Omit<OptionFireModel, 'touchUpdate'>): Promise<void>;
99
+ findByUid(uid: string): M;
100
+ /**
101
+ * Legge un singolo documento da Firestore e aggiorna items[id].
102
+ * Ritorna l'istanza oppure undefined se non esiste.
103
+ */
104
+ getOne(id: string, options?: OptionFireModel): Promise<M | undefined>;
105
+ /**
106
+ * Ritorna l'istanza se già presente nello store, altrimenti la carica da Firestore.
107
+ */
108
+ ensureOne(id: string): Promise<M | undefined>;
109
+ /** 🧹 Svuota completamente il LocalStorage associato al Model gestito dallo store */
110
+ localClear(): void;
111
+ }
112
+ export declare function validateQueryGetOpts(opts: GetProps & {
113
+ ids?: string[];
114
+ }): boolean;
115
+ export declare function buildConstraintsFromGetProps(opts: GetProps, alredyCheck?: boolean): QueryConstraint[] | false;
116
+ export {};
@@ -0,0 +1,27 @@
1
+ import { type FirebaseApp } from "firebase/app";
2
+ import { getAnalytics } from "firebase/analytics";
3
+ import { getAuth, GoogleAuthProvider, signInWithPopup } from 'firebase/auth';
4
+ import { getFirestore } from 'firebase/firestore';
5
+ import { getStorage } from "firebase/storage";
6
+ import { getFunctions } from "firebase/functions";
7
+ import { getMessaging } from "firebase/messaging";
8
+ export interface FirebaseConfig {
9
+ apiKey: string;
10
+ authDomain: string;
11
+ projectId: string;
12
+ storageBucket: string;
13
+ messagingSenderId: string;
14
+ appId: string;
15
+ measurementId?: string;
16
+ databaseURL?: string;
17
+ }
18
+ export declare let auth: ReturnType<typeof getAuth>;
19
+ export declare let provider: GoogleAuthProvider;
20
+ export declare let analytics: ReturnType<typeof getAnalytics>;
21
+ export declare let db: ReturnType<typeof getFirestore>;
22
+ export declare let storage: ReturnType<typeof getStorage>;
23
+ export declare let functions: ReturnType<typeof getFunctions>;
24
+ export declare let messaging: ReturnType<typeof getMessaging>;
25
+ export declare function setupFirebase(firebaseConfig: FirebaseConfig): FirebaseApp;
26
+ export declare function ensureFirebase(): void;
27
+ export { signInWithPopup };
@@ -0,0 +1 @@
1
+ export declare function middlewareCatchCall(error: any, showToast?: boolean): void;
@@ -0,0 +1,9 @@
1
+ import type { AnyFirestoreStoreReactive, GetProps } from './FirestoreStore';
2
+ type StoreWatchItem = {
3
+ store: AnyFirestoreStoreReactive;
4
+ getOpts?: GetProps;
5
+ getAuthOpts?: GetProps;
6
+ checkLogin?: boolean;
7
+ };
8
+ export declare function useStoreWatch(stores: readonly StoreWatchItem[]): void;
9
+ export {};
@@ -0,0 +1,88 @@
1
+ import { type ComputedRef, type Ref } from 'vue';
2
+ export type RuleFn<V> = (value: V) => string | null;
3
+ export type Schema<T> = {
4
+ [K in keyof T]?: RuleFn<T[K]>[];
5
+ };
6
+ type ErrorsOf<T> = {
7
+ [K in keyof T]: string | null;
8
+ };
9
+ type TouchedOf<T> = {
10
+ [K in keyof T]: boolean;
11
+ };
12
+ export interface FormValidatorOptions<T extends Record<string, any>> {
13
+ id?: string;
14
+ initialValues: T;
15
+ validator?: Schema<T>;
16
+ onSubmit?: (values: Readonly<T>, touchedValues: Partial<T>, touched: Readonly<TouchedOf<T>>) => void | Promise<void>;
17
+ onInvalid?: (errors: Readonly<ErrorsOf<T>>) => void;
18
+ /** Validazione on change (default: true per tutti) */
19
+ validateOnChange?: boolean | Partial<Record<keyof T, boolean>>;
20
+ /** Validazione on change (default: true per tutti) */
21
+ touchOnChange?: boolean | Partial<Record<keyof T, boolean>>;
22
+ syncWith?: Ref<Partial<T> | null | undefined> | (() => Partial<T> | null | undefined);
23
+ submitOnChange?: boolean | number;
24
+ syncPreference?: 'local' | 'db';
25
+ effects?: Partial<Record<keyof T, (value: T[keyof T], fv: FormValidator<T>) => void>>;
26
+ onAnyChange?: (key: keyof T, value: T[keyof T], fv: FormValidator<T>) => void;
27
+ }
28
+ export declare class FormValidator<T extends Record<string, any>> {
29
+ readonly id: string;
30
+ readonly values: T;
31
+ readonly errors: ErrorsOf<T>;
32
+ readonly touched: TouchedOf<T>;
33
+ private _initial;
34
+ private readonly schema;
35
+ private readonly _onSubmit?;
36
+ private readonly _onInvalid?;
37
+ private readonly _validateOnChangeMap;
38
+ private readonly _touchOnChangeMap;
39
+ private readonly _stopWatch?;
40
+ private _fieldCache;
41
+ private _allFields?;
42
+ private _submitOnChange?;
43
+ private _suspendAutoSubmit;
44
+ private _debouncedSubmit?;
45
+ private _syncPreference;
46
+ private readonly _effects?;
47
+ private readonly _onAnyChange?;
48
+ private _makeDebouncedSubmit;
49
+ constructor(options: FormValidatorOptions<T>);
50
+ constructor(initial: T, schema?: Schema<T>);
51
+ touch<K extends keyof T>(key: K): void;
52
+ touchAll(): void;
53
+ field<K extends keyof T>(key: K): ComputedRef<T[K]>;
54
+ fields(): {
55
+ [K in keyof T]: ComputedRef<T[K]>;
56
+ };
57
+ set<K extends keyof T>(key: K, value: T[K], validateNow?: boolean): void;
58
+ validateField<K extends keyof T>(key: K): boolean;
59
+ validateAll(): boolean;
60
+ fill(model: Partial<T>, options?: {
61
+ validate: boolean;
62
+ }): void;
63
+ reset({ keepTouched }?: {
64
+ keepTouched?: boolean;
65
+ }): void;
66
+ resetWithInitialValues(initialValues: T): void;
67
+ bindField<K extends keyof T>(key: K, forceValidateOnChange?: boolean): ComputedRef<T[K]>;
68
+ showError<K extends keyof T>(key: K): string | null;
69
+ hasError(k: keyof T): boolean;
70
+ getFieldId<K extends keyof T>(key: K): string;
71
+ getFieldIdError<K extends keyof T>(key: K): string;
72
+ getFieldProps<K extends keyof T>(key: K): {
73
+ id: string;
74
+ 'aria-invalid': boolean;
75
+ 'aria-describedby': string;
76
+ class: {
77
+ 'is-invalid': boolean;
78
+ };
79
+ };
80
+ get isValid(): boolean;
81
+ get isDirty(): boolean;
82
+ get touchedValues(): Partial<T>;
83
+ dispose(): void;
84
+ /** Handler pronto per il form: @submit.prevent="fv.submit" */
85
+ submit: () => Promise<void>;
86
+ setSyncPreference(pref: 'local' | 'db'): void;
87
+ }
88
+ export {};
@@ -0,0 +1,25 @@
1
+ import { Timestamp } from 'firebase/firestore';
2
+ /** Timestamp | Date → 'YYYY-MM-DD' (input type="date") */
3
+ export declare function timestampInputDate(v: Timestamp | Date | null | undefined): string;
4
+ /** Timestamp | Date → 'HH:mm' (input type="time") */
5
+ export declare function timestampInputTime(v: Timestamp | Date | null | undefined): string;
6
+ /** Timestamp | Date → 'YYYY-MM-DDTHH:mm' (input type="datetime-local") */
7
+ export declare function timestampInputDateTimeLocal(v: Timestamp | Date | null | undefined): string;
8
+ /** 'YYYY-MM-DD' → Date (locale) */
9
+ export declare function inputDateToDate(date: string): Date | null;
10
+ /** 'YYYY-MM-DD' + 'HH:mm' → Timestamp */
11
+ export declare function inputDateTimeToTimestamp(date: string, time?: string): Timestamp | null;
12
+ /** Qualsiasi valore → stringa sicura per input text */
13
+ export declare function valueToInputString(v: unknown, fallback?: string): string;
14
+ /** Qualsiasi valore → number | '' (input type="number") */
15
+ export declare function valueToInputNumber(v: unknown): number | '';
16
+ /** Qualsiasi valore → boolean (input type="checkbox") */
17
+ export declare function valueToInputBoolean(v: unknown): boolean;
18
+ /** Garantisce sempre un array di stringhe (select multiple, tag, ecc.) */
19
+ export declare function valueToStringArray(v: unknown): string[];
20
+ /** Normalizza value per <select> (evita undefined) */
21
+ export declare function valueToSelect<T extends string>(v: unknown, allowed?: readonly T[]): T | '';
22
+ /** Timestamp | Date → locale string breve */
23
+ export declare function timestampToLocale(v: Timestamp | Date | null | undefined, locale?: any): string;
24
+ /** Stringa vuota → placeholder visivo */
25
+ export declare function emptyToDash(v: unknown): string;
@@ -0,0 +1,28 @@
1
+ import type { RuleFn } from "./FormValidator";
2
+ export declare const required: (msg?: string) => RuleFn<any>;
3
+ export declare const email: (msg?: string) => RuleFn<string>;
4
+ export declare const dateISO: (msg?: string) => RuleFn<string>;
5
+ export declare const url: (msg?: string) => RuleFn<string>;
6
+ export declare const oneOf: <V extends string>(choices: readonly V[], msg?: string) => RuleFn<V | undefined>;
7
+ export declare const requiredTrue: (msg?: string) => RuleFn<boolean>;
8
+ /** Deve essere un numero valido */
9
+ export declare const isNumber: (msg?: string) => RuleFn<any>;
10
+ /** Numero minimo (incluso) */
11
+ export declare const minNumber: (min: number, msg?: string) => RuleFn<number | string>;
12
+ /** Numero massimo (incluso) */
13
+ export declare const maxNumber: (max: number, msg?: string) => RuleFn<number | string>;
14
+ /** Lunghezza minima stringa */
15
+ export declare const minLength: (min: number, msg?: string) => RuleFn<string>;
16
+ /** Lunghezza massima stringa */
17
+ export declare const maxLength: (max: number, msg?: string) => RuleFn<string>;
18
+ export declare const password: (msg?: string) => RuleFn<string>;
19
+ /** Password con lunghezza minima */
20
+ export declare const passwordWithMin: (min: number, msg?: string) => RuleFn<string>;
21
+ /** Conferma password: deve coincidere con la password originale */
22
+ export declare const passwordRetype: (getOriginal: () => string | null | undefined, msg?: string) => RuleFn<string>;
23
+ /** Deve essere dopo (>=) una data di riferimento */
24
+ export declare const dateAfter: (getMin: () => string | Date | null | undefined, msg?: string) => RuleFn<string>;
25
+ /** Deve essere prima (<=) di una data di riferimento */
26
+ export declare const dateBefore: (getMax: () => string | Date | null | undefined, msg?: string) => RuleFn<string>;
27
+ /** Deve essere compresa tra due date (inclusi) */
28
+ export declare const dateBetween: (getMin: () => string | Date | null | undefined, getMax: () => string | Date | null | undefined, msg?: string) => RuleFn<string>;
@@ -0,0 +1 @@
1
+ export type Gender = '' | 'm' | 'f' | 'o';
@@ -0,0 +1,2 @@
1
+ export type PhoneNumber = [prefix: string, number: string];
2
+ export declare const phoneNumberFromString: (phoneNumber: string, defaultPrefix?: string) => PhoneNumber;
@@ -0,0 +1,32 @@
1
+ export declare const LS: {
2
+ defaultKey: {
3
+ isDev: string;
4
+ debugMod: string;
5
+ currentUser: string;
6
+ };
7
+ /** Lettura con gestione errori, valore */
8
+ getStr(key: string): string | undefined;
9
+ /** Lettura con gestione errori, valore */
10
+ getParsed(key: string): any;
11
+ /** Scrittura sicura con serializzazione JSON */
12
+ set(key: string, value: any): any;
13
+ /** Aggiorna un valore esistente */
14
+ update(key: string, data: any): any;
15
+ /** Aggiunge uno o più elementi a un array salvato in localStorage */
16
+ push(key: string, ...items: any[]): any;
17
+ /** Rimozione sicura */
18
+ remove(key: string): void;
19
+ /** Alias compatibile (ma corretto) */
20
+ delete(key: string): void;
21
+ /** Verifica se una chiave esiste */
22
+ has(key: string): boolean;
23
+ /** Elenca tutte le chiavi conosciute (solo quelle definite in LocalStorageKey) */
24
+ keys(): string[];
25
+ /**
26
+ * Svuota il localStorage tranne le chiavi indicate
27
+ * @param exclude una chiave o un array di chiavi da preservare
28
+ */
29
+ clear(exclude?: string | string[]): void;
30
+ /** Migra il valore da una chiave a un’altra */
31
+ migrate(oldKey: string, newKey: string): void;
32
+ };
@@ -0,0 +1,3 @@
1
+ export declare const MSG_IS_OFFLINE = "Sei offline: cancello in locale, sincronizzo quando torni online.";
2
+ export declare function isBrowserOnline(): boolean;
3
+ export declare function isBrowserOffline(): boolean;
@@ -0,0 +1,18 @@
1
+ import type { User } from '../../models/User';
2
+ export type PushMsgContent = NotificationOptions & {
3
+ title: string;
4
+ };
5
+ export interface PushMsg {
6
+ reg: ServiceWorkerRegistration | undefined;
7
+ VAPID_PUBLIC_KEY: string | undefined;
8
+ isNotificationSupported: boolean;
9
+ permission: NotificationPermission;
10
+ needToAskPermission: boolean;
11
+ askPermission(currentUser: User): Promise<NotificationPermission>;
12
+ send(currentUser: User, content: string | PushMsgContent): Promise<void>;
13
+ sendTo(uid: string, content: string | PushMsgContent): Promise<boolean>;
14
+ getCurrentFcmToken(): Promise<string | null>;
15
+ registerFcmToken(currentUser: User): Promise<string | null>;
16
+ removeThisDeviceToken(currentUser: User): Promise<boolean>;
17
+ }
18
+ export declare const pushMsg: PushMsg;
@@ -0,0 +1,8 @@
1
+ import { Timestamp } from "firebase/firestore";
2
+ export declare function reviveTimestamp(json: {
3
+ seconds: number;
4
+ nanoseconds: number;
5
+ type?: string;
6
+ } | Timestamp): Timestamp;
7
+ export declare function reviveTimestampsDeep(value: any): any;
8
+ export declare const serializeTimestamp: (value: any) => any;