Angular library monorepo that publishes shared Ionic/Angular building blocks to npm. All rdlabo/proschool/odss Ionic Angular applications import from these packages rather than duplicating infrastructure code.
| Directory | npm package | Purpose |
|---|---|---|
projects/kit |
@rdlabo/ionic-angular-kit |
Core infrastructure: storage, overlay (modal/toast/alert), HTTP interceptor, auth guards, autofill directive, haptics, array merge utility |
projects/scroll-header |
@rdlabo/ionic-angular-scroll-header |
Scroll-linked header hide/show directives, CDK virtual scroll flicker fix |
projects/scroll-strategies |
@rdlabo/ngx-cdk-scroll-strategies |
Dynamic-size virtual scroll strategy for Angular CDK |
projects/photo-editor |
@rdlabo/ionic-angular-photo-editor |
Image editing/viewing components with filter presets |
projects/demo |
(not published) | Demo app for testing all libraries |
Typed wrapper around @ionic/storage-angular. Auto-initializes via inject(Storage).create() in the constructor; every operation awaits the ready Promise internally. No explicit init() call needed. API: set<T>, get<T>, remove, clear, keys.
Wraps Ionic Modal/Toast/Alert controllers. Setup: provideKitOverlay({ labels: { close, cancel } }).
presentModal<O>(component, componentProps?, options?)→Promise<O | undefined>— supportswatchKeyboardoption for sheet modalspresentToast(options)→Promise<HTMLIonToastElement>— returns the toast element (callers can chain.onDidDismiss()). Defaults: top, 2000ms, close button, vertical swipe. Triggers haptic feedback.alertClose({ header, message, subHeader? })→Promise<void>alertConfirm({ header, message, okText, subHeader? })→Promise<boolean>
Functional HTTP interceptor. Built-in: retry (2x, linear backoff), non-retryable status list [400, 403, 404, 418, 500, 502], Network.getStatus() check before calling onNetworkError. App provides: getAuthHeaders, buildExtraHeaders, onResponse, bypass, offlineFallback, onUnauthorized, onForbidden, onNetworkError, onServerError.
Functional CanActivateFn guards: kitRequireAuthorizedGuard, kitRequiredUnauthorizedGuard, kitRequireConfirmingGuard. App provides: authState() → Observable<'user'|'confirm'|'required'|'anonymous'>, onAuthorized, onUnauthenticated, redirects.
Selector: [rdlaboAutofill]. iOS-only workaround for ion-input autofill not propagating to Angular form model.
kitImpact(style?)— native haptic feedback, no-op on webarrayConcatById<T>(old, new, key, order='DESC')— merge paginated lists by key, deduplicate, sort
projects/util/mocks/— mock factories for NavController, ModalController, PopoverController, IonRouterOutletprojects/util/test.config.ts— shared vitest/karma configuration
| Project | Packages used |
|---|---|
| winecode | kit, scroll-header, scroll-strategies, photo-editor |
| receptray | scroll-header, scroll-strategies |
| tipsys | photo-editor, scroll-header, scroll-strategies |
| foodlabel | scroll-header |
| odss-team/odss-mobile | photo-editor, scroll-header |
| proschool-team/airlec2 | (adoption pending) |
npm install
npm run lint # ng lint (ESLint)
npm run test # ng test --watch=false (vitest)
npm run prebuild # build all libraries to dist/
npm run start # serve demo app (http://localhost:4200/)- Configuration-injected: kit services accept configuration via Angular DI (
provideKitOverlay,provideKitHttp,provideKitAuth) rather than hard-coding app-specific behavior. The kit ships no i18n strings; the consuming app provides all labels. - No NgModules: all components, directives, and pipes are standalone.
- Minimal API surface: each export solves a specific, well-scoped problem. Domain logic and navigation policy belong in the consuming app.
- Capacitor-aware: haptics, keyboard, network, and platform checks use
@capacitor/coreand degrade to no-op on web.
- Run
npm run lintbefore committing. - Each library has its own
public-api.ts— new exports must be added there. - Every public class, function, and type must have a JSDoc comment.
- Build all libraries before testing the demo:
npm run prebuild. - The
kitlibrary (projects/kit) must not import from other libraries in this monorepo (scroll-header, photo-editor, etc.) — it is a leaf dependency.