@rdlabo/ionic-theme-ios26 0.0.2 → 0.0.4
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/.cursor/rules/css-compilation.mdc +34 -0
- package/.cursor/rules/demo-application.mdc +39 -0
- package/.cursor/rules/development-workflow.mdc +41 -0
- package/.cursor/rules/project-role.mdc +21 -0
- package/.github/FUNDING.yml +15 -0
- package/.github/workflows/lint.yml +40 -0
- package/.husky/pre-commit +1 -0
- package/.lintstagedrc.yml +6 -0
- package/.prettierignore +3 -0
- package/FEEDBACK.md +118 -0
- package/FEEDBACK2.md +45 -0
- package/README.md +107 -75
- package/USING_ION_ITEM_GROUP.md +56 -0
- package/demo/ .cursor/rules/angular-20.mdc +136 -0
- package/demo/.browserslistrc +15 -0
- package/demo/.editorconfig +16 -0
- package/demo/.vscode/extensions.json +5 -0
- package/demo/.vscode/settings.json +3 -0
- package/demo/angular.json +141 -0
- package/demo/capacitor.config.ts +9 -0
- package/demo/eslint.config.js +49 -0
- package/demo/ionic.config.json +7 -0
- package/demo/karma.conf.js +44 -0
- package/demo/package-lock.json +20001 -0
- package/demo/package.json +60 -0
- package/demo/src/app/album/album-page.component.html +24 -0
- package/demo/src/app/album/album-page.component.scss +17 -0
- package/demo/src/app/album/album-page.component.spec.ts +21 -0
- package/demo/src/app/album/album-page.component.ts +24 -0
- package/demo/src/app/app.component.html +3 -0
- package/demo/src/app/app.component.ts +16 -0
- package/demo/src/app/app.config.ts +17 -0
- package/demo/src/app/app.routes.ts +8 -0
- package/demo/src/app/health/health-page.component.html +17 -0
- package/demo/src/app/health/health-page.component.scss +0 -0
- package/demo/src/app/health/health-page.component.spec.ts +21 -0
- package/demo/src/app/health/health-page.component.ts +14 -0
- package/demo/src/app/index/index-page.component.html +49 -0
- package/demo/src/app/index/index-page.component.scss +0 -0
- package/demo/src/app/index/index-page.component.spec.ts +21 -0
- package/demo/src/app/index/index-page.component.ts +100 -0
- package/demo/src/app/index/index.routes.ts +89 -0
- package/demo/src/app/index/pages/action-sheet/action-sheet.page.html +33 -0
- package/demo/src/app/index/pages/action-sheet/action-sheet.page.scss +0 -0
- package/demo/src/app/index/pages/action-sheet/action-sheet.page.spec.ts +21 -0
- package/demo/src/app/index/pages/action-sheet/action-sheet.page.ts +73 -0
- package/demo/src/app/index/pages/action-sheet/action-sheet.util.ts +28 -0
- package/demo/src/app/index/pages/alert/alert.page.html +33 -0
- package/demo/src/app/index/pages/alert/alert.page.scss +0 -0
- package/demo/src/app/index/pages/alert/alert.page.spec.ts +21 -0
- package/demo/src/app/index/pages/alert/alert.page.ts +73 -0
- package/demo/src/app/index/pages/alert/alert.util.ts +21 -0
- package/demo/src/app/index/pages/breadcrumbs/breadcrumbs.page.html +41 -0
- package/demo/src/app/index/pages/breadcrumbs/breadcrumbs.page.scss +0 -0
- package/demo/src/app/index/pages/breadcrumbs/breadcrumbs.page.spec.ts +21 -0
- package/demo/src/app/index/pages/breadcrumbs/breadcrumbs.page.ts +47 -0
- package/demo/src/app/index/pages/button/button.page.html +112 -0
- package/demo/src/app/index/pages/button/button.page.scss +3 -0
- package/demo/src/app/index/pages/button/button.page.spec.ts +21 -0
- package/demo/src/app/index/pages/button/button.page.ts +51 -0
- package/demo/src/app/index/pages/card/card.page.html +171 -0
- package/demo/src/app/index/pages/card/card.page.scss +0 -0
- package/demo/src/app/index/pages/card/card.page.spec.ts +21 -0
- package/demo/src/app/index/pages/card/card.page.ts +57 -0
- package/demo/src/app/index/pages/checkbox/checkbox.page.html +66 -0
- package/demo/src/app/index/pages/checkbox/checkbox.page.scss +0 -0
- package/demo/src/app/index/pages/checkbox/checkbox.page.spec.ts +21 -0
- package/demo/src/app/index/pages/checkbox/checkbox.page.ts +45 -0
- package/demo/src/app/index/pages/chip/chip.page.html +72 -0
- package/demo/src/app/index/pages/chip/chip.page.scss +0 -0
- package/demo/src/app/index/pages/chip/chip.page.spec.ts +21 -0
- package/demo/src/app/index/pages/chip/chip.page.ts +47 -0
- package/demo/src/app/index/pages/date-and-time-pickers/date-and-time-pickers.page.html +48 -0
- package/demo/src/app/index/pages/date-and-time-pickers/date-and-time-pickers.page.scss +0 -0
- package/demo/src/app/index/pages/date-and-time-pickers/date-and-time-pickers.page.spec.ts +21 -0
- package/demo/src/app/index/pages/date-and-time-pickers/date-and-time-pickers.page.ts +55 -0
- package/demo/src/app/index/pages/floating-action-button/floating-action-button.page.html +106 -0
- package/demo/src/app/index/pages/floating-action-button/floating-action-button.page.scss +0 -0
- package/demo/src/app/index/pages/floating-action-button/floating-action-button.page.spec.ts +21 -0
- package/demo/src/app/index/pages/floating-action-button/floating-action-button.page.ts +49 -0
- package/demo/src/app/index/pages/menu/menu.page.html +13 -0
- package/demo/src/app/index/pages/menu/menu.page.scss +0 -0
- package/demo/src/app/index/pages/menu/menu.page.spec.ts +21 -0
- package/demo/src/app/index/pages/menu/menu.page.ts +17 -0
- package/demo/src/app/index/pages/modal/modal.page.html +37 -0
- package/demo/src/app/index/pages/modal/modal.page.scss +0 -0
- package/demo/src/app/index/pages/modal/modal.page.spec.ts +21 -0
- package/demo/src/app/index/pages/modal/modal.page.ts +77 -0
- package/demo/src/app/index/pages/popover/popover.page.html +34 -0
- package/demo/src/app/index/pages/popover/popover.page.scss +0 -0
- package/demo/src/app/index/pages/popover/popover.page.spec.ts +21 -0
- package/demo/src/app/index/pages/popover/popover.page.ts +47 -0
- package/demo/src/app/index/pages/progress-indicators/progress-indicators.page.html +28 -0
- package/demo/src/app/index/pages/progress-indicators/progress-indicators.page.scss +0 -0
- package/demo/src/app/index/pages/progress-indicators/progress-indicators.page.spec.ts +21 -0
- package/demo/src/app/index/pages/progress-indicators/progress-indicators.page.ts +47 -0
- package/demo/src/app/index/pages/radio/radio.page.html +39 -0
- package/demo/src/app/index/pages/radio/radio.page.scss +0 -0
- package/demo/src/app/index/pages/radio/radio.page.spec.ts +21 -0
- package/demo/src/app/index/pages/radio/radio.page.ts +47 -0
- package/demo/src/app/index/pages/range/range.page.html +58 -0
- package/demo/src/app/index/pages/range/range.page.scss +0 -0
- package/demo/src/app/index/pages/range/range.page.spec.ts +21 -0
- package/demo/src/app/index/pages/range/range.page.ts +49 -0
- package/demo/src/app/index/pages/searchbar/searchbar.page.html +33 -0
- package/demo/src/app/index/pages/searchbar/searchbar.page.scss +0 -0
- package/demo/src/app/index/pages/searchbar/searchbar.page.spec.ts +21 -0
- package/demo/src/app/index/pages/searchbar/searchbar.page.ts +45 -0
- package/demo/src/app/index/pages/segment/segment.page.html +102 -0
- package/demo/src/app/index/pages/segment/segment.page.scss +0 -0
- package/demo/src/app/index/pages/segment/segment.page.spec.ts +21 -0
- package/demo/src/app/index/pages/segment/segment.page.ts +51 -0
- package/demo/src/app/index/pages/select/select.page.html +74 -0
- package/demo/src/app/index/pages/select/select.page.scss +0 -0
- package/demo/src/app/index/pages/select/select.page.spec.ts +21 -0
- package/demo/src/app/index/pages/select/select.page.ts +50 -0
- package/demo/src/app/index/pages/toast/toast.page.html +32 -0
- package/demo/src/app/index/pages/toast/toast.page.scss +0 -0
- package/demo/src/app/index/pages/toast/toast.page.spec.ts +21 -0
- package/demo/src/app/index/pages/toast/toast.page.ts +66 -0
- package/demo/src/app/index/pages/toggle/toggle.page.html +45 -0
- package/demo/src/app/index/pages/toggle/toggle.page.scss +0 -0
- package/demo/src/app/index/pages/toggle/toggle.page.spec.ts +21 -0
- package/demo/src/app/index/pages/toggle/toggle.page.ts +49 -0
- package/demo/src/app/settings/settings-page.component.html +117 -0
- package/demo/src/app/settings/settings-page.component.scss +33 -0
- package/demo/src/app/settings/settings-page.component.spec.ts +21 -0
- package/demo/src/app/settings/settings-page.component.ts +55 -0
- package/demo/src/app/tabs/tabs.page.html +23 -0
- package/demo/src/app/tabs/tabs.page.scss +9 -0
- package/demo/src/app/tabs/tabs.page.spec.ts +26 -0
- package/demo/src/app/tabs/tabs.page.ts +28 -0
- package/demo/src/app/tabs/tabs.routes.ts +40 -0
- package/demo/src/assets/.gitkeep +0 -0
- package/demo/src/favicon.ico +0 -0
- package/demo/src/global.scss +65 -0
- package/demo/src/index.html +24 -0
- package/demo/src/main.ts +5 -0
- package/demo/src/test.ts +7 -0
- package/demo/src/theme/variables.scss +20 -0
- package/demo/tsconfig.app.json +14 -0
- package/demo/tsconfig.json +30 -0
- package/demo/tsconfig.spec.json +17 -0
- package/demo/util/mocks/angular/angular-delegate.ts +18 -0
- package/demo/util/mocks/angular/ion-router-outlet.ts +39 -0
- package/demo/util/mocks/angular/modal-controller.ts +7 -0
- package/demo/util/mocks/angular/nav-controller.ts +22 -0
- package/demo/util/mocks/angular/popover-controller.ts +7 -0
- package/demo/util/mocks/util/base.mock.ts +13 -0
- package/demo/util/mocks/util/overlay.ts +13 -0
- package/demo/util/test.config.ts +54 -0
- package/package.json +39 -11
- package/prettier.config.js +18 -0
- package/screenshots/ios26.png +0 -0
- package/screenshots/why-ion-list-inset.png +0 -0
- package/src/components/ion-action-sheet.scss +61 -0
- package/src/components/ion-alert.scss +46 -0
- package/src/components/ion-breadcrumbs.scss +24 -0
- package/src/components/ion-button.scss +154 -0
- package/src/components/ion-card.scss +7 -0
- package/src/components/ion-chip.scss +10 -0
- package/src/components/ion-content.scss +13 -0
- package/src/components/ion-datetime.scss +9 -0
- package/src/components/ion-fab.scss +22 -0
- package/src/components/ion-list.scss +38 -0
- package/src/components/ion-loading.scss +9 -0
- package/src/components/ion-modal.scss +31 -0
- package/src/components/ion-picker.scss +4 -0
- package/src/components/ion-popover.scss +13 -0
- package/src/components/ion-range.scss +21 -0
- package/src/components/ion-searchbar.scss +37 -0
- package/src/components/ion-segment.scss +45 -0
- package/src/components/ion-tabs.scss +47 -0
- package/src/components/ion-toast.scss +12 -0
- package/src/components/ion-toggle.scss +56 -0
- package/src/components/ion-toolbar.scss +27 -0
- package/src/default-variables.scss +12 -0
- package/src/ionic-theme-ios26-dark-always.scss +6 -0
- package/src/ionic-theme-ios26-dark-class.scss +6 -0
- package/src/ionic-theme-ios26-dark-system.scss +8 -0
- package/src/ionic-theme-ios26.scss +23 -0
- package/src/md-ion-list-inset.scss +19 -0
- package/src/utils/api.scss +21 -0
- package/src/utils/dark/ion-button.scss +45 -0
- package/src/utils/theme-dark.scss +16 -0
- package/src/utils/theme-list-inset.scss +96 -0
- package/src/utils/translucent.scss +71 -0
- package/tsconfig.json +5 -0
- package/css/ion-list-inset.css +0 -247
- package/css/ion-list-inset.css.map +0 -1
- package/css/ionic-theme-ios26.css +0 -349
- package/css/ionic-theme-ios26.css.map +0 -1
- package/fesm2022/rdlabo-ionic-theme-ios26.mjs +0 -4
- package/fesm2022/rdlabo-ionic-theme-ios26.mjs.map +0 -1
- package/index.d.ts +0 -3
- package/src/assets/ion-list-inset.scss +0 -198
- package/src/assets/ios-design/ion-button.scss +0 -68
- package/src/assets/ios-design/ion-popover.scss +0 -23
- package/src/assets/ios-design/ion-searchbar.scss +0 -44
- package/src/assets/ios-design/ion-segment.scss +0 -12
- package/src/assets/ios-design/ion-tabs.scss +0 -60
- package/src/assets/ios-design/ion-toggle.scss +0 -8
- package/src/assets/ios-design/ios-design-dark.scss +0 -28
- package/src/assets/ios-design.scss +0 -110
- package/src/assets/ios-variables.scss +0 -38
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# Using `ion-item-group` with iOS26 Theme
|
|
2
|
+
|
|
3
|
+
This theme aims to bring Ionic Framework applications as close as possible to iOS 26 design. In most cases, you can use your existing Ionic code as-is, but **only under specific conditions**, you need to add `ion-item-group`.
|
|
4
|
+
|
|
5
|
+
## When is `ion-item-group` required?
|
|
6
|
+
|
|
7
|
+
It is only required when **both** of the following conditions are met:
|
|
8
|
+
|
|
9
|
+
- You have enabled the `inset` property on `ion-list`
|
|
10
|
+
|
|
11
|
+
Only when these conditions apply, you need to wrap your list items with `ion-item-group`.
|
|
12
|
+
|
|
13
|
+
## Implementation Example
|
|
14
|
+
|
|
15
|
+
```diff
|
|
16
|
+
<ion-list inset=true>
|
|
17
|
+
<ion-list-header><ion-label>Label</ion-label></ion-list-header>
|
|
18
|
+
+ <ion-item-group>
|
|
19
|
+
<ion-item>...</ion-item>
|
|
20
|
+
<ion-item>...</ion-item>
|
|
21
|
+
+ </ion-item-group>
|
|
22
|
+
</ion-list>
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Why is this change necessary?
|
|
26
|
+
|
|
27
|
+
### Background: Challenges in iOS Design Reproduction
|
|
28
|
+
|
|
29
|
+
By default in Ionic Framework, `ion-list` has a background color, and `ion-list-header` is treated as part of the list. However, with this structure, it's impossible to accurately reproduce **iOS's native design patterns**.
|
|
30
|
+
|
|
31
|
+

|
|
32
|
+
|
|
33
|
+
### Solution: Background Color Separation
|
|
34
|
+
|
|
35
|
+
To faithfully reproduce iOS design, this theme makes the following changes:
|
|
36
|
+
|
|
37
|
+
- Set `ion-list` background color to transparent
|
|
38
|
+
- Delegate background color to `ion-item-group`
|
|
39
|
+
|
|
40
|
+
This change allows `ion-list-header` to be treated as an independent element, achieving the native iOS appearance.
|
|
41
|
+
|
|
42
|
+
## Using the Same Design with Material Design
|
|
43
|
+
|
|
44
|
+
If you want to use the same design pattern with Material Design theme, import the following CSS:
|
|
45
|
+
|
|
46
|
+
```css
|
|
47
|
+
@import '@rdlabo/ionic-theme-ios26/css/md-ion-list-inset.css';
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
This will apply the same `ion-item-group` pattern to the Material Design theme as well.
|
|
51
|
+
|
|
52
|
+
## Summary
|
|
53
|
+
|
|
54
|
+
- **Most cases**: You can use your existing Ionic code as-is
|
|
55
|
+
- **Specific conditions only**: `ion-item-group` is only required when setting using `inset` on `ion-list`
|
|
56
|
+
- **Purpose**: To accurately reproduce iOS 26's native design patterns
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: This rule provides comprehensive best practices and coding standards for Angular development, focusing on modern TypeScript, standalone components, signals, and performance optimizations.
|
|
3
|
+
globs: ["**/*.{ts,html,scss,css}"]
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Angular Best Practices
|
|
7
|
+
|
|
8
|
+
This project adheres to modern Angular best practices, emphasizing maintainability, performance, accessibility, and scalability.
|
|
9
|
+
|
|
10
|
+
## TypeScript Best Practices
|
|
11
|
+
|
|
12
|
+
* **Strict Type Checking:** Always enable and adhere to strict type checking. This helps catch errors early and improves code quality.
|
|
13
|
+
* **Prefer Type Inference:** Allow TypeScript to infer types when they are obvious from the context. This reduces verbosity while maintaining type safety.
|
|
14
|
+
* **Bad:**
|
|
15
|
+
```typescript
|
|
16
|
+
let name: string = 'Angular';
|
|
17
|
+
```
|
|
18
|
+
* **Good:**
|
|
19
|
+
```typescript
|
|
20
|
+
let name = 'Angular';
|
|
21
|
+
```
|
|
22
|
+
* **Avoid `any`:** Do not use the `any` type unless absolutely necessary as it bypasses type checking. Prefer `unknown` when a type is uncertain and you need to handle it safely.
|
|
23
|
+
|
|
24
|
+
## Angular Best Practices
|
|
25
|
+
|
|
26
|
+
* **Standalone Components:** Always use standalone components, directives, and pipes. Avoid using `NgModules` for new features or refactoring existing ones.
|
|
27
|
+
* **Implicit Standalone:** When creating standalone components, you do not need to explicitly set `standalone: true` inside the `@Component`, `@Directive` and `@Pipe` decorators, as it is implied by default.
|
|
28
|
+
* **Bad:**
|
|
29
|
+
```typescript
|
|
30
|
+
@Component({
|
|
31
|
+
standalone: true,
|
|
32
|
+
// ...
|
|
33
|
+
})
|
|
34
|
+
export class MyComponent {}
|
|
35
|
+
```
|
|
36
|
+
* **Good:**
|
|
37
|
+
```typescript
|
|
38
|
+
@Component({
|
|
39
|
+
// `standalone: true` is implied
|
|
40
|
+
// ...
|
|
41
|
+
})
|
|
42
|
+
export class MyComponent {}
|
|
43
|
+
```
|
|
44
|
+
* **Signals for State Management:** Utilize Angular Signals for reactive state management within components and services.
|
|
45
|
+
* **Lazy Loading:** Implement lazy loading for feature routes to improve initial load times of your application.
|
|
46
|
+
* **NgOptimizedImage:** Use `NgOptimizedImage` for all static images to automatically optimize image loading and performance.
|
|
47
|
+
* **Host bindings:** Do NOT use the `@HostBinding` and `@HostListener` decorators. Put host bindings inside the `host` object of the `@Component` or `@Directive` decorator instead.
|
|
48
|
+
|
|
49
|
+
## Components
|
|
50
|
+
|
|
51
|
+
* **Single Responsibility:** Keep components small, focused, and responsible for a single piece of functionality.
|
|
52
|
+
* **`input()` and `output()` Functions:** Prefer `input()` and `output()` functions over the `@Input()` and `@Output()` decorators for defining component inputs and outputs.
|
|
53
|
+
* **Old Decorator Syntax:**
|
|
54
|
+
```typescript
|
|
55
|
+
@Input() userId!: string;
|
|
56
|
+
@Output() userSelected = new EventEmitter<string>();
|
|
57
|
+
```
|
|
58
|
+
* **New Function Syntax:**
|
|
59
|
+
```typescript
|
|
60
|
+
import { input, output } from '@angular/core';
|
|
61
|
+
|
|
62
|
+
// ...
|
|
63
|
+
userId = input<string>('');
|
|
64
|
+
userSelected = output<string>();
|
|
65
|
+
```
|
|
66
|
+
* **`computed()` for Derived State:** Use the `computed()` function from `@angular/core` for derived state based on signals.
|
|
67
|
+
* **`ChangeDetectionStrategy.OnPush`:** Always set `changeDetection: ChangeDetectionStrategy.OnPush` in the `@Component` decorator for performance benefits by reducing unnecessary change detection cycles.
|
|
68
|
+
* **Inline Templates:** Prefer inline templates (template: `...`) for small components to keep related code together. For larger templates, use external HTML files.
|
|
69
|
+
* **Reactive Forms:** Prefer Reactive forms over Template-driven forms for complex forms, validation, and dynamic controls due to their explicit, immutable, and synchronous nature.
|
|
70
|
+
* **No `ngClass` / `NgClass`:** Do not use the `ngClass` directive. Instead, use native `class` bindings for conditional styling.
|
|
71
|
+
* **Bad:**
|
|
72
|
+
```html
|
|
73
|
+
<section [ngClass]="{'active': isActive}"></section>
|
|
74
|
+
```
|
|
75
|
+
* **Good:**
|
|
76
|
+
```html
|
|
77
|
+
<section [class.active]="isActive"></section>
|
|
78
|
+
<section [class]="{'active': isActive}"></section>
|
|
79
|
+
<section [class]="myClasses"></section>
|
|
80
|
+
```
|
|
81
|
+
* **No `ngStyle` / `NgStyle`:** Do not use the `ngStyle` directive. Instead, use native `style` bindings for conditional inline styles.
|
|
82
|
+
* **Bad:**
|
|
83
|
+
```html
|
|
84
|
+
<section [ngStyle]="{'font-size': fontSize + 'px'}"></section>
|
|
85
|
+
```
|
|
86
|
+
* **Good:**
|
|
87
|
+
```html
|
|
88
|
+
<section [style.font-size.px]="fontSize"></section>
|
|
89
|
+
<section [style]="myStyles"></section>
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
## State Management
|
|
93
|
+
|
|
94
|
+
* **Signals for Local State:** Use signals for managing local component state.
|
|
95
|
+
* **`computed()` for Derived State:** Leverage `computed()` for any state that can be derived from other signals.
|
|
96
|
+
* **Pure and Predictable Transformations:** Ensure state transformations are pure functions (no side effects) and predictable.
|
|
97
|
+
* **Signal value updates:** Do NOT use `mutate` on signals, use `update` or `set` instead.
|
|
98
|
+
|
|
99
|
+
## Templates
|
|
100
|
+
|
|
101
|
+
* **Simple Templates:** Keep templates as simple as possible, avoiding complex logic directly in the template. Delegate complex logic to the component's TypeScript code.
|
|
102
|
+
* **Native Control Flow:** Use the new built-in control flow syntax (`@if`, `@for`, `@switch`) instead of the older structural directives (`*ngIf`, `*ngFor`, `*ngSwitch`).
|
|
103
|
+
* **Old Syntax:**
|
|
104
|
+
```html
|
|
105
|
+
<section *ngIf="isVisible">Content</section>
|
|
106
|
+
<section *ngFor="let item of items">{{ item }}</section>
|
|
107
|
+
```
|
|
108
|
+
* **New Syntax:**
|
|
109
|
+
```html
|
|
110
|
+
@if (isVisible) {
|
|
111
|
+
<section>Content</section>
|
|
112
|
+
}
|
|
113
|
+
@for (item of items; track item.id) {
|
|
114
|
+
<section>{{ item }}</section>
|
|
115
|
+
}
|
|
116
|
+
```
|
|
117
|
+
* **Async Pipe:** Use the `async` pipe to handle observables in templates. This automatically subscribes and unsubscribes, preventing memory leaks.
|
|
118
|
+
|
|
119
|
+
## Services
|
|
120
|
+
|
|
121
|
+
* **Single Responsibility:** Design services around a single, well-defined responsibility.
|
|
122
|
+
* **`providedIn: 'root'`:** Use the `providedIn: 'root'` option when declaring injectable services to ensure they are singletons and tree-shakable.
|
|
123
|
+
* **`inject()` Function:** Prefer the `inject()` function over constructor injection when injecting dependencies, especially within `provide` functions, `computed` properties, or outside of constructor context.
|
|
124
|
+
* **Old Constructor Injection:**
|
|
125
|
+
```typescript
|
|
126
|
+
constructor(private myService: MyService) {}
|
|
127
|
+
```
|
|
128
|
+
* **New `inject()` Function:**
|
|
129
|
+
```typescript
|
|
130
|
+
import { inject } from '@angular/core';
|
|
131
|
+
|
|
132
|
+
export class MyComponent {
|
|
133
|
+
private myService = inject(MyService);
|
|
134
|
+
// ...
|
|
135
|
+
}
|
|
136
|
+
```
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# This file is used by the build system to adjust CSS and JS output to support the specified browsers below.
|
|
2
|
+
# For additional information regarding the format and rule options, please see:
|
|
3
|
+
# https://github.com/browserslist/browserslist#queries
|
|
4
|
+
|
|
5
|
+
# For the full list of supported browsers by the Angular framework, please see:
|
|
6
|
+
# https://angular.dev/reference/versions#browser-support
|
|
7
|
+
|
|
8
|
+
# You can see what browsers were selected by your queries by running:
|
|
9
|
+
# npx browserslist
|
|
10
|
+
|
|
11
|
+
Chrome >=107
|
|
12
|
+
Firefox >=106
|
|
13
|
+
Edge >=107
|
|
14
|
+
Safari >=16.1
|
|
15
|
+
iOS >=16.1
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# Editor configuration, see https://editorconfig.org
|
|
2
|
+
root = true
|
|
3
|
+
|
|
4
|
+
[*]
|
|
5
|
+
charset = utf-8
|
|
6
|
+
indent_style = space
|
|
7
|
+
indent_size = 2
|
|
8
|
+
insert_final_newline = true
|
|
9
|
+
trim_trailing_whitespace = true
|
|
10
|
+
|
|
11
|
+
[*.ts]
|
|
12
|
+
quote_type = single
|
|
13
|
+
|
|
14
|
+
[*.md]
|
|
15
|
+
max_line_length = off
|
|
16
|
+
trim_trailing_whitespace = false
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
|
|
3
|
+
"version": 1,
|
|
4
|
+
"newProjectRoot": "projects",
|
|
5
|
+
"projects": {
|
|
6
|
+
"app": {
|
|
7
|
+
"projectType": "application",
|
|
8
|
+
"schematics": {
|
|
9
|
+
"@ionic/angular-toolkit:page": {
|
|
10
|
+
"styleext": "scss",
|
|
11
|
+
"standalone": true
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"root": "",
|
|
15
|
+
"sourceRoot": "src",
|
|
16
|
+
"prefix": "app",
|
|
17
|
+
"architect": {
|
|
18
|
+
"build": {
|
|
19
|
+
"builder": "@angular-devkit/build-angular:application",
|
|
20
|
+
"options": {
|
|
21
|
+
"outputPath": {
|
|
22
|
+
"base": "www",
|
|
23
|
+
"browser": ""
|
|
24
|
+
},
|
|
25
|
+
"index": "src/index.html",
|
|
26
|
+
"tsConfig": "tsconfig.app.json",
|
|
27
|
+
"inlineStyleLanguage": "scss",
|
|
28
|
+
"assets": [
|
|
29
|
+
{
|
|
30
|
+
"glob": "**/*",
|
|
31
|
+
"input": "src/assets",
|
|
32
|
+
"output": "assets"
|
|
33
|
+
}
|
|
34
|
+
],
|
|
35
|
+
"styles": ["src/global.scss", "src/theme/variables.scss"],
|
|
36
|
+
"scripts": [],
|
|
37
|
+
"browser": "src/main.ts"
|
|
38
|
+
},
|
|
39
|
+
"configurations": {
|
|
40
|
+
"production": {
|
|
41
|
+
"budgets": [
|
|
42
|
+
{
|
|
43
|
+
"type": "initial",
|
|
44
|
+
"maximumWarning": "2mb",
|
|
45
|
+
"maximumError": "5mb"
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
"type": "anyComponentStyle",
|
|
49
|
+
"maximumWarning": "2kb",
|
|
50
|
+
"maximumError": "4kb"
|
|
51
|
+
}
|
|
52
|
+
],
|
|
53
|
+
"outputHashing": "all"
|
|
54
|
+
},
|
|
55
|
+
"development": {
|
|
56
|
+
"optimization": false,
|
|
57
|
+
"extractLicenses": false,
|
|
58
|
+
"sourceMap": true,
|
|
59
|
+
"namedChunks": true
|
|
60
|
+
},
|
|
61
|
+
"ci": {
|
|
62
|
+
"progress": false
|
|
63
|
+
}
|
|
64
|
+
},
|
|
65
|
+
"defaultConfiguration": "production"
|
|
66
|
+
},
|
|
67
|
+
"serve": {
|
|
68
|
+
"builder": "@angular-devkit/build-angular:dev-server",
|
|
69
|
+
"configurations": {
|
|
70
|
+
"production": {
|
|
71
|
+
"buildTarget": "app:build:production"
|
|
72
|
+
},
|
|
73
|
+
"development": {
|
|
74
|
+
"buildTarget": "app:build:development"
|
|
75
|
+
},
|
|
76
|
+
"ci": {
|
|
77
|
+
"progress": false
|
|
78
|
+
}
|
|
79
|
+
},
|
|
80
|
+
"defaultConfiguration": "development"
|
|
81
|
+
},
|
|
82
|
+
"extract-i18n": {
|
|
83
|
+
"builder": "@angular-devkit/build-angular:extract-i18n",
|
|
84
|
+
"options": {
|
|
85
|
+
"buildTarget": "app:build"
|
|
86
|
+
}
|
|
87
|
+
},
|
|
88
|
+
"test": {
|
|
89
|
+
"builder": "@angular-devkit/build-angular:karma",
|
|
90
|
+
"options": {
|
|
91
|
+
"main": "src/test.ts",
|
|
92
|
+
"tsConfig": "tsconfig.spec.json",
|
|
93
|
+
"karmaConfig": "karma.conf.js",
|
|
94
|
+
"inlineStyleLanguage": "scss",
|
|
95
|
+
"assets": [
|
|
96
|
+
{
|
|
97
|
+
"glob": "**/*",
|
|
98
|
+
"input": "src/assets",
|
|
99
|
+
"output": "assets"
|
|
100
|
+
}
|
|
101
|
+
],
|
|
102
|
+
"styles": ["src/global.scss", "src/theme/variables.scss"],
|
|
103
|
+
"scripts": []
|
|
104
|
+
},
|
|
105
|
+
"configurations": {
|
|
106
|
+
"ci": {
|
|
107
|
+
"progress": false,
|
|
108
|
+
"watch": false
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
},
|
|
112
|
+
"lint": {
|
|
113
|
+
"builder": "@angular-eslint/builder:lint",
|
|
114
|
+
"options": {
|
|
115
|
+
"lintFilePatterns": ["src/**/*.ts", "src/**/*.html"]
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
},
|
|
121
|
+
"cli": {
|
|
122
|
+
"schematicCollections": [
|
|
123
|
+
"@ionic/angular-toolkit"
|
|
124
|
+
],
|
|
125
|
+
"analytics": "cbe1df8d-204f-4a38-b88d-9f3a65fd6af4"
|
|
126
|
+
},
|
|
127
|
+
"schematics": {
|
|
128
|
+
"@ionic/angular-toolkit:component": {
|
|
129
|
+
"styleext": "scss"
|
|
130
|
+
},
|
|
131
|
+
"@ionic/angular-toolkit:page": {
|
|
132
|
+
"styleext": "scss"
|
|
133
|
+
},
|
|
134
|
+
"@angular-eslint/schematics:application": {
|
|
135
|
+
"setParserOptionsProject": true
|
|
136
|
+
},
|
|
137
|
+
"@angular-eslint/schematics:library": {
|
|
138
|
+
"setParserOptionsProject": true
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
const eslint = require("@eslint/js");
|
|
3
|
+
const tseslint = require("typescript-eslint");
|
|
4
|
+
const angular = require("angular-eslint");
|
|
5
|
+
const rdlabo = require('@rdlabo/eslint-plugin-rules');
|
|
6
|
+
|
|
7
|
+
module.exports = tseslint.config(
|
|
8
|
+
{
|
|
9
|
+
files: ["**/*.ts"],
|
|
10
|
+
plugins: {
|
|
11
|
+
'@rdlabo/rules': rdlabo,
|
|
12
|
+
},
|
|
13
|
+
extends: [
|
|
14
|
+
eslint.configs.recommended,
|
|
15
|
+
...tseslint.configs.recommended,
|
|
16
|
+
...tseslint.configs.stylistic,
|
|
17
|
+
...angular.configs.tsRecommended,
|
|
18
|
+
],
|
|
19
|
+
processor: angular.processInlineTemplates,
|
|
20
|
+
rules: {
|
|
21
|
+
"@typescript-eslint/no-explicit-any": "off",
|
|
22
|
+
"@typescript-eslint/no-unused-vars": "off",
|
|
23
|
+
"@angular-eslint/directive-selector": "off",
|
|
24
|
+
"@angular-eslint/component-selector": "off",
|
|
25
|
+
"@angular-eslint/no-empty-lifecycle-method": "off",
|
|
26
|
+
"@typescript-eslint/no-empty-function": "off",
|
|
27
|
+
'@rdlabo/rules/deny-constructor-di': 'error',
|
|
28
|
+
'@rdlabo/rules/deny-import-from-ionic-module': 'error',
|
|
29
|
+
'@rdlabo/rules/implements-ionic-lifecycle': 'error',
|
|
30
|
+
'@rdlabo/rules/deny-soft-private-modifier': 'error',
|
|
31
|
+
'@rdlabo/rules/signal-use-as-signal': 'error',
|
|
32
|
+
'@rdlabo/rules/signal-use-as-signal-template': 'error',
|
|
33
|
+
'@rdlabo/rules/component-property-use-readonly': 'error',
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
files: ["**/*.html"],
|
|
38
|
+
plugins: {
|
|
39
|
+
'@rdlabo/rules': rdlabo,
|
|
40
|
+
},
|
|
41
|
+
extends: [
|
|
42
|
+
...angular.configs.templateRecommended,
|
|
43
|
+
...angular.configs.templateAccessibility,
|
|
44
|
+
],
|
|
45
|
+
rules: {
|
|
46
|
+
'@rdlabo/rules/ionic-attr-type-check': 'error',
|
|
47
|
+
},
|
|
48
|
+
}
|
|
49
|
+
);
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
// Karma configuration file, see link for more information
|
|
2
|
+
// https://karma-runner.github.io/1.0/config/configuration-file.html
|
|
3
|
+
|
|
4
|
+
module.exports = function (config) {
|
|
5
|
+
config.set({
|
|
6
|
+
basePath: '',
|
|
7
|
+
frameworks: ['jasmine', '@angular-devkit/build-angular'],
|
|
8
|
+
plugins: [
|
|
9
|
+
require('karma-jasmine'),
|
|
10
|
+
require('karma-chrome-launcher'),
|
|
11
|
+
require('karma-jasmine-html-reporter'),
|
|
12
|
+
require('karma-coverage'),
|
|
13
|
+
require('@angular-devkit/build-angular/plugins/karma')
|
|
14
|
+
],
|
|
15
|
+
client: {
|
|
16
|
+
jasmine: {
|
|
17
|
+
// you can add configuration options for Jasmine here
|
|
18
|
+
// the possible options are listed at https://jasmine.github.io/api/edge/Configuration.html
|
|
19
|
+
// for example, you can disable the random execution with `random: false`
|
|
20
|
+
// or set a specific seed with `seed: 4321`
|
|
21
|
+
},
|
|
22
|
+
clearContext: false // leave Jasmine Spec Runner output visible in browser
|
|
23
|
+
},
|
|
24
|
+
jasmineHtmlReporter: {
|
|
25
|
+
suppressAll: true // removes the duplicated traces
|
|
26
|
+
},
|
|
27
|
+
coverageReporter: {
|
|
28
|
+
dir: require('path').join(__dirname, './coverage/app'),
|
|
29
|
+
subdir: '.',
|
|
30
|
+
reporters: [
|
|
31
|
+
{ type: 'html' },
|
|
32
|
+
{ type: 'text-summary' }
|
|
33
|
+
]
|
|
34
|
+
},
|
|
35
|
+
reporters: ['progress', 'kjhtml'],
|
|
36
|
+
port: 9876,
|
|
37
|
+
colors: true,
|
|
38
|
+
logLevel: config.LOG_INFO,
|
|
39
|
+
autoWatch: true,
|
|
40
|
+
browsers: ['Chrome'],
|
|
41
|
+
singleRun: false,
|
|
42
|
+
restartOnFileChange: true
|
|
43
|
+
});
|
|
44
|
+
};
|